diff --git a/INSTALL.txt b/INSTALL.txt
index 70e4f24efd..12dca9c5b4 100644
--- a/INSTALL.txt
+++ b/INSTALL.txt
@@ -29,7 +29,7 @@ php.ini file
- Mysql 5.x
- ability to schedule jobs with cron (Linux/Mac) or Scheduled Tasks
-(Windows)
+(Windows) [Note: other options are presented in Section 7 of this document]
- Installation into a top-level domain or sub-domain (without a
directory/path component in the URL) is preferred. Directory paths will
@@ -89,3 +89,18 @@ You can generally find the location of PHP by executing "which php". If you
have troubles with this section please contact your hosting provider for
assistance. Friendika will not work correctly if you cannot perform this step.
+Alternative: You may be able to use the 'poormancron' plugin to perform this
+step if you are using a recent Friendika release. To do this, edit the file
+".htconfig.php" and look for a line describing your plugins. On a fresh
+installation, it will look like
+
+$a->config['system']['addon'] = 'js_upload';
+
+This indicates the "js_upload" addon module is enabled. You may add additional
+addons/plugins using this same line in the configuration file. Change it to
+read
+
+$a->config['system']['addon'] = 'js_upload,poormancron';
+
+and save your changes.
+
diff --git a/addon/oembed/oembed.php b/addon/oembed/oembed.php
index 82183f3cce..4bbd75387a 100644
--- a/addon/oembed/oembed.php
+++ b/addon/oembed/oembed.php
@@ -10,13 +10,11 @@
function oembed_install() {
register_hook('jot_tool', 'addon/oembed/oembed.php', 'oembed_hook_jot_tool');
register_hook('page_header', 'addon/oembed/oembed.php', 'oembed_hook_page_header');
- register_hook('bbcode', 'addon/oembed/oembed.php', 'oembed_hook_bbcode');
}
function oembed_uninstall() {
unregister_hook('jot_tool', 'addon/oembed/oembed.php', 'oembed_hook_jot_tool');
unregister_hook('page_header', 'addon/oembed/oembed.php', 'oembed_hook_page_header');
- unregister_hook('bbcode', 'addon/oembed/oembed.php', 'oembed_hook_bbcode');
}
function oembed_hook_page_header($a, &$b){
@@ -53,49 +51,7 @@ function oembed_hook_jot_tool($a, &$b) {
';
}
-function oembed_replacecb($matches){
- $embedurl=$matches[1];
- $ourl = "http://oohembed.com/oohembed/?url=".urlencode($embedurl);
- $txt = fetch_url($ourl);
- $j = json_decode($txt);
- $ret="";
- switch ($j->type) {
- case "video": {
- if (isset($j->thumbnail_url)) {
- $tw = (isset($j->thumbnail_width)) ? $j->thumbnail_width:200;
- $th = (isset($j->thumbnail_height)) ? $j->thumbnail_height:180;
- $ret = "";
- $ret.= " ";
- $ret.= " ";
- } else {
- $ret=$j->html;
- }
- $ret.=" ";
- }; break;
- case "photo": {
- $ret = " ";
- $ret.=" ";
- }; break;
- case "link": {
- //$ret = "".$j->title." ";
- }; break;
- case "rich": {
- // not so safe..
- $ret = "
".$j->html." ";
- }; break;
- }
-
- $embedlink = (isset($j->title))?$j->title:$embedurl;
- $ret .= "$embedlink ";
- if (isset($j->author_name)) $ret.=" by ".$j->author_name;
- if (isset($j->provider_name)) $ret.=" on ".$j->provider_name;
- $ret.="";
- return $ret;
-}
-function oembed_hook_bbcode($a, &$text){
- $text = preg_replace_callback("/\[embed\](.+?)\[\/embed\]/is", oembed_replacecb ,$text);
-}
?>
\ No newline at end of file
diff --git a/boot.php b/boot.php
index 223c9416d1..ac010c19de 100644
--- a/boot.php
+++ b/boot.php
@@ -2,7 +2,7 @@
set_time_limit(0);
-define ( 'BUILD_ID', 1033 );
+define ( 'BUILD_ID', 1034 );
define ( 'FRIENDIKA_VERSION', '2.10.0902' );
define ( 'DFRN_PROTOCOL_VERSION', '2.0' );
@@ -10,6 +10,16 @@ define ( 'EOL', " \r\n" );
define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' );
define ( 'DOWN_ARROW', '⇩' );
+
+/**
+ * SSL redirection policies
+ */
+
+define ( 'SSL_POLICY_NONE', 0 );
+define ( 'SSL_POLICY_FULL', 1 );
+define ( 'SSL_POLICY_SELFSIGN', 2 );
+
+
/**
* log levels
*/
@@ -270,10 +280,17 @@ class App {
}
function get_baseurl($ssl = false) {
- if(strlen($this->baseurl))
- return $this->baseurl;
- $this->baseurl = (($ssl) ? 'https' : $this->scheme) . "://" . $this->hostname . ((isset($this->path) && strlen($this->path)) ? '/' . $this->path : '' );
+ $scheme = $this->scheme;
+
+ if(x($this->config,'ssl_policy')) {
+ if(($ssl) || ($this->config['ssl_policy'] == SSL_POLICY_FULL))
+ $scheme = 'https';
+ if(($this->config['ssl_policy'] == SSL_POLICY_SELFSIGN) && (local_user() || x($_POST,'auth-params')))
+ $scheme = 'https';
+ }
+
+ $this->baseurl = $scheme . "://" . $this->hostname . ((isset($this->path) && strlen($this->path)) ? '/' . $this->path : '' );
return $this->baseurl;
}
diff --git a/database.sql b/database.sql
index 54950f0fd1..817fd09226 100644
--- a/database.sql
+++ b/database.sql
@@ -471,4 +471,8 @@ CREATE TABLE IF NOT EXISTS `event` (
`deny_gid` MEDIUMTEXT NOT NULL
) ENGINE = MYISAM DEFAULT CHARSET=utf8;
-
+CREATE TABLE IF NOT EXISTS 'cache' (
+ `k` CHAR( 255 ) NOT NULL PRIMARY KEY ,
+ `v` TEXT NOT NULL,
+ `updated` DATETIME NOT NULL
+) ENGINE = MYISAM DEFAULT CHARSET=utf8;
diff --git a/htconfig.php b/htconfig.php
index 13c065e697..5f5c76cbd7 100644
--- a/htconfig.php
+++ b/htconfig.php
@@ -72,4 +72,7 @@ $a->config['system']['rino_encrypt'] = true;
$a->config['system']['addon'] = 'js_upload';
-
\ No newline at end of file
+// Disable oembed embedding
+// This disable the conversion of [embed]$url[/embed] tag in html
+// $a->config['system']['no_oembed'] = true;
+
diff --git a/include/acl_selectors.php b/include/acl_selectors.php
index d0952421ea..269dc3e349 100644
--- a/include/acl_selectors.php
+++ b/include/acl_selectors.php
@@ -17,8 +17,9 @@ function group_select($selname,$selclass,$preselected = false,$size = 4) {
$selected = " selected=\"selected\" ";
else
$selected = '';
+ $trimmed = substr($rr['name'],0,12);
- $o .= "{$rr['name']} \r\n";
+ $o .= "$trimmed \r\n";
}
}
@@ -30,7 +31,7 @@ function group_select($selname,$selclass,$preselected = false,$size = 4) {
-function contact_select($selname, $selclass, $preselected = false, $size = 4, $privmail = false, $celeb = false) {
+function contact_select($selname, $selclass, $preselected = false, $size = 4, $privmail = false, $celeb = false, $privatenet = false) {
$o = '';
@@ -43,6 +44,10 @@ function contact_select($selname, $selclass, $preselected = false, $size = 4, $p
$sql_extra .= sprintf(" AND `rel` = %d ", intval(REL_BUD));
}
+ if($privmail || $privatenet) {
+ $sql_extra .= " AND `network` IN ( 'dfrn' ) ";
+ }
+
if($privmail)
$o .= "\r\n";
else
@@ -61,11 +66,10 @@ function contact_select($selname, $selclass, $preselected = false, $size = 4, $p
$selected = " selected=\"selected\" ";
else
$selected = '';
- if(($privmail) && ($rr['network'] === 'stat'))
- $disabled = ' disabled="true" ' ;
- else
- $disabled = '';
- $o .= "{$rr['name']} \r\n";
+
+ $trimmed = substr($rr['name'],0,22);
+
+ $o .= "$trimmed \r\n";
}
}
@@ -110,7 +114,7 @@ function populate_acl($user = null,$celeb = false) {
$o .= '';
$o .= '';
$o .= '' . t('Contacts') . ' ';
- $o .= contact_select('contact_allow','contact_allow',$allow_cid,4,false,$celeb);
+ $o .= contact_select('contact_allow','contact_allow',$allow_cid,4,false,$celeb,true);
$o .= '
';
$o .= '' . "\r\n";
$o .= '
' . "\r\n";
@@ -125,7 +129,7 @@ function populate_acl($user = null,$celeb = false) {
$o .= '';
$o .= '';
$o .= '' . t('Contacts') . ' ';
- $o .= contact_select('contact_deny','contact_deny', $deny_cid,4,false, $celeb);
+ $o .= contact_select('contact_deny','contact_deny', $deny_cid,4,false, $celeb,true);
$o .= '
';
$o .= '' . "\r\n";
$o .= '
' . "\r\n";
diff --git a/include/bbcode.php b/include/bbcode.php
index 8382cc8044..eb0806dc52 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -1,5 +1,5 @@
', $Text);
+ // oembed tag
+ $Text = oembed_bbcode2html($Text);
+
call_hooks('bbcode',$Text);
return $Text;
diff --git a/include/items.php b/include/items.php
index e238280fc8..f204745bb4 100644
--- a/include/items.php
+++ b/include/items.php
@@ -1,6 +1,7 @@
]+>.+?' . 'http://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?#s',
'[youtube]$1[/youtube]', $res['body']);
+ $res['body'] = oembed_html2bbcode($res['body']);
+
$config = HTMLPurifier_Config::createDefault();
$config->set('Cache.DefinitionImpl', null);
@@ -903,6 +906,10 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0) {
$feed->enable_order_by_date(false);
$feed->init();
+ if($feed->error())
+ logger('consume_feed: Error parsing XML: ' . $feed->error());
+
+
// Check at the feed level for updated contact name and/or photo
$name_updated = '';
diff --git a/include/main.js b/include/main.js
index fcd1d6fee0..63b34bd21a 100644
--- a/include/main.js
+++ b/include/main.js
@@ -44,12 +44,14 @@
$('#pause').html('');
}
}
- if(event.keyCode == '36' && event.shiftKey == true) {
- if(homebase !== undefined) {
- event.preventDefault();
- document.location = homebase;
- }
- }
+// this is shift-home on FF, but $ on IE, disabling until I figure out why the diff.
+// update: incompatible usage of onKeyDown vs onKeyPress
+// if(event.keyCode == '36' && event.shiftKey == true) {
+// if(homebase !== undefined) {
+// event.preventDefault();
+// document.location = homebase;
+// }
+// }
});
});
diff --git a/include/notifier.php b/include/notifier.php
index dd5d55ed00..87095e814f 100644
--- a/include/notifier.php
+++ b/include/notifier.php
@@ -255,7 +255,7 @@ function notifier_run($argv, $argc){
$recip_str = implode(', ', $recipients);
- $r = q("SELECT * FROM `contact` WHERE `id` IN ( %s ) AND `blocked` = 0 ",
+ $r = q("SELECT * FROM `contact` WHERE `id` IN ( %s ) AND `blocked` = 0 AND `pending` = 0 ",
dbesc($recip_str)
);
if(! count($r)){
@@ -363,13 +363,61 @@ function notifier_run($argv, $argc){
continue;
$params = 'hub.mode=publish&hub.url=' . urlencode($a->get_baseurl() . '/dfrn_poll/' . $owner['nickname'] );
post_url($h,$params);
- logger('pubsub: publish: ' . $h . ' returned ' . $a->get_curl_code());
+ logger('pubsub: publish: ' . $h . ' ' . $params . ' returned ' . $a->get_curl_code());
if(count($hubs) > 1)
sleep(7); // try and avoid multiple hubs responding at precisely the same time
}
}
}
+ if($notify_hub) {
+
+ /**
+ *
+ * If you have less than 150 dfrn friends and it's a public message,
+ * we'll just go ahead and push them out securely with dfrn/rino.
+ * If you've got more than that, you'll have to rely on PuSH delivery.
+ *
+ */
+
+ $max_allowed = ((get_config('system','maxpubdeliver') === false) ? 150 : intval(get_config('system','maxdeliver')));
+
+
+ /**
+ *
+ * Only get the bare essentials and go back for the full record.
+ * If you've got a lot of friends and we grab all the details at once it could exhaust memory.
+ *
+ */
+
+ $r = q("SELECT `id`, `name` FROM `contact`
+ WHERE `network` = 'dfrn' AND `uid` = %d AND `blocked` = 0 AND `pending` = 0
+ AND `rel` != %d ",
+ intval($owner['uid']),
+ intval(REL_FAN)
+ );
+
+ if((count($r)) && ($max_allowed < count($r))) {
+ foreach($r as $rr) {
+
+ /* Don't deliver to folks who have already been delivered to */
+
+ if(! in_array($rr['id'], $conversants)) {
+ $n = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1",
+ intval($rr['id'])
+ );
+ if(count($n)) {
+
+ logger('notifier: dfrnpubdelivery: ' . $n[0]['name']);
+ $deliver_status = dfrn_deliver($owner,$n[0],$atom);
+ }
+ }
+ else
+ logger('notifier: dfrnpubdelivery: ignoring ' . $rr['name']);
+ }
+ }
+ }
+
return;
}
diff --git a/include/oembed.php b/include/oembed.php
new file mode 100644
index 0000000000..a130357abf
--- /dev/null
+++ b/include/oembed.php
@@ -0,0 +1,97 @@
+";
+ switch ($j->type) {
+ case "video": {
+ if (isset($j->thumbnail_url)) {
+ $tw = (isset($j->thumbnail_width)) ? $j->thumbnail_width:200;
+ $th = (isset($j->thumbnail_height)) ? $j->thumbnail_height:180;
+ $ret = "";
+ $ret.= " ";
+ $ret.= " ";
+ } else {
+ $ret=$j->html;
+ }
+ $ret.=" ";
+ }; break;
+ case "photo": {
+ $ret = " ";
+ $ret.=" ";
+ }; break;
+ case "link": {
+ //$ret = "".$j->title." ";
+ }; break;
+ case "rich": {
+ // not so safe..
+ $ret = "".$j->html." ";
+ }; break;
+ }
+
+ $embedlink = (isset($j->title))?$j->title:$embedurl;
+ $ret .= "$embedlink ";
+ if (isset($j->author_name)) $ret.=" by ".$j->author_name;
+ if (isset($j->provider_name)) $ret.=" on ".$j->provider_name;
+ $ret.="";
+ return $ret;
+}
+
+function oembed_bbcode2html($text){
+ $stopoembed = get_config("system","no_oembed");
+ if ($stopoembed == true){
+ return preg_replace("/\[embed\](.+?)\[\/embed\]/is", "". t('Embedding disabled') ." : $1 " ,$text);
+ }
+ return preg_replace_callback("/\[embed\](.+?)\[\/embed\]/is", oembed_replacecb ,$text);
+}
+
+
+function oe_build_xpath($attr, $value){
+ // http://westhoffswelt.de/blog/0036_xpath_to_select_html_by_class.html
+ return "contains( normalize-space( @$attr ), ' $value ' ) or substring( normalize-space( @$attr ), 1, string-length( '$value' ) + 1 ) = '$value ' or substring( normalize-space( @$attr ), string-length( @$attr ) - string-length( '$value' ) ) = ' $value' or @$attr = '$value'";
+}
+
+function oe_get_inner_html( $node ) {
+ $innerHTML= '';
+ $children = $node->childNodes;
+ foreach ($children as $child) {
+ $innerHTML .= $child->ownerDocument->saveXML( $child );
+ }
+ return $innerHTML;
+}
+
+/**
+ * Find ....
+ * and replace it with [embed]url[/embed]
+ */
+function oembed_html2bbcode($text) {
+ $dom = DOMDocument::loadHTML($text);
+ $xpath = new DOMXPath($dom);
+ $attr = "oembed";
+
+ $xattr = oe_build_xpath("class","oembed");
+ $entries = $xpath->query("//span[$xattr]");
+
+ $xattr = oe_build_xpath("rel","oembed");
+ foreach($entries as $e) {
+ $href = $xpath->evaluate("a[$xattr]/@href", $e)->item(0)->nodeValue;
+ if(!is_null($href)) $e->parentNode->replaceChild(new DOMText("[embed]".$href."[embed]"), $e);
+ }
+ return oe_get_inner_html( $dom->getElementsByTagName("body")->item(0) );
+}
+
+?>
\ No newline at end of file
diff --git a/include/poller.php b/include/poller.php
index 1003b2f081..2ba285b7b6 100644
--- a/include/poller.php
+++ b/include/poller.php
@@ -30,6 +30,10 @@ function poller_run($argv, $argc){
$php_path = ((x($a->config,'php_path') && strlen($a->config['php_path'])) ? $a->config['php_path'] : 'php');
//proc_close(proc_open("\"$php_path\" \"include/queue.php\" &", array(), $foo));
proc_run($php_path,"include/queue.php");
+
+ // clear old cache
+ q("DELETE FROM `cache` WHERE `updated`<'%s'",
+ dbesc(datetime_convert('UTC','UTC',"now - 30 days")));
$hub_update = false;
@@ -58,6 +62,9 @@ function poller_run($argv, $argc){
foreach($contacts as $contact) {
+ if($manual_id)
+ $contact['last-update'] = '0000-00-00 00:00:00';
+
if($contact['priority'] || $contact['subhub']) {
$hub_update = true;
@@ -76,7 +83,7 @@ function poller_run($argv, $argc){
$contact['priority'] = (($interval !== false) ? intval($interval) : 3);
$hub_update = false;
- if(datetime_convert('UTC','UTC', 'now') > datetime_convert('UTC','UTC', $t . " + 1 day"))
+ if((datetime_convert('UTC','UTC', 'now') > datetime_convert('UTC','UTC', $t . " + 1 day")) || $force)
$hub_update = true;
}
diff --git a/index.php b/index.php
index ae6a578cb4..685a76a131 100644
--- a/index.php
+++ b/index.php
@@ -140,7 +140,7 @@ if(strlen($a->module)) {
}
else {
if((x($_SERVER,'QUERY_STRING')) && ($_SERVER['QUERY_STRING'] === 'q=internal_error.html') && isset($dreamhost_error_hack)) {
- logger('index.php: dreamhost_error_hack invoked');
+ logger('index.php: dreamhost_error_hack invoked. Original URI =' . $_SERVER['REQUEST_URI']);
goaway($a->get_baseurl() . $_SERVER['REQUEST_URI']);
}
diff --git a/mod/contacts.php b/mod/contacts.php
index 177ca99734..4c627c88f9 100644
--- a/mod/contacts.php
+++ b/mod/contacts.php
@@ -121,6 +121,15 @@ function contacts_content(&$a) {
return; // NOTREACHED
}
+ if($cmd === 'update') {
+
+ // pull feed and consume it, which should subscribe to the hub.
+
+ $php_path = ((x($a->config,'php_path') && strlen($a->config['php_path'])) ? $a->config['php_path'] : 'php');
+ proc_run($php_path,"include/poller.php","$contact_id");
+ goaway($a->get_baseurl() . '/contacts/' . $contact_id);
+ // NOTREACHED
+ }
if($cmd === 'block') {
$blocked = (($orig_record[0]['blocked']) ? 0 : 1);
@@ -248,6 +257,7 @@ function contacts_content(&$a) {
'$last_update' => (($r[0]['last-update'] == '0000-00-00 00:00:00')
? t('Never')
: datetime_convert('UTC',date_default_timezone_get(),$r[0]['last-update'],'D, j M Y, g:i A')),
+ '$udnow' => t('Update now'),
'$profile_select' => contact_profile_assign($r[0]['profile-id'],(($r[0]['network'] !== 'dfrn') ? true : false)),
'$contact_id' => $r[0]['id'],
'$block_text' => (($r[0]['blocked']) ? t('Unblock this contact') : t('Block this contact') ),
diff --git a/mod/dfrn_poll.php b/mod/dfrn_poll.php
index 1061cdb899..85e7fc0afd 100644
--- a/mod/dfrn_poll.php
+++ b/mod/dfrn_poll.php
@@ -26,6 +26,7 @@ function dfrn_poll_init(&$a) {
}
if(($dfrn_id === '') && (! x($_POST,'dfrn_id')) && ($a->argc > 1)) {
+ logger('dfrn_poll: public feed request from ' . $_SERVER['REMOTE_ADDR'] );
header("Content-type: application/atom+xml");
$o = get_feed_for($a, '*', $a->argv[1],$last_update);
echo $o;
diff --git a/mod/follow.php b/mod/follow.php
index a90ae3f512..62ba2585c2 100644
--- a/mod/follow.php
+++ b/mod/follow.php
@@ -10,7 +10,9 @@ function follow_post(&$a) {
// NOTREACHED
}
- $url = notags(trim($_POST['url']));
+ $url = $orig_url = notags(trim($_POST['url']));
+
+ $email_conversant = false;
if($url) {
$links = lrdd($url);
@@ -29,6 +31,11 @@ function follow_post(&$a) {
}
}
+ else {
+ if((strpos($orig_url,'@')) && validate_email($orig_url)) {
+ $email_conversant = true;
+ }
+ }
}
// If we find a DFRN site, send our subscriber to the other person's
diff --git a/mod/item.php b/mod/item.php
index 11e79a7ab2..7125ae1f49 100644
--- a/mod/item.php
+++ b/mod/item.php
@@ -71,6 +71,7 @@ function item_post(&$a) {
$location = notags(trim($_POST['location']));
$coord = notags(trim($_POST['coord']));
$verb = notags(trim($_POST['verb']));
+ $emailcc = notags(trim($_POST['emailcc']));
if(! strlen($body)) {
notice( t('Empty post discarded.') . EOL );
@@ -421,12 +422,39 @@ function item_post(&$a) {
logger('mod_item: notifier invoked: ' . "\"$php_path\" \"include/notifier.php\" \"$notify_type\" \"$post_id\" &");
- proc_run($php_path, "include/notifier.php", $notify_type, "$post_id");
+ proc_run($php_path, "include/notifier.php", $notify_type, "$post_id");
$datarray['id'] = $post_id;
call_hooks('post_local_end', $datarray);
-
+
+ if(strlen($emailcc) && $profile_uid == local_user()) {
+ $erecips = explode(',', $emailcc);
+ if(count($erecips)) {
+ foreach($erecips as $recip) {
+ $addr = trim($recip);
+ if(! strlen($addr))
+ continue;
+ $disclaimer = ' ' . t('This message was sent to you by ') . $a->user['username']
+ . t(', a member of the Friendika social network.') . ' ';
+ $disclaimer .= t('You may visit them online at') . ' '
+ . $a->get_baseurl() . '/profile/' . $a->user['nickname'] . ' ';
+ $disclaimer .= t('Please contact the sender by replying to this post if you do not wish to receive these messages.') . ' ';
+
+ $subject = '[Friendika]' . ' ' . $a->user['username'] . ' ' . t('posted an update.');
+ $headers = 'From: ' . $a->user['username'] . ' <' . $a->user['email'] . '>' . "\n";
+ $headers .= 'MIME-Version: 1.0' . "\n";
+ $headers .= 'Content-Type: text/html; charset=UTF-8' . "\n";
+ $headers .= 'Content-Transfer-Encoding: 8bit' . "\n\n";
+ $link = ' ';
+ $html = prepare_body($datarray);
+ $message = '' . $link . $html . $disclaimer . '';
+ @mail($addr, $subject, $message, $headers);
+ }
+ }
+ }
+
+
goaway($a->get_baseurl() . "/" . $_POST['return'] );
return; // NOTREACHED
diff --git a/mod/network.php b/mod/network.php
index 50d7134c17..80edca1d02 100644
--- a/mod/network.php
+++ b/mod/network.php
@@ -87,6 +87,8 @@ function network_content(&$a, $update = 0) {
'$baseurl' => $a->get_baseurl(),
'$defloc' => $a->user['default-location'],
'$visitor' => 'block',
+ '$emailcc' => t('CC: email addresses'),
+ '$emtitle' => t('Example: bob@example.com, mary@example.com'),
'$lockstate' => $lockstate,
'$acl' => populate_acl((($group) ? $group_acl : $a->user), $celeb),
'$bang' => (($group) ? '!' : ''),
diff --git a/mod/profile.php b/mod/profile.php
index c84b493c50..91c1ba6d85 100644
--- a/mod/profile.php
+++ b/mod/profile.php
@@ -144,6 +144,8 @@ function profile_content(&$a, $update = 0) {
'$return_path' => $a->cmd,
'$visitor' => (($is_owner || $commvisitor) ? 'block' : 'none'),
'$lockstate' => $lockstate,
+ '$emailcc' => t('CC: email addresses'),
+ '$emtitle' => t('Example: bob@example.com, mary@example.com'),
'$bang' => '',
'$acl' => (($is_owner) ? populate_acl($a->user, $celeb) : ''),
'$profile_uid' => $a->profile['profile_uid'],
diff --git a/update.php b/update.php
index 0bd58d6d48..f7bf9da1ed 100644
--- a/update.php
+++ b/update.php
@@ -320,3 +320,11 @@ function update_1031() {
function update_1032() {
q("ALTER TABLE `profile` ADD `pdesc` CHAR( 255 ) NOT NULL AFTER `name` ");
}
+
+function update_1033() {
+ q("CREATE TABLE IF NOT EXISTS `cache` (
+ `k` CHAR( 255 ) NOT NULL PRIMARY KEY ,
+ `v` TEXT NOT NULL,
+ `updated` DATETIME NOT NULL
+ ) ENGINE = MYISAM DEFAULT CHARSET=utf8;");
+}
diff --git a/view/de/contact_edit.tpl b/view/de/contact_edit.tpl
index fcd3f2d66f..0b32bdd66b 100644
--- a/view/de/contact_edit.tpl
+++ b/view/de/contact_edit.tpl
@@ -3,6 +3,8 @@
$name
+