aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/Contact.php17
-rw-r--r--include/Photo.php178
-rw-r--r--include/Scrape.php11
-rw-r--r--include/api.php41
-rw-r--r--include/config.php10
-rw-r--r--include/conversation.php8
-rw-r--r--include/datetime.php2
-rwxr-xr-xinclude/diaspora.php259
-rw-r--r--include/enotify.php62
-rwxr-xr-xinclude/items.php126
-rw-r--r--include/nav.php2
-rw-r--r--include/onepoll.php27
-rw-r--r--include/plugin.php35
-rw-r--r--include/poller.php4
-rw-r--r--include/queue_fn.php7
-rw-r--r--include/text.php21
16 files changed, 560 insertions, 250 deletions
diff --git a/include/Contact.php b/include/Contact.php
index 675d1c81e..14e1a52cd 100644
--- a/include/Contact.php
+++ b/include/Contact.php
@@ -139,6 +139,10 @@ function terminate_friendship($user,$self,$contact) {
if(! function_exists('mark_for_death')) {
function mark_for_death($contact) {
+
+ if($contact['archive'])
+ return;
+
if($contact['term-date'] == '0000-00-00 00:00:00') {
q("UPDATE `contact` SET `term-date` = '%s' WHERE `id` = %d LIMIT 1",
dbesc(datetime_convert()),
@@ -146,12 +150,23 @@ function mark_for_death($contact) {
);
}
else {
+
+ // TODO: We really should send a notification to the owner after 2-3 weeks
+ // so they won't be surprised when the contact vanishes and can take
+ // remedial action if this was a serious mistake or glitch
+
$expiry = $contact['term-date'] . ' + 32 days ';
if(datetime_convert() > datetime_convert('UTC','UTC',$expiry)) {
// relationship is really truly dead.
+ // archive them rather than delete
+ // though if the owner tries to unarchive them we'll start the whole process over again
+
+ q("update contact set `archive` = 1 where id = %d limit 1",
+ intval($contact['id'])
+ );
- contact_remove($contact['id']);
+ //contact_remove($contact['id']);
}
}
diff --git a/include/Photo.php b/include/Photo.php
index f769a70a6..3af1691ee 100644
--- a/include/Photo.php
+++ b/include/Photo.php
@@ -121,7 +121,70 @@ class Photo {
$this->image = imagerotate($this->image,$degrees,0);
$this->width = imagesx($this->image);
$this->height = imagesy($this->image);
- }
+ }
+
+ public function flip($horiz = true, $vert = false) {
+ $w = imagesx($this->image);
+ $h = imagesy($this->image);
+ $flipped = imagecreate($w, $h);
+ if($horiz) {
+ for ($x = 0; $x < $w; $x++) {
+ imagecopy($flipped, $this->image, $x, 0, $w - $x - 1, 0, 1, $h);
+ }
+ }
+ if($vert) {
+ for ($y = 0; $y < $h; $y++) {
+ imagecopy($flipped, $this->image, 0, $y, 0, $h - $y - 1, $w, 1);
+ }
+ }
+ $this->image = $flipped;
+ }
+
+ public function orient($filename) {
+ // based off comment on http://php.net/manual/en/function.imagerotate.php
+
+ if(! function_exists('exif_read_data'))
+ return;
+
+ $exif = exif_read_data($filename);
+ $ort = $exif['Orientation'];
+
+ switch($ort)
+ {
+ case 1: // nothing
+ break;
+
+ case 2: // horizontal flip
+ $this->flip();
+ break;
+
+ case 3: // 180 rotate left
+ $this->rotate(180);
+ break;
+
+ case 4: // vertical flip
+ $this->flip(false, true);
+ break;
+
+ case 5: // vertical flip + 90 rotate right
+ $this->flip(false, true);
+ $this->rotate(-90);
+ break;
+
+ case 6: // 90 rotate right
+ $this->rotate(-90);
+ break;
+
+ case 7: // horizontal flip + 90 rotate right
+ $this->flip();
+ $this->rotate(-90);
+ break;
+
+ case 8: // 90 rotate left
+ $this->rotate(90);
+ break;
+ }
+ }
@@ -256,35 +319,81 @@ class Photo {
else
$guid = get_guid();
- $r = q("INSERT INTO `photo`
- ( `uid`, `contact-id`, `guid`, `resource-id`, `created`, `edited`, `filename`, type, `album`, `height`, `width`, `data`, `scale`, `profile`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid` )
- VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, '%s', '%s', '%s', '%s' )",
- intval($uid),
- intval($cid),
- dbesc($guid),
- dbesc($rid),
- dbesc(datetime_convert()),
- dbesc(datetime_convert()),
- dbesc(basename($filename)),
- dbesc($this->type),
- dbesc($album),
- intval($this->height),
- intval($this->width),
- dbesc($this->imageString()),
- intval($scale),
- intval($profile),
- dbesc($allow_cid),
- dbesc($allow_gid),
- dbesc($deny_cid),
- dbesc($deny_gid)
+ $x = q("select id from photo where `resource-id` = '%s' and uid = %d and `contact-id` = %d and `scale` = %d limit 1",
+ dbesc($rid),
+ intval($uid),
+ intval($cid),
+ intval($scale)
);
+ if(count($x)) {
+ $r = q("UPDATE `photo`
+ set `uid` = %d,
+ `contact-id` = %d,
+ `guid` = '%s',
+ `resource-id` = '%s',
+ `created` = '%s',
+ `edited` = '%s',
+ `filename` = '%s',
+ `type` = '%s',
+ `album` = '%s',
+ `height` = %d,
+ `width` = %d,
+ `data` = '%s',
+ `scale` = %d,
+ `profile` = %d,
+ `allow_cid` = '%s',
+ `allow_gid` = '%s',
+ `deny_cid` = '%s',
+ `deny_gid` = '%s'
+ where id = %d limit 1",
+
+ intval($uid),
+ intval($cid),
+ dbesc($guid),
+ dbesc($rid),
+ dbesc(datetime_convert()),
+ dbesc(datetime_convert()),
+ dbesc(basename($filename)),
+ dbesc($this->type),
+ dbesc($album),
+ intval($this->height),
+ intval($this->width),
+ dbesc($this->imageString()),
+ intval($scale),
+ intval($profile),
+ dbesc($allow_cid),
+ dbesc($allow_gid),
+ dbesc($deny_cid),
+ dbesc($deny_gid),
+ intval($x[0]['id'])
+ );
+ }
+ else {
+ $r = q("INSERT INTO `photo`
+ ( `uid`, `contact-id`, `guid`, `resource-id`, `created`, `edited`, `filename`, type, `album`, `height`, `width`, `data`, `scale`, `profile`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid` )
+ VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, '%s', '%s', '%s', '%s' )",
+ intval($uid),
+ intval($cid),
+ dbesc($guid),
+ dbesc($rid),
+ dbesc(datetime_convert()),
+ dbesc(datetime_convert()),
+ dbesc(basename($filename)),
+ dbesc($this->type),
+ dbesc($album),
+ intval($this->height),
+ intval($this->width),
+ dbesc($this->imageString()),
+ intval($scale),
+ intval($profile),
+ dbesc($allow_cid),
+ dbesc($allow_gid),
+ dbesc($deny_cid),
+ dbesc($deny_gid)
+ );
+ }
return $r;
}
-
-
-
-
-
}}
@@ -326,6 +435,17 @@ function import_profile_photo($photo,$uid,$cid) {
$a = get_app();
+ $r = q("select `resource-id` from photo where `uid` = %d and `contact-id` = %d and `scale` = 4 and `album` = 'Contact Photos' limit 1",
+ intval($uid),
+ intval($cid)
+ );
+ if(count($r)) {
+ $hash = $r[0]['resource-id'];
+ }
+ else {
+ $hash = photo_new_resource();
+ }
+
$photo_failure = false;
$filename = basename($photo);
@@ -340,8 +460,6 @@ function import_profile_photo($photo,$uid,$cid) {
$img->scaleImageSquare(175);
- $hash = photo_new_resource();
-
$r = $img->store($uid, $cid, $hash, $filename, 'Contact Photos', 4 );
if($r === false)
@@ -361,8 +479,6 @@ function import_profile_photo($photo,$uid,$cid) {
if($r === false)
$photo_failure = true;
-
-
$photo = $a->get_baseurl() . '/photo/' . $hash . '-4.' . $img->getExt();
$thumb = $a->get_baseurl() . '/photo/' . $hash . '-5.' . $img->getExt();
$micro = $a->get_baseurl() . '/photo/' . $hash . '-6.' . $img->getExt();
diff --git a/include/Scrape.php b/include/Scrape.php
index ca8f6e83a..4f53effe9 100644
--- a/include/Scrape.php
+++ b/include/Scrape.php
@@ -352,10 +352,11 @@ function probe_url($url, $mode = PROBE_NORMAL) {
$email_conversant = false;
$twitter = ((strpos($url,'twitter.com') !== false) ? true : false);
+ $lastfm = ((strpos($url,'last.fm/user') !== false) ? true : false);
$at_addr = ((strpos($url,'@') !== false) ? true : false);
- if(! $twitter) {
+ if((! $twitter) && (! $lastfm)) {
if(strpos($url,'mailto:') !== false && $at_addr) {
$url = str_replace('mailto:','',$url);
@@ -564,6 +565,14 @@ function probe_url($url, $mode = PROBE_NORMAL) {
$vcard['fn'] = $tid . '@twitter';
}
+ if($lastfm) {
+ $profile = $url;
+ $poll = str_replace(array('www.','last.fm/'),array('','ws.audioscrobbler.com/1.0/'),$url) . '/recenttracks.rss';
+ $vcard['nick'] = basename($url);
+ $vcard['fn'] = $vcard['nick'] . t(' on Last.fm');
+ $network = NETWORK_FEED;
+ }
+
if(! x($vcard,'fn'))
if(x($vcard,'nick'))
$vcard['fn'] = $vcard['nick'];
diff --git a/include/api.php b/include/api.php
index 9925b5766..b77156dfa 100644
--- a/include/api.php
+++ b/include/api.php
@@ -245,7 +245,7 @@
}
- logger('api_user: ' . $extra_query . ' ' , $user);
+ logger('api_user: ' . $extra_query . ', user: ' . $user);
// user info
$uinfo = q("SELECT *, `contact`.`id` as `cid` FROM `contact`
WHERE 1
@@ -719,14 +719,18 @@
if ($page<0) $page=0;
$since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
$max_id = (x($_REQUEST,'max_id')?$_REQUEST['max_id']:0);
+ $exclude_replies = (x($_REQUEST,'exclude_replies')?1:0);
//$since_id = 0;//$since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
$start = $page*$count;
//$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:false);
+ $sql_extra = '';
if ($max_id > 0)
- $sql_extra = 'AND `item`.`id` <= '.intval($max_id);
+ $sql_extra .= ' AND `item`.`id` <= '.intval($max_id);
+ if ($exclude_replies > 0)
+ $sql_extra .= ' AND `item`.`parent` = `item`.`id`';
$r = q("SELECT `item`.*, `item`.`id` AS `item_id`,
`contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`,
@@ -860,6 +864,8 @@
logger('API: api_statuses_show: '.$id);
//$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:false);
+ //$sql_extra = "";
+ if ($_GET["conversation"] == "true") $sql_extra .= " AND `item`.`parent` = %d ORDER BY `received` ASC "; else $sql_extra .= " AND `item`.`id` = %d";
$r = q("SELECT `item`.*, `item`.`id` AS `item_id`,
`contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`,
@@ -870,19 +876,24 @@
AND `contact`.`id` = `item`.`contact-id`
AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
$sql_extra
- AND `item`.`id`=%d",
+ ",
intval($id)
);
-
+//var_dump($r);
$ret = api_format_items($r,$user_info);
-
- $data = array('$status' => $ret[0]);
- /*switch($type){
- case "atom":
- case "rss":
- $data = api_rss_extra($a, $data, $user_info);
- }*/
- return api_apply_template("status", $type, $data);
+//var_dump($ret);
+ if ($_GET["conversation"] == "true") {
+ $data = array('$statuses' => $ret);
+ return api_apply_template("timeline", $type, $data);
+ } else {
+ $data = array('$status' => $ret[0]);
+ /*switch($type){
+ case "atom":
+ case "rss":
+ $data = api_rss_extra($a, $data, $user_info);
+ }*/
+ return api_apply_template("status", $type, $data);
+ }
}
api_register_func('api/statuses/show','api_statuses_show', true);
@@ -1061,11 +1072,14 @@
$page = (x($_REQUEST,'page')?$_REQUEST['page']-1:0);
if ($page<0) $page=0;
$since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
+ $exclude_replies = (x($_REQUEST,'exclude_replies')?1:0);
//$since_id = 0;//$since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
$start = $page*$count;
- if ($user_info['self']==1) $sql_extra = "AND `item`.`wall` = 1 ";
+ $sql_extra = '';
+ if ($user_info['self']==1) $sql_extra .= " AND `item`.`wall` = 1 ";
+ if ($exclude_replies > 0) $sql_extra .= ' AND `item`.`parent` = `item`.`id`';
$r = q("SELECT `item`.*, `item`.`id` AS `item_id`,
`contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`,
@@ -1654,7 +1668,6 @@ account/update_profile_background_image
account/update_profile_image
blocks/create
blocks/destroy
-oauth/authorize
Not implemented in status.net:
statuses/retweeted_to_me
diff --git a/include/config.php b/include/config.php
index df1070c13..1f2a70e5a 100644
--- a/include/config.php
+++ b/include/config.php
@@ -18,19 +18,17 @@
if(! function_exists('load_config')) {
function load_config($family) {
global $a;
- $r = q("SELECT * FROM `config` WHERE `cat` = '%s'",
- dbesc($family)
- );
+ $r = q("SELECT * FROM `config` WHERE `cat` = '%s'", dbesc($family));
if(count($r)) {
foreach($r as $rr) {
$k = $rr['k'];
- if ($rr['cat'] === 'config') {
+ if ($family === 'config') {
$a->config[$k] = $rr['v'];
} else {
$a->config[$family][$k] = $rr['v'];
}
}
- } else if ($rr['cat'] != 'config') {
+ } else if ($family != 'config') {
// Negative caching
$a->config[$family] = "!<unset>!";
}
@@ -128,7 +126,7 @@ function load_pconfig($uid,$family) {
$k = $rr['k'];
$a->config[$uid][$family][$k] = $rr['v'];
}
- } else if ($rr['cat'] != 'config') {
+ } else if ($family != 'config') {
// Negative caching
$a->config[$uid][$family] = "!<unset>!";
}
diff --git a/include/conversation.php b/include/conversation.php
index a9c6287a9..2244e8df7 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -173,8 +173,8 @@ function localize_item(&$item){
$item['body'] = str_replace($mtch[0],'@[url=' . zrl($mtch[1]). ']',$item['body']);
}
}
+ // add zrl's to public images
if(preg_match_all('/\[url=(.*?)\/photos\/(.*?)\/image\/(.*?)\]\[img(.*?)\]h(.*?)\[\/img\]\[\/url\]/is',$item['body'],$matches,PREG_SET_ORDER)) {
-logger('matched');
foreach($matches as $mtch) {
$item['body'] = str_replace($mtch[0],'[url=' . zrl($mtch[1] . '/photos/' . $mtch[2] . '/image/' . $mtch[3] ,true) . '][img' . $mtch[4] . ']h' . $mtch[5] . '[/img][/url]',$item['body']);
}
@@ -308,7 +308,7 @@ function conversation(&$a, $items, $mode, $update, $preview = false) {
if(($normalised != 'mailbox') && (x($a->contacts[$normalised])))
$profile_avatar = $a->contacts[$normalised]['thumb'];
else
- $profile_avatar = ((strlen($item['author-avatar'])) ? $item['author-avatar'] : $item['thumb']);
+ $profile_avatar = ((strlen($item['author-avatar'])) ? $a->get_cached_avatar_image($item['author-avatar']) : $item['thumb']);
$locate = array('location' => $item['location'], 'coord' => $item['coord'], 'html' => '');
call_hooks('render_location',$locate);
@@ -546,7 +546,7 @@ function conversation(&$a, $items, $mode, $update, $preview = false) {
}
$likebuttons = '';
- $shareable = ((($profile_owner == local_user()) && (! $item['private'])) ? true : false); //($mode != 'display') &&
+ $shareable = ((($profile_owner == local_user()) && ((! $item['private']) || $item['network'] === NETWORK_FEED)) ? true : false);
if($page_writeable) {
if($toplevelpost) {
@@ -657,7 +657,7 @@ function conversation(&$a, $items, $mode, $update, $preview = false) {
if(($normalised != 'mailbox') && (x($a->contacts,$normalised)))
$profile_avatar = $a->contacts[$normalised]['thumb'];
else
- $profile_avatar = (((strlen($item['author-avatar'])) && $diff_author) ? $item['author-avatar'] : $thumb);
+ $profile_avatar = (((strlen($item['author-avatar'])) && $diff_author) ? $item['author-avatar'] : $a->get_cached_avatar_image($thumb));
$like = ((x($alike,$item['id'])) ? format_like($alike[$item['id']],$alike[$item['id'] . '-l'],'like',$item['id']) : '');
$dislike = ((x($dlike,$item['id'])) ? format_like($dlike[$item['id']],$dlike[$item['id'] . '-l'],'dislike',$item['id']) : '');
diff --git a/include/datetime.php b/include/datetime.php
index 3b1491e4d..58a618610 100644
--- a/include/datetime.php
+++ b/include/datetime.php
@@ -87,7 +87,7 @@ function datetime_convert($from = 'UTC', $to = 'UTC', $s = 'now', $fmt = "Y-m-d
$from = 'UTC';
if($to === '')
$to = 'UTC';
- if($s === '')
+ if( ($s === '') || (! is_string($s)) )
$s = 'now';
// Slight hackish adjustment so that 'zero' datetime actually returns what is intended
diff --git a/include/diaspora.php b/include/diaspora.php
index 1e6662f04..0ca9163a8 100755
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -1060,45 +1060,64 @@ function diaspora_comment($importer,$xml,$msg) {
}
$parent_item = $r[0];
- $author_signed_data = $guid . ';' . $parent_guid . ';' . $text . ';' . $diaspora_handle;
- $author_signature = base64_decode($author_signature);
+ /* How Diaspora performs comment signature checking:
- if(strcasecmp($diaspora_handle,$msg['author']) == 0) {
- $person = $contact;
- $key = $msg['key'];
- }
- else {
- $person = find_diaspora_person_by_handle($diaspora_handle);
+ - If an item has been sent by the comment author to the top-level post owner to relay on
+ to the rest of the contacts on the top-level post, the top-level post owner should check
+ the author_signature, then create a parent_author_signature before relaying the comment on
+ - If an item has been relayed on by the top-level post owner, the contacts who receive it
+ check only the parent_author_signature. Basically, they trust that the top-level post
+ owner has already verified the authenticity of anything he/she sends out
+ - In either case, the signature that get checked is the signature created by the person
+ who sent the salmon
+ */
- if(is_array($person) && x($person,'pubkey'))
- $key = $person['pubkey'];
- else {
- logger('diaspora_comment: unable to find author details');
- return;
- }
- }
-
- if(! rsa_verify($author_signed_data,$author_signature,$key,'sha256')) {
- logger('diaspora_comment: verification failed.');
- return;
- }
+ $signed_data = $guid . ';' . $parent_guid . ';' . $text . ';' . $diaspora_handle;
+ $key = $msg['key'];
if($parent_author_signature) {
- $owner_signed_data = $guid . ';' . $parent_guid . ';' . $text . ';' . $diaspora_handle;
+ // If a parent_author_signature exists, then we've received the comment
+ // relayed from the top-level post owner. There's no need to check the
+ // author_signature if the parent_author_signature is valid
$parent_author_signature = base64_decode($parent_author_signature);
- $key = $msg['key'];
+ if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) {
+ logger('diaspora_comment: top-level owner verification failed.');
+ return;
+ }
+ }
+ else {
+ // If there's no parent_author_signature, then we've received the comment
+ // from the comment creator. In that case, the person is commenting on
+ // our post, so he/she must be a contact of ours and his/her public key
+ // should be in $msg['key']
+
+ $author_signature = base64_decode($author_signature);
- if(! rsa_verify($owner_signed_data,$parent_author_signature,$key,'sha256')) {
- logger('diaspora_comment: owner verification failed.');
+ if(! rsa_verify($signed_data,$author_signature,$key,'sha256')) {
+ logger('diaspora_comment: comment author verification failed.');
return;
}
}
// Phew! Everything checks out. Now create an item.
+ // Find the original comment author information.
+ // We need this to make sure we display the comment author
+ // information (name and avatar) correctly.
+ if(strcasecmp($diaspora_handle,$msg['author']) == 0)
+ $person = $contact;
+ else {
+ $person = find_diaspora_person_by_handle($diaspora_handle);
+
+ if(! is_array($person)) {
+ logger('diaspora_comment: unable to find author details');
+ return;
+ }
+ }
+
$body = diaspora2bb($text);
$message_id = $diaspora_handle . ':' . $guid;
@@ -1613,7 +1632,7 @@ function diaspora_like($importer,$xml,$msg) {
intval($r[0]['id']),
intval($importer['uid'])
);*/
- // FIXME
+ // FIXME--actually don't unless it turns out that Diaspora does indeed send out "false" likes
// send notification via proc_run()
return;
}
@@ -1626,45 +1645,64 @@ function diaspora_like($importer,$xml,$msg) {
return;
}
- $signed_data = $guid . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $diaspora_handle;
- $author_signature = base64_decode($author_signature);
+ /* How Diaspora performs "like" signature checking:
- if(strcasecmp($diaspora_handle,$msg['author']) == 0) {
- $person = $contact;
- $key = $msg['key'];
- }
- else {
- $person = find_diaspora_person_by_handle($diaspora_handle);
- if(is_array($person) && x($person,'pubkey'))
- $key = $person['pubkey'];
- else {
- logger('diaspora_like: unable to find author details');
- return;
- }
- }
+ - If an item has been sent by the like author to the top-level post owner to relay on
+ to the rest of the contacts on the top-level post, the top-level post owner should check
+ the author_signature, then create a parent_author_signature before relaying the like on
+ - If an item has been relayed on by the top-level post owner, the contacts who receive it
+ check only the parent_author_signature. Basically, they trust that the top-level post
+ owner has already verified the authenticity of anything he/she sends out
+ - In either case, the signature that get checked is the signature created by the person
+ who sent the salmon
+ */
- if(! rsa_verify($signed_data,$author_signature,$key,'sha256')) {
- logger('diaspora_like: verification failed.');
- return;
- }
+ $signed_data = $guid . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $diaspora_handle;
+ $key = $msg['key'];
if($parent_author_signature) {
-
- //$owner_signed_data = $guid . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $diaspora_handle;
+ // If a parent_author_signature exists, then we've received the like
+ // relayed from the top-level post owner. There's no need to check the
+ // author_signature if the parent_author_signature is valid
$parent_author_signature = base64_decode($parent_author_signature);
- $key = $msg['key'];
-
if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) {
- logger('diaspora_like: owner verification failed.');
+ logger('diaspora_like: top-level owner verification failed.');
+ return;
+ }
+ }
+ else {
+ // If there's no parent_author_signature, then we've received the like
+ // from the like creator. In that case, the person is "like"ing
+ // our post, so he/she must be a contact of ours and his/her public key
+ // should be in $msg['key']
+
+ $author_signature = base64_decode($author_signature);
+
+ if(! rsa_verify($signed_data,$author_signature,$key,'sha256')) {
+ logger('diaspora_like: like creator verification failed.');
return;
}
}
// Phew! Everything checks out. Now create an item.
+ // Find the original comment author information.
+ // We need this to make sure we display the comment author
+ // information (name and avatar) correctly.
+ if(strcasecmp($diaspora_handle,$msg['author']) == 0)
+ $person = $contact;
+ else {
+ $person = find_diaspora_person_by_handle($diaspora_handle);
+
+ if(! is_array($person)) {
+ logger('diaspora_like: unable to find author details');
+ return;
+ }
+ }
+
$uri = $diaspora_handle . ':' . $guid;
$activity = ACTIVITY_LIKE;
@@ -1802,39 +1840,38 @@ function diaspora_signed_retraction($importer,$xml,$msg) {
$signed_data = $guid . ';' . $type ;
+ $key = $msg['key'];
- $sig_decode = base64_decode($sig);
+ /* How Diaspora performs relayable_retraction signature checking:
- if(strcasecmp($diaspora_handle,$msg['author']) == 0) {
- $person = $contact;
- $key = $msg['key'];
- }
- else {
- $person = find_diaspora_person_by_handle($diaspora_handle);
+ - If an item has been sent by the item author to the top-level post owner to relay on
+ to the rest of the contacts on the top-level post, the top-level post owner checks
+ the author_signature, then creates a parent_author_signature before relaying the item on
+ - If an item has been relayed on by the top-level post owner, the contacts who receive it
+ check only the parent_author_signature. Basically, they trust that the top-level post
+ owner has already verified the authenticity of anything he/she sends out
+ - In either case, the signature that get checked is the signature created by the person
+ who sent the salmon
+ */
- if(is_array($person) && x($person,'pubkey'))
- $key = $person['pubkey'];
- else {
- logger('diaspora_signed_retraction: unable to find author details');
+ if($parent_author_signature) {
+
+ $parent_author_signature = base64_decode($parent_author_signature);
+
+ if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) {
+ logger('diaspora_signed_retraction: top-level post owner verification failed');
return;
}
- }
- if(! rsa_verify($signed_data,$sig_decode,$key,'sha256')) {
- logger('diaspora_signed_retraction: retraction-owner verification failed.' . print_r($msg,true));
- return;
}
+ else {
- if($parent_author_signature) {
- $parent_author_signature = base64_decode($parent_author_signature);
-
- $key = $msg['key'];
+ $sig_decode = base64_decode($sig);
- if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) {
- logger('diaspora_signed_retraction: failed to verify person relaying the retraction (e.g. owner of a post relaying a retracted comment');
+ if(! rsa_verify($signed_data,$sig_decode,$key,'sha256')) {
+ logger('diaspora_signed_retraction: retraction owner verification failed.' . print_r($msg,true));
return;
}
-
}
if($type === 'StatusMessage' || $type === 'Comment' || $type === 'Like') {
@@ -2113,7 +2150,7 @@ function diaspora_send_followup($item,$owner,$contact,$public_batch = false) {
$a = get_app();
$myaddr = $owner['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3);
- $theiraddr = $contact['addr'];
+// $theiraddr = $contact['addr'];
// The first item in the `item` table with the parent id is the parent. However, MySQL doesn't always
// return the items ordered by `item`.`id`, in which case the wrong item is chosen as the parent.
@@ -2176,7 +2213,10 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) {
$a = get_app();
$myaddr = $owner['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3);
- $theiraddr = $contact['addr'];
+// $theiraddr = $contact['addr'];
+
+ $body = $item['body'];
+ $text = html_entity_decode(bb2diaspora($body));
// The first item in the `item` table with the parent id is the parent. However, MySQL doesn't always
@@ -2195,26 +2235,30 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) {
$relay_retract = false;
$sql_sign_id = 'iid';
if( $item['deleted']) {
- $tpl = get_markup_template('diaspora_relayable_retraction.tpl');
$relay_retract = true;
- $sql_sign_id = 'retract_iid';
+
$target_type = ( ($item['verb'] === ACTIVITY_LIKE) ? 'Like' : 'Comment');
+ $sender_signed_text = $item['guid'] . ';' . $target_type ;
+
+ $sql_sign_id = 'retract_iid';
+ $tpl = get_markup_template('diaspora_relayable_retraction.tpl');
}
elseif($item['verb'] === ACTIVITY_LIKE) {
- $tpl = get_markup_template('diaspora_like_relay.tpl');
$like = true;
+
$target_type = 'Post';
// $positive = (($item['deleted']) ? 'false' : 'true');
$positive = 'true';
+ $sender_signed_text = $item['guid'] . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $myaddr;
+
+ $tpl = get_markup_template('diaspora_like_relay.tpl');
}
- else {
+ else { // item is a comment
+ $sender_signed_text = $item['guid'] . ';' . $parent_guid . ';' . $text . ';' . $myaddr;
+
$tpl = get_markup_template('diaspora_comment_relay.tpl');
}
- $body = $item['body'];
-
- $text = html_entity_decode(bb2diaspora($body));
-
// fetch the original signature if the relayable was created by a Diaspora
// or DFRN user. Relayables for other networks are not supported.
@@ -2235,51 +2279,20 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) {
// function is called
logger('diaspora_send_relay: original author signature not found, cannot send relayable');
return;
-/*
- $itemcontact = q("select * from contact where `id` = %d limit 1",
- intval($item['contact-id'])
- );
- if(count($itemcontact)) {
- if(! $itemcontact[0]['self']) {
- $prefix = sprintf( t('[Relayed] Comment authored by %s from network %s'),
- '['. $item['author-name'] . ']' . '(' . $item['author-link'] . ')',
- network_to_name($itemcontact['network'])) . "\n";
- // "$body" was assigned to "$text" above. It isn't used after that, so I don't think
- // the following change will do anything
- $body = $prefix . $body;
-
- // I think this comment will fail upon reaching Diaspora, because "$signed_text" is not defined
- }
- }
- else {
- // I'm confused about this "else." Since it sets "$handle = $myaddr," it seems like it should be for the case
- // where the top-level post owner commented on his own post, i.e. "$itemcontact[0]['self']" is true. But it's
- // positioned to be for the case where "count($itemcontact)" is 0.
-
- $handle = $myaddr;
-
- if($like)
- $signed_text = $item['guid'] . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $handle;
- elseif($relay_retract)
- $signed_text = $item['guid'] . ';' . $target_type;
- else
- $signed_text = $item['guid'] . ';' . $parent_guid . ';' . $text . ';' . $handle;
-
- $authorsig = base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256'));
-
- q("insert into sign (`" . $sql_sign_id . "`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ",
- intval($item['id']),
- dbesc($signed_text),
- dbesc($authorsig),
- dbesc($handle)
- );
- }
-*/
}
- // sign it with the top-level owner's signature
+ // Sign the relayable with the top-level owner's signature
+ //
+ // We'll use the $sender_signed_text that we just created, instead of the $signed_text
+ // stored in the database, because that provides the best chance that Diaspora will
+ // be able to reconstruct the signed text the same way we did. This is particularly a
+ // concern for the comment, whose signed text includes the text of the comment. The
+ // smallest change in the text of the comment, including removing whitespace, will
+ // make the signature verification fail. Since we translate from BB code to Diaspora's
+ // markup at the top of this function, which is AFTER we placed the original $signed_text
+ // in the database, it's hazardous to trust the original $signed_text.
- $parentauthorsig = base64_encode(rsa_sign($signed_text,$owner['uprvkey'],'sha256'));
+ $parentauthorsig = base64_encode(rsa_sign($sender_signed_text,$owner['uprvkey'],'sha256'));
$msg = replace_macros($tpl,array(
'$guid' => xmlify($item['guid']),
diff --git a/include/enotify.php b/include/enotify.php
index fe0f128b6..134e42f8e 100644
--- a/include/enotify.php
+++ b/include/enotify.php
@@ -41,8 +41,8 @@ function notification($params) {
$subject = sprintf( t('[Friendica:Notify] New mail received at %s'),$sitename);
- $preamble = sprintf( t('%s sent you a new private message at %s.'),$params['source_name'],$sitename);
- $epreamble = sprintf( t('%s sent you %s.'),'[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]', '[url=$itemlink]' . t('a private message') . '[/url]');
+ $preamble = sprintf( t('%1$s sent you a new private message at %2$s.'),$params['source_name'],$sitename);
+ $epreamble = sprintf( t('%1$s sent you %2$s.'),'[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]', '[url=$itemlink]' . t('a private message') . '[/url]');
$sitelink = t('Please visit %s to view and/or reply to your private messages.');
$tsitelink = sprintf( $sitelink, $siteurl . '/message/' . $params['item']['id'] );
$hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '/message/' . $params['item']['id'] . '">' . $sitename . '</a>');
@@ -66,27 +66,38 @@ function notification($params) {
);
}
- $possess_desc = str_replace('<!item_type!>',item_post_type($p[0]),$possess_desc);
+ $item_post_type = item_post_type($p[0]);
+ //$possess_desc = str_replace('<!item_type!>',$possess_desc);
// "a post"
- $dest_str = sprintf($possess_desc,'a');
+ $dest_str = sprintf(t('%1$s commented on [url=%2$s]a %3$s[/url]'),
+ '[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]',
+ $itemlink,
+ $item_post_type);
// "George Bull's post"
if($p)
- $dest_str = sprintf($possess_desc,sprintf( t("%s's"),$p[0]['author-name']));
+ $dest_str = sprintf(t('%1$s commented on [url=%2$s]%3$s\'s %4$s[/url]'),
+ '[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]',
+ $itemlink,
+ $p[0]['author-name'],
+ $item_post_type);
// "your post"
if($p[0]['owner-name'] == $p[0]['author-name'] && $p[0]['wall'])
- $dest_str = sprintf($possess_desc, t('your') );
+ $dest_str = sprintf(t('%1$s commented on [url=%2$s]your %3$s[/url]'),
+ '[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]',
+ $itemlink,
+ $item_post_type);
// Some mail softwares relies on subject field for threading.
// So, we cannot have different subjects for notifications of the same thread.
// Before this we have the name of the replier on the subject rendering
// differents subjects for messages on the same thread.
- $subject = sprintf( t('[Friendica:Notify] Comment to conversation #%d by %s'), $parent_id, $params['source_name']);
+ $subject = sprintf( t('[Friendica:Notify] Comment to conversation #%1$d by %2$s'), $parent_id, $params['source_name']);
$preamble = sprintf( t('%s commented on an item/conversation you have been following.'), $params['source_name']);
- $epreamble = sprintf( t('%s commented on %s.'), '[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]', '[url=$itemlink]' . $dest_str . '[/url]');
+ $epreamble = $dest_str;
$sitelink = t('Please visit %s to view and/or reply to the conversation.');
$tsitelink = sprintf( $sitelink, $siteurl );
@@ -97,9 +108,11 @@ function notification($params) {
if($params['type'] == NOTIFY_WALL) {
$subject = sprintf( t('[Friendica:Notify] %s posted to your profile wall') , $params['source_name']);
- $preamble = sprintf( t('%s posted to your profile wall at %s') , $params['source_name'], $sitename);
+ $preamble = sprintf( t('%1$s posted to your profile wall at %2$s') , $params['source_name'], $sitename);
- $epreamble = sprintf( t('%s posted to %s') , '[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]', '[url=$itemlink]' . t('your profile wall.') . '[/url]');
+ $epreamble = sprintf( t('%1$s posted to [url=%2s]your wall[/url]') ,
+ '[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]',
+ $itemlink);
$sitelink = t('Please visit %s to view and/or reply to the conversation.');
$tsitelink = sprintf( $sitelink, $siteurl );
@@ -109,8 +122,10 @@ function notification($params) {
if($params['type'] == NOTIFY_TAGSELF) {
$subject = sprintf( t('[Friendica:Notify] %s tagged you') , $params['source_name']);
- $preamble = sprintf( t('%s tagged you at %s') , $params['source_name'], $sitename);
- $epreamble = sprintf( t('%s %s.') , '[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]', '[url=' . $params['link'] . ']' . t('tagged you') . '[/url]');
+ $preamble = sprintf( t('%1$s tagged you at %2$s') , $params['source_name'], $sitename);
+ $epreamble = sprintf( t('%1$s [url=%2$s]tagged you[/url].') ,
+ '[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]',
+ $params['link']);
$sitelink = t('Please visit %s to view and/or reply to the conversation.');
$tsitelink = sprintf( $sitelink, $siteurl );
@@ -120,8 +135,10 @@ function notification($params) {
if($params['type'] == NOTIFY_TAGSHARE) {
$subject = sprintf( t('[Friendica:Notify] %s tagged your post') , $params['source_name']);
- $preamble = sprintf( t('%s tagged your post at %s') , $params['source_name'], $sitename);
- $epreamble = sprintf( t('%s tagged %s') , '[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]', '[url=$itemlink]' . t('your post') . '[/url]' );
+ $preamble = sprintf( t('%1$s tagged your post at %2$s') , $params['source_name'], $sitename);
+ $epreamble = sprintf( t('%1$s tagged [url=%2$s]your post[/url]') ,
+ '[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]',
+ $itemlink);
$sitelink = t('Please visit %s to view and/or reply to the conversation.');
$tsitelink = sprintf( $sitelink, $siteurl );
@@ -131,8 +148,10 @@ function notification($params) {
if($params['type'] == NOTIFY_INTRO) {
$subject = sprintf( t('[Friendica:Notify] Introduction received'));
- $preamble = sprintf( t('You\'ve received an introduction from \'%s\' at %s'), $params['source_name'], $sitename);
- $epreamble = sprintf( t('You\'ve received %s from %s.'), '[url=$itemlink]' . t('an introduction') . '[/url]' , '[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]');
+ $preamble = sprintf( t('You\'ve received an introduction from \'%1$s\' at %2$s'), $params['source_name'], $sitename);
+ $epreamble = sprintf( t('You\'ve received [url=%1$s]an introduction[/url] from %2$s.'),
+ $itemlink,
+ '[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]');
$body = sprintf( t('You may visit their profile at %s'),$params['source_link']);
$sitelink = t('Please visit %s to approve or reject the introduction.');
@@ -143,11 +162,12 @@ function notification($params) {
if($params['type'] == NOTIFY_SUGGEST) {
$subject = sprintf( t('[Friendica:Notify] Friend suggestion received'));
- $preamble = sprintf( t('You\'ve received a friend suggestion from \'%s\' at %s'), $params['source_name'], $sitename);
- $epreamble = sprintf( t('You\'ve received %s for %s from %s.'),
- '[url=$itemlink]' . t('a friend suggestion') . '[/url]',
- '[url=' . $params['item']['url'] . ']' . $params['item']['name'] . '[/url]',
- '[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]');
+ $preamble = sprintf( t('You\'ve received a friend suggestion from \'%1$s\' at %2$s'), $params['source_name'], $sitename);
+ $epreamble = sprintf( t('You\'ve received [url=%1$s]a friend suggestion[/url] for %2$s from %3$s.'),
+ $itemlink,
+ '[url=' . $params['item']['url'] . ']' . $params['item']['name'] . '[/url]',
+ '[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]');
+
$body = t('Name:') . ' ' . $params['item']['name'] . "\n";
$body .= t('Photo:') . ' ' . $params['item']['photo'] . "\n";
$body .= sprintf( t('You may visit their profile at %s'),$params['item']['url']);
diff --git a/include/items.php b/include/items.php
index 95a885a1b..a0dd1c815 100755
--- a/include/items.php
+++ b/include/items.php
@@ -22,8 +22,6 @@ function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0)
if($a->argv[$x] === 'category' && $a->argc > ($x + 1) && strlen($a->argv[$x+1]))
$category = $a->argv[$x+1];
}
-
-
}
@@ -448,6 +446,8 @@ function get_atom_elements($feed,$item) {
$res['body'] = $purifier->purify($res['body']);
$res['body'] = @html2bbcode($res['body']);
+
+
}
elseif(! $have_real_body) {
@@ -816,6 +816,12 @@ function item_store($arr,$force_parent = false) {
if($r[0]['private'])
$arr['private'] = 1;
+ // Edge case. We host a public forum that was originally posted to privately.
+ // The original author commented, but as this is a comment, the permissions
+ // weren't fixed up so it will still show the comment as private unless we fix it here.
+
+ if((intval($r[0]['forum_mode']) == 1) && (! $r[0]['private']))
+ $arr['private'] = 0;
}
else {
@@ -910,6 +916,16 @@ function item_store($arr,$force_parent = false) {
intval($current_post)
);
+ $arr['id'] = $current_post;
+ $arr['parent'] = $parent_id;
+ $arr['allow_cid'] = $allow_cid;
+ $arr['allow_gid'] = $allow_gid;
+ $arr['deny_cid'] = $deny_cid;
+ $arr['deny_gid'] = $deny_gid;
+ $arr['private'] = $private;
+ $arr['deleted'] = $parent_deleted;
+ call_hooks('post_remote_end',$arr);
+
// update the commented timestamp on the parent
q("UPDATE `item` set `commented` = '%s', `changed` = '%s' WHERE `id` = %d LIMIT 1",
@@ -1250,6 +1266,12 @@ function dfrn_deliver($owner,$contact,$atom, $dissolve = false) {
return 3;
}
+ if($contact['term-date'] != '0000-00-00 00:00:00') {
+ logger("dfrn_deliver: $url back from the dead - removing mark for death");
+ require_once('include/Contact.php');
+ unmark_for_death($contact);
+ }
+
$res = parse_xml_string($xml);
return $res->status;
@@ -1645,6 +1667,11 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0)
if(count($r)) {
if((x($datarray,'edited') !== false) && (datetime_convert('UTC','UTC',$datarray['edited']) !== $r[0]['edited'])) {
+
+ // do not accept (ignore) an earlier edit than one we currently have.
+ if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited'])
+ continue;
+
$r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc($datarray['title']),
dbesc($datarray['body']),
@@ -1791,6 +1818,11 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0)
if(count($r)) {
if((x($datarray,'edited') !== false) && (datetime_convert('UTC','UTC',$datarray['edited']) !== $r[0]['edited'])) {
+
+ // do not accept (ignore) an earlier edit than one we currently have.
+ if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited'])
+ continue;
+
$r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc($datarray['title']),
dbesc($datarray['body']),
@@ -1845,13 +1877,12 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0)
$datarray['last-child'] = 1;
}
- if($contact['network'] === NETWORK_FEED) {
- if(! strlen($contact['notify'])) {
+ if(($contact['network'] === NETWORK_FEED) || (! strlen($contact['notify']))) {
// one way feed - no remote comment ability
$datarray['last-child'] = 0;
- }
- $datarray['private'] = 1;
}
+ if($contact['network'] === NETWORK_FEED)
+ $datarray['private'] = 1;
// This is my contact on another system, but it's really me.
// Turn this into a wall post.
@@ -2277,7 +2308,12 @@ function local_delivery($importer,$data) {
if(count($r)) {
$iid = $r[0]['id'];
- if((x($datarray,'edited') !== false) && (datetime_convert('UTC','UTC',$datarray['edited']) !== $r[0]['edited'])) {
+ if((x($datarray,'edited') !== false) && (datetime_convert('UTC','UTC',$datarray['edited']) !== $r[0]['edited'])) {
+
+ // do not accept (ignore) an earlier edit than one we currently have.
+ if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited'])
+ continue;
+
logger('received updated comment' , LOGGER_DEBUG);
$r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc($datarray['title']),
@@ -2456,6 +2492,11 @@ function local_delivery($importer,$data) {
if(count($r)) {
if((x($datarray,'edited') !== false) && (datetime_convert('UTC','UTC',$datarray['edited']) !== $r[0]['edited'])) {
+
+ // do not accept (ignore) an earlier edit than one we currently have.
+ if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited'])
+ continue;
+
$r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc($datarray['title']),
dbesc($datarray['body']),
@@ -2622,6 +2663,11 @@ function local_delivery($importer,$data) {
if(count($r)) {
if((x($datarray,'edited') !== false) && (datetime_convert('UTC','UTC',$datarray['edited']) !== $r[0]['edited'])) {
+
+ // do not accept (ignore) an earlier edit than one we currently have.
+ if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited'])
+ continue;
+
$r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s' WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc($datarray['title']),
dbesc($datarray['body']),
@@ -3358,3 +3404,69 @@ function drop_item($id,$interactive = true) {
}
}
+
+
+function first_post_date($uid,$wall = false) {
+ $r = q("select id, created from item
+ where uid = %d and wall = %d and deleted = 0 and visible = 1 AND moderated = 0
+ and id = parent
+ order by created asc limit 1",
+ intval($uid),
+ intval($wall ? 1 : 0)
+ );
+ if(count($r)) {
+// logger('first_post_date: ' . $r[0]['id'] . ' ' . $r[0]['created'], LOGGER_DATA);
+ return substr(datetime_convert('',date_default_timezone_get(),$r[0]['created']),0,10);
+ }
+ return false;
+}
+
+function posted_dates($uid,$wall) {
+ $dnow = datetime_convert('',date_default_timezone_get(),'now','Y-m-d');
+
+ $dthen = first_post_date($uid,$wall);
+ if(! $dthen)
+ return array();
+
+ // If it's near the end of a long month, backup to the 28th so that in
+ // consecutive loops we'll always get a whole month difference.
+
+ if(intval(substr($dnow,8)) > 28)
+ $dnow = substr($dnow,0,8) . '28';
+ if(intval(substr($dthen,8)) > 28)
+ $dnow = substr($dthen,0,8) . '28';
+
+ $ret = array();
+ while($dnow >= $dthen) {
+ $dstart = substr($dnow,0,8) . '01';
+ $dend = substr($dnow,0,8) . get_dim(intval($dnow),intval(substr($dnow,5)));
+ $start_month = datetime_convert('','',$dstart,'Y-m-d');
+ $end_month = datetime_convert('','',$dend,'Y-m-d');
+ $str = day_translate(datetime_convert('','',$dnow,'F Y'));
+ $ret[] = array($str,$end_month,$start_month);
+ $dnow = datetime_convert('','',$dnow . ' -1 month', 'Y-m-d');
+ }
+ return $ret;
+}
+
+
+function posted_date_widget($url,$uid,$wall) {
+ $o = '';
+
+ // For former Facebook folks that left because of "timeline"
+
+ if($wall && intval(get_pconfig($uid,'system','no_wall_archive_widget')))
+ return $o;
+
+ $ret = posted_dates($uid,$wall);
+ if(! count($ret))
+ return $o;
+
+ $o = replace_macros(get_markup_template('posted_date_widget.tpl'),array(
+ '$title' => t('Archives'),
+ '$size' => ((count($ret) > 6) ? 6 : count($ret)),
+ '$url' => $url,
+ '$dates' => $ret
+ ));
+ return $o;
+} \ No newline at end of file
diff --git a/include/nav.php b/include/nav.php
index 909ba9b54..a67a8b614 100644
--- a/include/nav.php
+++ b/include/nav.php
@@ -55,7 +55,7 @@ function nav(&$a) {
// user info
$r = q("SELECT micro FROM contact WHERE uid=%d AND self=1", intval($a->user['uid']));
$userinfo = array(
- 'icon' => (count($r) ? $r[0]['micro']: $a->get_baseurl($ssl_state)."/images/person-48.jpg"),
+ 'icon' => (count($r) ? $a->get_cached_avatar_image($r[0]['micro']) : $a->get_baseurl($ssl_state)."/images/person-48.jpg"),
'name' => $a->user['username'],
);
diff --git a/include/onepoll.php b/include/onepoll.php
index ba7d5ebaf..d68f26883 100644
--- a/include/onepoll.php
+++ b/include/onepoll.php
@@ -36,11 +36,6 @@ function onepoll_run($argv, $argc){
logger('onepoll: start');
- $abandon_days = intval(get_config('system','account_abandon_days'));
- if($abandon_days < 1)
- $abandon_days = 0;
-
-
$manual_id = 0;
$generation = 0;
$hub_update = false;
@@ -54,9 +49,7 @@ function onepoll_run($argv, $argc){
logger('onepoll: no contact');
return;
}
-
- if(was_recently_delayed($contact_id))
- return;
+
$d = datetime_convert();
@@ -64,11 +57,6 @@ function onepoll_run($argv, $argc){
// and which have a polling address and ignore Diaspora since
// we are unable to match those posts with a Diaspora GUID and prevent duplicates.
- $abandon_sql = (($abandon_days)
- ? sprintf(" AND `user`.`login_date` > UTC_TIMESTAMP() - INTERVAL %d DAY ", intval($abandon_days))
- : ''
- );
-
$contacts = q("SELECT `contact`.* FROM `contact`
WHERE ( `rel` = %d OR `rel` = %d ) AND `poll` != ''
AND NOT `network` IN ( '%s', '%s' )
@@ -88,14 +76,13 @@ function onepoll_run($argv, $argc){
$contact = $contacts[0];
-
$xml = false;
$t = $contact['last-update'];
if($contact['subhub']) {
- $interval = get_config('system','pushpoll_frequency');
- $contact['priority'] = (($interval !== false) ? intval($interval) : 3);
+ $poll_interval = get_config('system','pushpoll_frequency');
+ $contact['priority'] = (($poll_interval !== false) ? intval($poll_interval) : 3);
$hub_update = false;
if(datetime_convert('UTC','UTC', 'now') > datetime_convert('UTC','UTC', $t . " + 1 day"))
@@ -139,15 +126,18 @@ function onepoll_run($argv, $argc){
. '&perm=' . $perm ;
$handshake_xml = fetch_url($url);
+ $html_code = $a->get_curl_code();
logger('onepoll: handshake with url ' . $url . ' returns xml: ' . $handshake_xml, LOGGER_DATA);
- if(! $handshake_xml) {
+ if((! strlen($handshake_xml)) || ($html_code >= 400) || (! $html_code)) {
logger("poller: $url appears to be dead - marking for death ");
+
// dead connection - might be a transient event, or this might
// mean the software was uninstalled or the domain expired.
// Will keep trying for one month.
+
mark_for_death($contact);
// set the last-update so we don't keep polling
@@ -161,6 +151,9 @@ function onepoll_run($argv, $argc){
if(! strstr($handshake_xml,'<?xml')) {
logger('poller: response from ' . $url . ' did not contain XML.');
+
+ mark_for_death($contact);
+
$r = q("UPDATE `contact` SET `last-update` = '%s' WHERE `id` = %d LIMIT 1",
dbesc(datetime_convert()),
intval($contact['id'])
diff --git a/include/plugin.php b/include/plugin.php
index ae8eee78a..c6b61ae6e 100644
--- a/include/plugin.php
+++ b/include/plugin.php
@@ -148,7 +148,9 @@ function load_hooks() {
$r = q("SELECT * FROM `hook` WHERE 1");
if(count($r)) {
foreach($r as $rr) {
- $a->hooks[] = array($rr['hook'], $rr['file'], $rr['function']);
+ if(! array_key_exists($rr['hook'],$a->hooks))
+ $a->hooks[$rr['hook']] = array();
+ $a->hooks[$rr['hook']][] = array($rr['file'],$rr['function']);
}
}
}}
@@ -158,25 +160,24 @@ if(! function_exists('call_hooks')) {
function call_hooks($name, &$data = null) {
$a = get_app();
- if(count($a->hooks)) {
- foreach($a->hooks as $hook) {
- if($hook[HOOK_HOOK] === $name) {
- @include_once($hook[HOOK_FILE]);
- if(function_exists($hook[HOOK_FUNCTION])) {
- $func = $hook[HOOK_FUNCTION];
- $func($a,$data);
- }
- else {
- // remove orphan hooks
- q("delete from hook where hook = '%s' and file = '$s' and function = '%s' limit 1",
- dbesc($hook[HOOK_HOOK]),
- dbesc($hook[HOOK_FILE]),
- dbesc($hook[HOOK_FUNCTION])
- );
- }
+ if((is_array($a->hooks)) && (array_key_exists($name,$a->hooks))) {
+ foreach($a->hooks[$name] as $hook) {
+ @include_once($hook[0]);
+ if(function_exists($hook[1])) {
+ $func = $hook[1];
+ $func($a,$data);
+ }
+ else {
+ // remove orphan hooks
+ q("delete from hook where hook = '%s' and file = '$s' and function = '%s' limit 1",
+ dbesc($name),
+ dbesc($hook[0]),
+ dbesc($hook[1])
+ );
}
}
}
+
}}
diff --git a/include/poller.php b/include/poller.php
index 6b12445d1..fefc9b381 100644
--- a/include/poller.php
+++ b/include/poller.php
@@ -201,8 +201,8 @@ function poller_run($argv, $argc){
if($contact['subhub']) {
- $interval = get_config('system','pushpoll_frequency');
- $contact['priority'] = (($interval !== false) ? intval($interval) : 3);
+ $poll_interval = get_config('system','pushpoll_frequency');
+ $contact['priority'] = (($poll_interval !== false) ? intval($poll_interval) : 3);
$hub_update = false;
if((datetime_convert('UTC','UTC', 'now') > datetime_convert('UTC','UTC', $t . " + 1 day")) || $force)
diff --git a/include/queue_fn.php b/include/queue_fn.php
index 2aca338f5..e43912431 100644
--- a/include/queue_fn.php
+++ b/include/queue_fn.php
@@ -23,6 +23,13 @@ function was_recently_delayed($cid) {
);
if(count($r))
return true;
+
+ $r = q("select `term-date` from contact where id = %d and `term-date` != '' and `term-date` != '0000-00-00 00:00:00' limit 1",
+ intval($cid)
+ );
+ if(count($r))
+ return true;
+
return false;
}
diff --git a/include/text.php b/include/text.php
index d4a4d5580..cc4bee268 100644
--- a/include/text.php
+++ b/include/text.php
@@ -1059,7 +1059,7 @@ function feed_salmonlinks($nick) {
if(! function_exists('get_plink')) {
function get_plink($item) {
$a = get_app();
- if (x($item,'plink') && (! $item['private'])){
+ if (x($item,'plink') && ((! $item['private']) || ($item['network'] === NETWORK_FEED))){
return array(
'href' => $item['plink'],
'title' => t('link to source'),
@@ -1255,13 +1255,13 @@ function bb_translate_video($s) {
function html2bb_video($s) {
- $s = preg_replace('#<object[^>]+>(.*?)https+://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+)(.*?)</object>#ism',
+ $s = preg_replace('#<object[^>]+>(.*?)https?://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+)(.*?)</object>#ism',
'[youtube]$2[/youtube]', $s);
- $s = preg_replace('#<iframe[^>](.*?)https+://www.youtube.com/embed/([A-Za-z0-9\-_=]+)(.*?)</iframe>#ism',
+ $s = preg_replace('#<iframe[^>](.*?)https?://www.youtube.com/embed/([A-Za-z0-9\-_=]+)(.*?)</iframe>#ism',
'[youtube]$2[/youtube]', $s);
- $s = preg_replace('#<iframe[^>](.*?)https+://player.vimeo.com/video/([0-9]+)(.*?)</iframe>#ism',
+ $s = preg_replace('#<iframe[^>](.*?)https?://player.vimeo.com/video/([0-9]+)(.*?)</iframe>#ism',
'[vimeo]$2[/vimeo]', $s);
return $s;
@@ -1541,3 +1541,16 @@ function protect_sprintf($s) {
return(str_replace('%','%%',$s));
}
+
+function is_a_date_arg($s) {
+ $i = intval($s);
+ if($i > 1900) {
+ $y = date('Y');
+ if($i <= $y+1 && strpos($s,'-') == 4) {
+ $m = intval(substr($s,5));
+ if($m > 0 && $m <= 12)
+ return true;
+ }
+ }
+ return false;
+}