diff options
Diffstat (limited to 'include/items.php')
-rwxr-xr-x | include/items.php | 887 |
1 files changed, 484 insertions, 403 deletions
diff --git a/include/items.php b/include/items.php index 05ff1b078..370dd5c72 100755 --- a/include/items.php +++ b/include/items.php @@ -19,7 +19,9 @@ function collect_recipients($item,&$private_envelope) { // it is private $allow_people = expand_acl($item['allow_cid']); + $allow_groups = expand_groups(expand_acl($item['allow_gid'])); + $allow_groups = filter_insecure($item['uid'],$allow_groups); $recipients = array_unique(array_merge($allow_people,$allow_groups)); @@ -44,7 +46,13 @@ function collect_recipients($item,&$private_envelope) { $deny_groups = expand_groups(expand_acl($item['deny_gid'])); $deny = array_unique(array_merge($deny_people,$deny_groups)); - $recipients = array_diff($recipients,$deny); + + // Don't deny anybody if nobody was allowed (e.g. they were all filtered out) + // That would lead to array_diff doing the wrong thing. + // This will result in a private post that won't be delivered to anybody. + + if($recipients && $deny) + $recipients = array_diff($recipients,$deny); $private_envelope = true; } else { @@ -95,11 +103,57 @@ function collect_recipients($item,&$private_envelope) { $recipients[] = $item['author_xchan']; if($item['owner_xchan'] != $item['author_xchan']) $recipients[] = $item['owner_xchan']; + return $recipients; } /** + * If channel is configured to filter insecure members of privacy groups + * (those whose networks leak privacy via email notifications or other criteria) + * remove them from any privacy groups (collections) that were included in a post. + * They can still be addressed individually. + * Networks may need to be added or removed from this list as circumstances change. + * + * Update: this may need to be the default, which will force people to opt-in to sending stuff + * privately to insecure platforms. + */ + +function filter_insecure($channel_id,$arr) { + $insecure_nets = " and not xchan_network in ('diaspora', 'friendica-over-diaspora') "; + + $ret = array(); + + if((! intval(get_config($channel_id,'system','filter_insecure_collections'))) || (! $arr)) + return $arr; + + $str = ''; + foreach($arr as $rr) { + if(strlen($str)) + $str .= ','; + $str .= "'" . dbesc($rr) . "'"; + } + $r = q("select xchan_hash from xchan where xchan_hash in ($str) $insecure_nets "); + if($r) { + foreach($r as $rr) { + $ret[] = $rr['xchan_hash']; + } + } + return $ret; +} + + +function comments_are_now_closed($item) { + if($item['comments_closed'] !== '0000-00-00 00:00:00') { + $d = datetime_convert(); + if($d > $item['comments_closed']) + return true; + } + return false; +} + + +/** * @function can_comment_on_post($observer_xchan,$item); * * This function examines the comment_policy attached to an item and decides if the current observer has @@ -108,6 +162,7 @@ function collect_recipients($item,&$private_envelope) { * Generally we should look at the item - in particular the author['book_flags'] and see if ABOOK_FLAG_SELF is set. * If it is, you should be able to use perm_is_allowed( ... 'post_comments'), and if it isn't you need to call * can_comment_on_post() + * We also check the comments_closed date/time on the item if this is set. */ function can_comment_on_post($observer_xchan,$item) { @@ -116,8 +171,14 @@ function can_comment_on_post($observer_xchan,$item) { if(! $observer_xchan) return false; + + if($item['comment_policy'] === 'none') return false; + + if(comments_are_now_closed($item)) + return false; + if($observer_xchan === $item['author_xchan'] || $observer_xchan === $item['owner_xchan']) return true; switch($item['comment_policy']) { @@ -132,6 +193,7 @@ function can_comment_on_post($observer_xchan,$item) { // false. return false; break; + case 'any connections': case 'contacts': case '': if(array_key_exists('owner',$item)) { @@ -296,6 +358,9 @@ function post_activity_item($arr) { return $ret; } + $arr['public_policy'] = ((x($_REQUEST,'public_policy')) ? escape_tags($_REQUEST['public_policy']) : map_scope($channel['channel_r_stream'],true)); + if($arr['public_policy']) + $arr['item_private'] = 1; if(! array_key_exists('mimetype',$arr)) $arr['mimetype'] = 'text/bbcode'; @@ -315,9 +380,9 @@ function post_activity_item($arr) { $key = get_config('system','pubkey'); $arr['item_flags'] = $arr['item_flags'] | ITEM_OBSCURED; if($arr['title']) - $arr['title'] = json_encode(aes_encapsulate($arr['title'],$key)); + $arr['title'] = json_encode(crypto_encapsulate($arr['title'],$key)); if($arr['body']) - $arr['body'] = json_encode(aes_encapsulate($arr['body'],$key)); + $arr['body'] = json_encode(crypto_encapsulate($arr['body'],$key)); } $arr['mid'] = ((x($arr,'mid')) ? $arr['mid'] : item_message_id()); @@ -400,6 +465,7 @@ function get_public_feed($channel,$params) { $params['records'] = ((x($params,'records')) ? $params['records'] : 40); $params['direction'] = ((x($params,'direction')) ? $params['direction'] : 'desc'); $params['pages'] = ((x($params,'pages')) ? intval($params['pages']) : 0); + $params['top'] = ((x($params,'top')) ? intval($params['top']) : 0); switch($params['type']) { case 'json': @@ -440,7 +506,8 @@ function get_feed_for($channel, $observer_hash, $params) { 'records' => $params['records'], // FIXME 'direction' => $params['direction'], // FIXME 'pages' => $params['pages'], - 'order' => 'post' + 'order' => 'post', + 'top' => $params['top'] ), $channel, $observer_hash, CLIENT_MODE_NORMAL, get_app()->module); @@ -696,6 +763,9 @@ function get_item_elements($x) { $arr['commented'] = ((x($x,'commented') && $x['commented']) ? datetime_convert('UTC','UTC',$x['commented']) : $arr['created']); + $arr['comments_closed'] = ((x($x,'comments_closed') && $x['comments_closed']) + ? datetime_convert('UTC','UTC',$x['comments_closed']) + : '0000-00-00 00:00:00'); $arr['title'] = (($x['title']) ? htmlspecialchars($x['title'], ENT_COMPAT,'UTF-8',false) : ''); @@ -884,38 +954,41 @@ function encode_item($item) { } - $x['message_id'] = $item['mid']; - $x['message_top'] = $item['parent_mid']; - $x['message_parent'] = $item['thr_parent']; - $x['created'] = $item['created']; - $x['edited'] = $item['edited']; - $x['expires'] = $item['expires']; - $x['commented'] = $item['commented']; - $x['mimetype'] = $item['mimetype']; - $x['title'] = $item['title']; - $x['body'] = $item['body']; - $x['app'] = $item['app']; - $x['verb'] = $item['verb']; - $x['object_type'] = $item['obj_type']; - $x['target_type'] = $item['tgt_type']; - $x['permalink'] = $item['plink']; - $x['location'] = $item['location']; - $x['longlat'] = $item['coord']; - $x['signature'] = $item['sig']; - $x['route'] = $item['route']; - - $x['owner'] = encode_item_xchan($item['owner']); - $x['author'] = encode_item_xchan($item['author']); + $x['message_id'] = $item['mid']; + $x['message_top'] = $item['parent_mid']; + $x['message_parent'] = $item['thr_parent']; + $x['created'] = $item['created']; + $x['edited'] = $item['edited']; + $x['expires'] = $item['expires']; + $x['commented'] = $item['commented']; + $x['mimetype'] = $item['mimetype']; + $x['title'] = $item['title']; + $x['body'] = $item['body']; + $x['app'] = $item['app']; + $x['verb'] = $item['verb']; + $x['object_type'] = $item['obj_type']; + $x['target_type'] = $item['tgt_type']; + $x['permalink'] = $item['plink']; + $x['location'] = $item['location']; + $x['longlat'] = $item['coord']; + $x['signature'] = $item['sig']; + $x['route'] = $item['route']; + + $x['owner'] = encode_item_xchan($item['owner']); + $x['author'] = encode_item_xchan($item['author']); if($item['object']) - $x['object'] = json_decode_plus($item['object']); + $x['object'] = json_decode_plus($item['object']); if($item['target']) - $x['target'] = json_decode_plus($item['target']); + $x['target'] = json_decode_plus($item['target']); if($item['attach']) - $x['attach'] = json_decode_plus($item['attach']); + $x['attach'] = json_decode_plus($item['attach']); if($y = encode_item_flags($item)) - $x['flags'] = $y; + $x['flags'] = $y; + + if($item['comments_closed'] !== '0000-00-00 00:00:00') + $x['comments_closed'] = $item['comments_closed']; - $x['public_scope'] = $scope; + $x['public_scope'] = $scope; if($item['item_flags'] & ITEM_NOCOMMENT) $x['comment_scope'] = 'none'; @@ -923,7 +996,7 @@ function encode_item($item) { $x['comment_scope'] = $c_scope; if($item['term']) - $x['tags'] = encode_item_terms($item['term']); + $x['tags'] = encode_item_terms($item['term']); logger('encode_item: ' . print_r($x,true), LOGGER_DATA); @@ -969,6 +1042,8 @@ function translate_scope($scope) { return t('Visible to all connections.'); if(strpos($scope,'contacts') === 0) return t('Visible to approved connections.'); + if(strpos($scope,'specific') === 0) + return t('Visible to specific connections.'); } function encode_item_xchan($xchan) { @@ -1224,22 +1299,23 @@ function get_profile_elements($x) { -function get_atom_elements($feed,$item) { +function get_atom_elements($feed,$item,&$author) { $best_photo = array(); $res = array(); - $author = $item->get_author(); - if($author) { - $res['author-name'] = unxmlify($author->get_name()); - $res['author-link'] = unxmlify($author->get_link()); + $found_author = $item->get_author(); + if($found_author) { + $author['author_name'] = unxmlify($found_author->get_name()); + $author['author_link'] = unxmlify($found_author->get_link()); } else { - $res['author-name'] = unxmlify($feed->get_title()); - $res['author-link'] = unxmlify($feed->get_permalink()); + $author['author_name'] = unxmlify($feed->get_title()); + $author['author_link'] = unxmlify($feed->get_permalink()); } + $res['mid'] = unxmlify($item->get_id()); $res['title'] = unxmlify($item->get_title()); $res['body'] = unxmlify($item->get_content()); @@ -1264,9 +1340,9 @@ function get_atom_elements($feed,$item) { if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) { $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']; foreach($base as $link) { - if(!x($res, 'author-avatar') || !$res['author-avatar']) { + if(!x($author, 'author_photo') || ! $author['author_photo']) { if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') - $res['author-avatar'] = unxmlify($link['attribs']['']['href']); + $author['author_photo'] = unxmlify($link['attribs']['']['href']); } } } @@ -1277,11 +1353,11 @@ function get_atom_elements($feed,$item) { $base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']; if($base && count($base)) { foreach($base as $link) { - if($link['attribs']['']['rel'] === 'alternate' && (! $res['author-link'])) - $res['author-link'] = unxmlify($link['attribs']['']['href']); - if(!x($res, 'author-avatar') || !$res['author-avatar']) { + if($link['attribs']['']['rel'] === 'alternate' && (! $res['author_link'])) + $author['author_link'] = unxmlify($link['attribs']['']['href']); + if(!x($author, 'author_photo') || ! $author['author_photo']) { if($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo') - $res['author-avatar'] = unxmlify($link['attribs']['']['href']); + $author['author_photo'] = unxmlify($link['attribs']['']['href']); } } } @@ -1289,16 +1365,16 @@ function get_atom_elements($feed,$item) { // No photo/profile-link on the item - look at the feed level - if((! (x($res,'author-link'))) || (! (x($res,'author-avatar')))) { + if((! (x($author,'author_link'))) || (! (x($author,'author_photo')))) { $rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author'); if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) { $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']; foreach($base as $link) { - if($link['attribs']['']['rel'] === 'alternate' && (! $res['author-link'])) - $res['author-link'] = unxmlify($link['attribs']['']['href']); - if(! $res['author-avatar']) { + if($link['attribs']['']['rel'] === 'alternate' && (! $author['author_link'])) + $author['author_link'] = unxmlify($link['attribs']['']['href']); + if(! $author['author_photo']) { if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') - $res['author-avatar'] = unxmlify($link['attribs']['']['href']); + $author['author_photo'] = unxmlify($link['attribs']['']['href']); } } } @@ -1310,11 +1386,11 @@ function get_atom_elements($feed,$item) { if($base && count($base)) { foreach($base as $link) { - if($link['attribs']['']['rel'] === 'alternate' && (! $res['author-link'])) - $res['author-link'] = unxmlify($link['attribs']['']['href']); - if(! (x($res,'author-avatar'))) { + if($link['attribs']['']['rel'] === 'alternate' && (! $res['author_link'])) + $author['author_link'] = unxmlify($link['attribs']['']['href']); + if(! (x($author,'author_photo'))) { if($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo') - $res['author-avatar'] = unxmlify($link['attribs']['']['href']); + $author['author_photo'] = unxmlify($link['attribs']['']['href']); } } } @@ -1339,6 +1415,12 @@ function get_atom_elements($feed,$item) { $res['body'] = str_replace(array(' ',"\t","\r","\n"), array('','','',''),$res['body']); // make sure nobody is trying to sneak some html tags by us $res['body'] = notags(base64url_decode($res['body'])); + + // We could probably turn these old Friendica bbcode bookmarks into bookmark tags but we'd have to + // create a term table item for them. For now just make sure they stay as links. + + $res['body'] = preg_replace('/\[bookmark(.*?)\](.*?)\[\/bookmark\]','[url$1]$2[/url]',$res['body']); + } @@ -1378,9 +1460,9 @@ function get_atom_elements($feed,$item) { $private = $item->get_item_tags(NAMESPACE_DFRN,'private'); if($private && intval($private[0]['data']) > 0) - $res['private'] = intval($private[0]['data']); + $res['item_private'] = ((intval($private[0]['data'])) ? 1 : 0); else - $res['private'] = 0; + $res['item_private'] = 0; $rawlocation = $item->get_item_tags(NAMESPACE_DFRN, 'location'); if($rawlocation) @@ -1417,23 +1499,29 @@ function get_atom_elements($feed,$item) { if($d2 > $d3) $res['edited'] = datetime_convert(); + $res['created'] = datetime_convert('UTC','UTC',$res['created']); + $res['edited'] = datetime_convert('UTC','UTC',$res['edited']); + $rawowner = $item->get_item_tags(NAMESPACE_DFRN, 'owner'); + if(! $rawowner) + $rawowner = $item->get_item_tags(NAMESPACE_ZOT,'owner'); + if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']) - $res['owner-name'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']); + $author['owner_name'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']); elseif($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']) - $res['owner-name'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']); + $author['owner_name'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']); if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']) - $res['owner-link'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']); + $author['owner_link'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']); elseif($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']) - $res['owner-link'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']); + $author['owner_link'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']); if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) { $base = $rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']; foreach($base as $link) { - if(!x($res, 'owner-avatar') || !$res['owner-avatar']) { + if(!x($author, 'owner_photo') || ! $author['owner_photo']) { if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') - $res['owner-avatar'] = unxmlify($link['attribs']['']['href']); + $author['owner_photo'] = unxmlify($link['attribs']['']['href']); } } } @@ -1470,12 +1558,12 @@ function get_atom_elements($feed,$item) { $termurl = unxmlify(substr($scheme,9)); } else { - $termtype = TERM_UNKNOWN; + $termtype = TERM_CATEGORY; } $termterm = notags(trim(unxmlify($term))); if($termterm) { - $terms = array( + $terms[] = array( 'otype' => TERM_OBJ_POST, 'type' => $termtype, 'url' => $termurl, @@ -1483,11 +1571,12 @@ function get_atom_elements($feed,$item) { ); } } - $res['term'] = implode(',', $tag_arr); + $res['term'] = $terms; } $attach = $item->get_enclosures(); if($attach) { + $res['attach'] = array(); $att_arr = array(); foreach($attach as $att) { $len = intval($att->get_length()); @@ -1503,33 +1592,32 @@ function get_atom_elements($feed,$item) { $title = ' '; if(! $type) $type = 'application/octet-stream'; - - $att_arr[] = '[attach]href="' . $link . '" length="' . $len . '" type="' . $type . '" title="' . $title . '"[/attach]'; + $res['attach'][] = array('href' => $link, 'length' => $len, 'type' => $type, 'title' => $title ); } - $res['attach'] = implode(',', $att_arr); } $rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'object'); if($rawobj) { - $res['object'] = '<object>' . "\n"; + $obj = array(); + $child = $rawobj[0]['child']; if($child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']) { $res['obj_type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']; - $res['object'] .= '<type>' . $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data'] . '</type>' . "\n"; + $obj['type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']; } if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data']) - $res['object'] .= '<id>' . $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'] . '</id>' . "\n"; + $obj['id'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data']; if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) - $res['object'] .= '<link>' . encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) . '</link>' . "\n"; + $obj['link'] = encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']); if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'title') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data']) - $res['object'] .= '<title>' . $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'] . '</title>' . "\n"; + $obj['title'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data']; if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'content') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']) { $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']; if(! $body) $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['summary'][0]['data']; // preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events - $res['object'] .= '<orig>' . xmlify($body) . '</orig>' . "\n"; + $obj['orig'] = xmlify($body); if((strpos($body,'<') !== false) || (strpos($body,'>') !== false)) { $body = purify_html($body); @@ -1537,74 +1625,55 @@ function get_atom_elements($feed,$item) { } - $res['object'] .= '<content>' . $body . '</content>' . "\n"; + $obj['content'] = $body; } - $res['object'] .= '</object>' . "\n"; + $res['object'] = $obj; } $rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'target'); if($rawobj) { - $res['target'] = '<target>' . "\n"; + $obj = array(); + $child = $rawobj[0]['child']; if($child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']) { - $res['target'] .= '<type>' . $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data'] . '</type>' . "\n"; + $res['tgt_type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']; + $obj['type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']; } if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data']) - $res['target'] .= '<id>' . $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'] . '</id>' . "\n"; + $obj['id'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data']; if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) - $res['target'] .= '<link>' . encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) . '</link>' . "\n"; - if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'data') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data']) - $res['target'] .= '<title>' . $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'] . '</title>' . "\n"; - if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'data') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']) { + $obj['link'] = encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']); + if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'title') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data']) + $obj['title'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data']; + if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'content') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']) { $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']; if(! $body) $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['summary'][0]['data']; // preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events - $res['target'] .= '<orig>' . xmlify($body) . '</orig>' . "\n"; + $obj['orig'] = xmlify($body); if((strpos($body,'<') !== false) || (strpos($body,'>') !== false)) { $body = purify_html($body); $body = html2bbcode($body); + } - $res['target'] .= '<content>' . $body . '</content>' . "\n"; + $obj['content'] = $body; } - $res['target'] .= '</target>' . "\n"; + $res['target'] = $obj; } - // This is some experimental stuff. By now retweets are shown with "RT:" - // But: There is data so that the message could be shown similar to native retweets - // There is some better way to parse this array - but it didn't worked for me. - - $child = $item->feed->data["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["feed"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["entry"][0]["child"]["http://activitystrea.ms/spec/1.0/"][object][0]["child"]; - if (is_array($child)) { - $message = $child["http://activitystrea.ms/spec/1.0/"]["object"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["content"][0]["data"]; - $author = $child[SIMPLEPIE_NAMESPACE_ATOM_10]["author"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]; - $uri = $author["uri"][0]["data"]; - $name = $author["name"][0]["data"]; - $avatar = @array_shift($author["link"][2]["attribs"]); - $avatar = $avatar["href"]; - - if (($name != "") and ($uri != "") and ($avatar != "") and ($message != "")) { - $res["owner-name"] = $res["author-name"]; - $res["owner-link"] = $res["author-link"]; - $res["owner-avatar"] = $res["author-avatar"]; - - $res["author-name"] = $name; - $res["author-link"] = $uri; - $res["author-avatar"] = $avatar; - - $res["body"] = html2bbcode($message); - } - } + $res['public_policy'] = 'specific'; + $res['comment_policy'] = 'none'; $arr = array('feed' => $feed, 'item' => $item, 'result' => $res); call_hooks('parse_atom', $arr); - logger('get_atom_elements: ' . print_r($res,true)); + logger('get_atom_elements: author: ' . print_r($author,true),LOGGER_DATA); + logger('get_atom_elements: ' . print_r($res,true),LOGGER_DATA); return $res; } @@ -1613,6 +1682,7 @@ function encode_rel_links($links) { $o = ''; if(! ((is_array($links)) && (count($links)))) return $o; + foreach($links as $link) { $o .= '<link '; if($link['attribs']['']['rel']) @@ -1643,7 +1713,7 @@ function item_store($arr,$allow_exec = false) { if(! $arr['uid']) { logger('item_store: no uid'); $ret['message'] = 'No uid.'; - return ret; + return $ret; } $uplinked_comment = false; @@ -1675,8 +1745,8 @@ function item_store($arr,$allow_exec = false) { } - $arr['title'] = ((x($arr,'title')) ? trim($arr['title']) : ''); - $arr['body'] = ((x($arr,'body')) ? trim($arr['body']) : ''); + $arr['title'] = ((array_key_exists('title',$arr) && strlen($arr['title'])) ? trim($arr['title']) : ''); + $arr['body'] = ((array_key_exists('body',$arr) && strlen($arr['body'])) ? trim($arr['body']) : ''); $arr['allow_cid'] = ((x($arr,'allow_cid')) ? trim($arr['allow_cid']) : ''); $arr['allow_gid'] = ((x($arr,'allow_gid')) ? trim($arr['allow_gid']) : ''); @@ -1751,6 +1821,8 @@ function item_store($arr,$allow_exec = false) { $arr['edited'] = ((x($arr,'edited') !== false) ? datetime_convert('UTC','UTC',$arr['edited']) : datetime_convert()); $arr['expires'] = ((x($arr,'expires') !== false) ? datetime_convert('UTC','UTC',$arr['expires']) : '0000-00-00 00:00:00'); $arr['commented'] = ((x($arr,'commented') !== false) ? datetime_convert('UTC','UTC',$arr['commented']) : datetime_convert()); + $arr['comments_closed'] = ((x($arr,'comments_closed') !== false) ? datetime_convert('UTC','UTC',$arr['comments_closed']) : '0000-00-00 00:00:00'); + $arr['received'] = datetime_convert(); $arr['changed'] = datetime_convert(); $arr['location'] = ((x($arr,'location')) ? notags(trim($arr['location'])) : ''); @@ -1770,7 +1842,6 @@ function item_store($arr,$allow_exec = false) { $arr['public_policy'] = ((x($arr,'public_policy')) ? notags(trim($arr['public_policy'])) : '' ); $arr['comment_policy'] = ((x($arr,'comment_policy')) ? notags(trim($arr['comment_policy'])) : 'contacts' ); - $arr['item_flags'] = $arr['item_flags'] | ITEM_UNSEEN; @@ -1802,6 +1873,7 @@ function item_store($arr,$allow_exec = false) { $deny_cid = $arr['deny_cid']; $deny_gid = $arr['deny_gid']; $public_policy = $arr['public_policy']; + $comments_closed = $arr['comments_closed']; $arr['item_flags'] = $arr['item_flags'] | ITEM_THREAD_TOP; } else { @@ -1816,6 +1888,12 @@ function item_store($arr,$allow_exec = false) { if($r) { + if(comments_are_now_closed($r[0])) { + logger('item_store: comments closed'); + $ret['message'] = 'Comments closed.'; + return $ret; + } + // is the new message multi-level threaded? // even though we don't support it now, preserve the info // and re-attach to the conversation parent. @@ -1832,13 +1910,14 @@ function item_store($arr,$allow_exec = false) { $r = $z; } - $parent_id = $r[0]['id']; - $parent_deleted = $r[0]['item_restrict'] & ITEM_DELETED; - $allow_cid = $r[0]['allow_cid']; - $allow_gid = $r[0]['allow_gid']; - $deny_cid = $r[0]['deny_cid']; - $deny_gid = $r[0]['deny_gid']; - $public_policy = $r[0]['public_policy']; + $parent_id = $r[0]['id']; + $parent_deleted = $r[0]['item_restrict'] & ITEM_DELETED; + $allow_cid = $r[0]['allow_cid']; + $allow_gid = $r[0]['allow_gid']; + $deny_cid = $r[0]['deny_cid']; + $deny_gid = $r[0]['deny_gid']; + $public_policy = $r[0]['public_policy']; + $comments_closed = $r[0]['comments_closed']; if($r[0]['item_flags'] & ITEM_WALL) $arr['item_flags'] = $arr['item_flags'] | ITEM_WALL; @@ -1952,7 +2031,8 @@ function item_store($arr,$allow_exec = false) { // Set parent id - and also make sure to inherit the parent's ACL's. $r = q("UPDATE item SET parent = %d, allow_cid = '%s', allow_gid = '%s', - deny_cid = '%s', deny_gid = '%s', public_policy = '%s', item_private = %d WHERE id = %d LIMIT 1", + deny_cid = '%s', deny_gid = '%s', public_policy = '%s', item_private = %d, comments_closed = '%s' + WHERE id = %d LIMIT 1", intval($parent_id), dbesc($allow_cid), dbesc($allow_gid), @@ -1960,6 +2040,7 @@ function item_store($arr,$allow_exec = false) { dbesc($deny_gid), dbesc($public_policy), intval($private), + dbesc($comments_closed), intval($current_post) ); @@ -1972,7 +2053,8 @@ function item_store($arr,$allow_exec = false) { $arr['deny_gid'] = $deny_gid; $arr['public_policy'] = $public_policy; $arr['item_private'] = $private; - + $arr['comments_closed'] = $comments_closed; + // Store taxonomy if(($terms) && (is_array($terms))) { @@ -1995,9 +2077,10 @@ function item_store($arr,$allow_exec = false) { // update the commented timestamp on the parent - $z = q("select max(created) as commented from item where parent_mid = '%s' and uid = %d ", + $z = q("select max(created) as commented from item where parent_mid = '%s' and uid = %d and not ( item_restrict & %d ) ", dbesc($arr['parent_mid']), - intval($arr['uid']) + intval($arr['uid']), + intval(ITEM_DELAYED_PUBLISH) ); q("UPDATE item set commented = '%s', changed = '%s' WHERE id = %d LIMIT 1", @@ -2144,10 +2227,15 @@ function item_store_update($arr,$allow_exec = false) { $arr['edited'] = ((x($arr,'edited') !== false) ? datetime_convert('UTC','UTC',$arr['edited']) : datetime_convert()); $arr['expires'] = ((x($arr,'expires') !== false) ? datetime_convert('UTC','UTC',$arr['expires']) : $orig[0]['expires']); + + if(array_key_exists('comments_closed',$arr) && $arr['comments_closed'] != '0000-00-00 00:00:00') + $arr['comments_closed'] = datetime_convert('UTC','UTC',$arr['comments_closed']); + else + $arr['comments_closed'] = $orig[0]['comments_closed']; + $arr['commented'] = $orig[0]['commented']; $arr['received'] = datetime_convert(); $arr['changed'] = datetime_convert(); - $arr['title'] = ((x($arr,'title')) ? notags(trim($arr['title'])) : ''); $arr['location'] = ((x($arr,'location')) ? notags(trim($arr['location'])) : $orig[0]['location']); $arr['coord'] = ((x($arr,'coord')) ? notags(trim($arr['coord'])) : $orig[0]['coord']); $arr['verb'] = ((x($arr,'verb')) ? notags(trim($arr['verb'])) : $orig[0]['verb']); @@ -2163,7 +2251,8 @@ function item_store_update($arr,$allow_exec = false) { $arr['deny_gid'] = ((array_key_exists('deny_gid',$arr)) ? trim($arr['deny_gid']) : $orig[0]['deny_gid']); $arr['item_private'] = ((array_key_exists('item_private',$arr)) ? intval($arr['item_private']) : $orig[0]['item_private']); - $arr['body'] = ((x($arr,'body')) ? trim($arr['body']) : ''); + $arr['title'] = ((array_key_exists('title',$arr) && strlen($arr['title'])) ? trim($arr['title']) : ''); + $arr['body'] = ((array_key_exists('body',$arr) && strlen($arr['body'])) ? trim($arr['body']) : ''); $arr['attach'] = ((x($arr,'attach')) ? notags(trim($arr['attach'])) : $orig[0]['attach']); $arr['app'] = ((x($arr,'app')) ? notags(trim($arr['app'])) : $orig[0]['app']); // $arr['item_restrict'] = ((x($arr,'item_restrict')) ? intval($arr['item_restrict']) : $orig[0]['item_restrict'] ); @@ -2246,6 +2335,52 @@ function item_store_update($arr,$allow_exec = false) { return $ret; } +function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id) { + + // We won't be able to sign Diaspora comments for authenticated visitors + // - we don't have their private key + + // since Diaspora doesn't handle edits we can only do this for the original text and not update it. + + $enabled = intval(get_config('system','diaspora_enabled')); + if(! $enabled) { + logger('mod_item: diaspora support disabled, not storing comment signature', LOGGER_DEBUG); + return; + } + + $body = $datarray['body']; + if(array_key_exists('item_flags',$datarray) && ($datarray['item_flags'] & ITEM_OBSCURED)) { + $key = get_config('system','prvkey'); + if($datarray['body']) + $body = crypto_unencapsulate(json_decode($datarray['body'],true),$key); + } + + logger('mod_item: storing diaspora comment signature',LOGGER_DEBUG); + + require_once('include/bb2diaspora.php'); + + $signed_body = html_entity_decode(bb2diaspora($body)); + + $diaspora_handle = $channel['channel_address'] . '@' . get_app()->get_hostname(); + + $signed_text = $datarray['mid'] . ';' . $parent_item['mid'] . ';' . $signed_body . ';' . $diaspora_handle; + + if( $uprvkey !== false ) + $authorsig = base64_encode(rsa_sign($signed_text,$channel['channel_prvkey'],'sha256')); + else + $authorsig = ''; + + $r = q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", + intval($post_id), + dbesc($signed_text), + dbesc(base64_encode($authorsig)), + dbesc($diaspora_handle) + ); + if(! $r) + logger('store_diaspora_comment_sig: DB write failed'); + + return; +} @@ -2342,6 +2477,10 @@ function tag_deliver($uid,$item_id) { $mention = false; + /** + * Fetch stuff we need - a channel and an item + */ + $u = q("select * from channel where channel_id = %d limit 1", intval($uid) ); @@ -2359,14 +2498,19 @@ function tag_deliver($uid,$item_id) { $item = $i[0]; - if(($item['source_xchan']) && ($item['item_flags'] & ITEM_UPLINK) && ($item['item_flags'] & ITEM_THREAD_TOP) && ($item['edited'] != $item['created'])) { - // this is an update to a post which was already processed by us and has a second delivery chain + if(($item['source_xchan']) && ($item['item_flags'] & ITEM_UPLINK) + && ($item['item_flags'] & ITEM_THREAD_TOP) && ($item['edited'] != $item['created'])) { + // this is an update (edit) to a post which was already processed by us and has a second delivery chain // Just start the second delivery chain to deliver the updated post proc_run('php','include/notifier.php','tgroup',$item['id']); return; } + /** + * Seems like a good place to plug in a poke notification. + */ + if (stristr($item['verb'],ACTIVITY_POKE)) { $poke_notify = true; @@ -2395,6 +2539,10 @@ function tag_deliver($uid,$item_id) { } } + /** + * Do community tagging + */ + if($item['obj_type'] === ACTIVITY_OBJ_TAGTERM) { // We received a community tag activity for a post. @@ -2435,6 +2583,11 @@ function tag_deliver($uid,$item_id) { logger('tag_deliver: tag permission denied for ' . $u[0]['channel_address']); } + /** + * A "union" is a message which our channel has sourced from another channel. + * This sets up a second delivery chain just like forum tags do. + * Find out if this is a source-able post. + */ $union = check_item_source($uid,$item); if($union) @@ -2444,53 +2597,22 @@ function tag_deliver($uid,$item_id) { // This might be a followup (e.g. comment) by the original post author to a tagged forum // If so setup a second delivery chain - $r = null; - if( ! ($item['item_flags'] & ITEM_THREAD_TOP)) { $x = q("select * from item where id = parent and parent = %d and uid = %d limit 1", intval($item['parent']), intval($uid) ); - if(($x) && ($x[0]['item_flags'] & ITEM_UPLINK)) { + start_delivery_chain($u[0],$item,$item_id,$x[0]); + } + } - logger('tag_deliver: creating second delivery chain for comment to tagged post.'); - - // now change this copy of the post to a forum head message and deliver to all the tgroup members - // also reset all the privacy bits to the forum default permissions - - $private = (($u[0]['channel_allow_cid'] || $u[0]['channel_allow_gid'] || $u[0]['channel_deny_cid'] || $u[0]['channel_deny_gid']) ? 1 : 0); - -//FIXME - add check for public_policy - - $flag_bits = ITEM_WALL|ITEM_ORIGIN; - - // maintain the original source, which will be the original item owner and was stored in source_xchan - // when we created the delivery fork - $r = q("update item set source_xchan = '%s' where id = %d limit 1", - dbesc($x[0]['source_xchan']), - intval($item_id) - ); + /** + * Now we've got those out of the way. Let's see if this is a post that's tagged for re-delivery + */ - $r = q("update item set item_flags = ( item_flags | %d ), owner_xchan = '%s', allow_cid = '%s', allow_gid = '%s', - deny_cid = '%s', deny_gid = '%s', item_private = %d where id = %d limit 1", - intval($flag_bits), - dbesc($u[0]['channel_hash']), - dbesc($u[0]['channel_allow_cid']), - dbesc($u[0]['channel_allow_gid']), - dbesc($u[0]['channel_deny_cid']), - dbesc($u[0]['channel_deny_gid']), - intval($private), - intval($item_id) - ); - if($r) - proc_run('php','include/notifier.php','tgroup',$item_id); - else - logger('tag_deliver: failed to update item'); - } - } $terms = get_terms_oftype($item['term'],TERM_MENTION); @@ -2516,8 +2638,6 @@ function tag_deliver($uid,$item_id) { intval($item_id) ); - - // At this point we've determined that the person receiving this post was mentioned in it or it is a union. // Now let's check if this mention was inside a reshare so we don't spam a forum // If it's private we may have to unobscure it momentarily so that we can parse it. @@ -2553,7 +2673,9 @@ function tag_deliver($uid,$item_id) { $arr = array('channel_id' => $uid, 'item' => $item, 'body' => $body); call_hooks('tagged',$arr); - // Valid tag. Send a notification + /** + * Kill two birds with one stone. As long as we're here, send a mention notification. + */ require_once('include/enotify.php'); notification(array( @@ -2587,51 +2709,33 @@ function tag_deliver($uid,$item_id) { return; } - // tgroup delivery - setup a second delivery chain // prevent delivery looping - only proceed // if the message originated elsewhere and is a top-level post - if(($item['item_flags'] & ITEM_WALL) || ($item['item_flags'] & ITEM_ORIGIN) || (!($item['item_flags'] & ITEM_THREAD_TOP)) || ($item['id'] != $item['parent'])) { + if(($item['item_flags'] & ITEM_WALL) + || ($item['item_flags'] & ITEM_ORIGIN) + || (!($item['item_flags'] & ITEM_THREAD_TOP)) + || ($item['id'] != $item['parent'])) { logger('tag_deliver: item was local or a comment. rejected.'); return; } logger('tag_deliver: creating second delivery chain.'); - - // now change this copy of the post to a forum head message and deliver to all the tgroup members - // also reset all the privacy bits to the forum default permissions - - $private = (($u[0]['channel_allow_cid'] || $u[0]['channel_allow_gid'] || $u[0]['channel_deny_cid'] || $u[0]['channel_deny_gid']) ? 1 : 0); - -// FIXME set public_policy and recheck private - - $flag_bits = ITEM_WALL|ITEM_ORIGIN|ITEM_UPLINK; - - // preserve the source - - $r = q("update item set source_xchan = owner_xchan where id = %d limit 1", - intval($item_id) - ); - - $r = q("update item set item_flags = ( item_flags | %d ), owner_xchan = '%s', allow_cid = '%s', allow_gid = '%s', - deny_cid = '%s', deny_gid = '%s', item_private = %d where id = %d limit 1", - intval($flag_bits), - dbesc($u[0]['channel_hash']), - dbesc($u[0]['channel_allow_cid']), - dbesc($u[0]['channel_allow_gid']), - dbesc($u[0]['channel_deny_cid']), - dbesc($u[0]['channel_deny_gid']), - intval($private), - intval($item_id) - ); - if($r) - proc_run('php','include/notifier.php','tgroup',$item_id); - else - logger('tag_deliver: failed to update item'); + start_delivery_chain($u[0],$item,$item_id,null); } +/** + * @function tgroup_check($uid,$item) + * + * This function is called pre-deliver to see if a post matches the criteria to be tag delivered. + * We don't actually do anything except check that it matches the criteria. + * This is so that the channel with tag_delivery enabled can receive the post even if they turn off + * permissions for the sender to send their stream. tag_deliver() can't be called until the post is actually stored. + * By then it would be too late to reject it. + */ + function tgroup_check($uid,$item) { @@ -2702,6 +2806,95 @@ function tgroup_check($uid,$item) { } +/** + * Sourced and tag-delivered posts are re-targetted for delivery to the connections of the channel + * receiving the post. This starts the second delivery chain, by resetting permissions and ensuring + * that ITEM_UPLINK is set on the parent post, and storing the current owner_xchan as the source_xchan. + * We'll become the new owner. If called without $parent, this *is* the parent post. + */ + +function start_delivery_chain($channel,$item,$item_id,$parent) { + + + + // Change this copy of the post to a forum head message and deliver to all the tgroup members + // also reset all the privacy bits to the forum default permissions + + $private = (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] + || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 1 : 0); + + $new_public_policy = map_scope($channel['channel_r_stream'],true); + + if((! $private) && $new_public_policy) + $private = 1; + + $flag_bits = $item['item_flags'] | ITEM_WALL|ITEM_ORIGIN; + + // maintain the original source, which will be the original item owner and was stored in source_xchan + // when we created the delivery fork + + if($parent) { + $r = q("update item set source_xchan = '%s' where id = %d limit 1", + dbesc($parent['source_xchan']), + intval($item_id) + ); + } + else { + $flag_bits = $flag_bits | ITEM_UPLINK; + $r = q("update item set source_xchan = owner_xchan where id = %d limit 1", + intval($item_id) + ); + } + + $title = $item['title']; + $body = $item['body']; + + if($private) { + if(!($flag_bits & ITEM_OBSCURED)) { + $key = get_config('system','pubkey'); + $flag_bits = $flag_bits|ITEM_OBSCURED; + if($title) + $title = json_encode(crypto_encapsulate($title,$key)); + if($body) + $body = json_encode(crypto_encapsulate($body,$key)); + } + } + else { + if($flag_bits & ITEM_OBSCURED) { + $key = get_config('system','prvkey'); + $flag_bits = $flag_bits ^ ITEM_OBSCURED; + if($title) + $title = crypto_unencapsulate(json_decode($title,true),$key); + if($body) + $body = crypto_unencapsulate(json_decode($body,true),$key); + } + } + + $r = q("update item set item_flags = %d, owner_xchan = '%s', allow_cid = '%s', allow_gid = '%s', + deny_cid = '%s', deny_gid = '%s', item_private = %d, public_policy = '%s', comment_policy = '%s', title = '%s', body = '%s' where id = %d limit 1", + intval($flag_bits), + dbesc($channel['channel_hash']), + dbesc($channel['channel_allow_cid']), + dbesc($channel['channel_allow_gid']), + dbesc($channel['channel_deny_cid']), + dbesc($channel['channel_deny_gid']), + intval($private), + dbesc($new_public_policy), + dbesc(map_scope($channel['channel_w_comment'])), + dbesc($title), + dbesc($body), + intval($item_id) + ); + + if($r) + proc_run('php','include/notifier.php','tgroup',$item_id); + else + logger('start_delivery_chain: failed to update item'); + + return; +} + + /** * @function check_item_source($uid,$item) @@ -2899,7 +3092,7 @@ function mail_store($arr) { * recursion. */ -function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) { +function consume_feed($xml,$importer,&$contact,$pass = 0) { require_once('library/simplepie/simplepie.inc'); @@ -2908,15 +3101,8 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) return; } - // Want to see this work as a content source for the matrix? - // Read this: https://github.com/friendica/red/wiki/Service_Federation - $feed = new SimplePie(); $feed->set_raw_data($xml); - if($datedir) - $feed->enable_order_by_date(true); - else - $feed->enable_order_by_date(false); $feed->init(); if($feed->error()) @@ -2926,7 +3112,6 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) // Check at the feed level for updated contact name and/or photo - // process any deleted entries $del_entries = $feed->get_feed_tags(NAMESPACE_TOMB, 'deleted-entry'); @@ -2943,41 +3128,21 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) else $when = datetime_convert('UTC','UTC','now','Y-m-d H:i:s'); } + + if($deleted && is_array($contact)) { -/* $r = q("SELECT `item`.*, `contact`.`self` FROM `item` left join `contact` on `item`.`contact-id` = `contact`.`id` - WHERE `mid` = '%s' AND `item`.`uid` = %d AND `contact-id` = %d AND NOT `item`.`file` LIKE '%%[%%' LIMIT 1", + $r = q("SELECT * from item where mid = '%s' and author_xchan = '%s' and uid = %d limit 1", dbesc($mid), - intval($importer['channel_id']), - intval($contact['id']) + dbesc($contact['xchan_hash']), + intval($importer['channel_id']) ); -*/ - if(count($r)) { + + if($r) { $item = $r[0]; - if(! $item['deleted']) + if(! ($item['item_restrict'] & ITEM_DELETED)) { logger('consume_feed: deleting item ' . $item['id'] . ' mid=' . $item['mid'], LOGGER_DEBUG); - - if($item['mid'] == $item['parent_mid']) { - $r = q("UPDATE `item` SET item_restrict = (item_restrict | %d), `edited` = '%s', `changed` = '%s', - `body` = '', `title` = '' - WHERE `parent_mid` = '%s' AND `uid` = %d", - intval(ITEM_DELETED), - dbesc($when), - dbesc(datetime_convert()), - dbesc($item['mid']), - intval($importer['channel_id']) - ); - } - else { - $r = q("UPDATE `item` SET item_restrict = ( item_restrict | %d ), `edited` = '%s', `changed` = '%s', - `body` = '', `title` = '' - WHERE `mid` = '%s' AND `uid` = %d LIMIT 1", - intval(ITEM_DELETED), - dbesc($when), - dbesc(datetime_convert()), - dbesc($mid), - intval($importer['channel_id']) - ); + drop_item($item['id'],false); } } } @@ -2988,21 +3153,16 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0) if($feed->get_item_quantity()) { - logger('consume_feed: feed item count = ' . $feed->get_item_quantity()); - - // in inverse date order - if ($datedir) - $items = array_reverse($feed->get_items()); - else - $items = $feed->get_items(); + logger('consume_feed: feed item count = ' . $feed->get_item_quantity(), LOGGER_DEBUG); + $items = $feed->get_items(); foreach($items as $item) { $is_reply = false; $item_id = $item->get_id(); -logger('consume_feed: processing ' . $item_id); + logger('consume_feed: processing ' . $item_id, LOGGER_DEBUG); $rawthread = $item->get_item_tags( NAMESPACE_THREAD,'in-reply-to'); if(isset($rawthread[0]['attribs']['']['ref'])) { @@ -3019,22 +3179,17 @@ logger('consume_feed: processing ' . $item_id); // Have we seen it? If not, import it. $item_id = $item->get_id(); - $datarray = get_atom_elements($feed,$item); - - if((! x($datarray,'author-name')) && ($contact['network'] != NETWORK_DFRN)) - $datarray['author-name'] = $contact['name']; - if((! x($datarray,'author-link')) && ($contact['network'] != NETWORK_DFRN)) - $datarray['author-link'] = $contact['url']; - if((! x($datarray,'author-avatar')) && ($contact['network'] != NETWORK_DFRN)) - $datarray['author-avatar'] = $contact['thumb']; - - if((! x($datarray,'author-name')) || (! x($datarray,'author-link'))) { - logger('consume_feed: no author information! ' . print_r($datarray,true)); - continue; - } + $author = array(); + $datarray = get_atom_elements($feed,$item,$author); + if(! x($author,'author_name')) + $author['author_name'] = $contact['xchan_name']; + if(! x($author,'author_link')) + $author['author_link'] = $contact['xchan_url']; + if(! x($author,'author_photo')) + $author['author_photo'] = $contact['xchan_photo_m']; - $r = q("SELECT `uid`, `edited`, `body` FROM `item` WHERE `mid` = '%s' AND `uid` = %d LIMIT 1", + $r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1", dbesc($item_id), intval($importer['channel_id']) ); @@ -3042,71 +3197,30 @@ logger('consume_feed: processing ' . $item_id); // Update content if 'updated' changes if($r) { - 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; - $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `edited` = '%s' WHERE `mid` = '%s' AND `uid` = %d LIMIT 1", - dbesc($datarray['title']), - dbesc($datarray['body']), - dbesc(datetime_convert('UTC','UTC',$datarray['edited'])), - dbesc($item_id), - intval($importer['channel_id']) - ); + update_feed_item($importer['channel_id'],$datarray); } - continue; } - $datarray['parent_mid'] = $parent_mid; $datarray['uid'] = $importer['channel_id']; - $datarray['contact-id'] = $contact['id']; - if((activity_match($datarray['verb'],ACTIVITY_LIKE)) || (activity_match($datarray['verb'],ACTIVITY_DISLIKE))) { - $datarray['type'] = 'activity'; - $datarray['gravity'] = GRAVITY_LIKE; - // only one like or dislike per person - $r = q("select id from item where uid = %d and `contact-id` = %d and verb ='%s' and deleted = 0 and (`parent_mid` = '%s' OR `thr_parent` = '%s') limit 1", - intval($datarray['uid']), - intval($datarray['contact-id']), - dbesc($datarray['verb']), - dbesc($parent_mid), - dbesc($parent_mid) - ); - if($r && count($r)) - continue; - } - if(($datarray['verb'] === ACTIVITY_TAG) && ($datarray['obj_type'] === ACTIVITY_OBJ_TAGTERM)) { - $xo = parse_xml_string($datarray['object'],false); - $xt = parse_xml_string($datarray['target'],false); +//FIXME + $datarray['owner_xchan'] = $datarray['author_xchan'] = $contact['xchan_hash']; - if($xt->type == ACTIVITY_OBJ_NOTE) { - $r = q("select * from item where `mid` = '%s' AND `uid` = %d limit 1", - dbesc($xt->id), - intval($importer['channel_id']) - ); - if(! count($r)) - continue; + // FIXME pull out the author and owner - // extract tag, if not duplicate, add to parent item - if($xo->id && $xo->content) { - $newtag = '#[zrl=' . $xo->id . ']'. $xo->content . '[/zrl]'; - if(! (stristr($r[0]['tag'],$newtag))) { - q("UPDATE item SET tag = '%s' WHERE id = %d LIMIT 1", - dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . $newtag), - intval($r[0]['id']) - ); - } - } - } - } -logger('consume_feed: ' . print_r($datarray,true)); + logger('consume_feed: ' . print_r($datarray,true),LOGGER_DATA); -// $xx = item_store($datarray); + $xx = item_store($datarray); $r = $xx['item_id']; continue; } @@ -3116,47 +3230,25 @@ logger('consume_feed: ' . print_r($datarray,true)); // Head post of a conversation. Have we seen it? If not, import it. $item_id = $item->get_id(); - - $datarray = get_atom_elements($feed,$item); + $author = array(); + $datarray = get_atom_elements($feed,$item,$author); if(is_array($contact)) { - if((! x($datarray,'author-name')) && ($contact['network'] != NETWORK_DFRN)) - $datarray['author-name'] = $contact['name']; - if((! x($datarray,'author-link')) && ($contact['network'] != NETWORK_DFRN)) - $datarray['author-link'] = $contact['url']; - if((! x($datarray,'author-avatar')) && ($contact['network'] != NETWORK_DFRN)) - $datarray['author-avatar'] = $contact['thumb']; + if(! x($author,'author_name')) + $author['author_name'] = $contact['xchan_name']; + if(! x($author,'author_link')) + $author['author_link'] = $contact['xchan_url']; + if(! x($author,'author_photo')) + $author['author_photo'] = $contact['xchan_photo_m']; } - if((! x($datarray,'author-name')) || (! x($datarray,'author-link'))) { - logger('consume_feed: no author information! ' . print_r($datarray,true)); + if((! x($author,'author_name')) || (! x($author,'author_link'))) { + logger('consume_feed: no author information! ' . print_r($author,true)); continue; } - // special handling for events - - if((x($datarray,'obj_type')) && ($datarray['obj_type'] === ACTIVITY_OBJ_EVENT)) { - $ev = bbtoevent($datarray['body']); - if(x($ev,'desc') && x($ev,'start')) { - $ev['uid'] = $importer['channel_id']; - $ev['mid'] = $item_id; - $ev['edited'] = $datarray['edited']; - $ev['private'] = $datarray['private']; - - if(is_array($contact)) - $ev['cid'] = $contact['id']; - $r = q("SELECT * FROM `event` WHERE `mid` = '%s' AND `uid` = %d LIMIT 1", - dbesc($item_id), - intval($importer['channel_id']) - ); - if(count($r)) - $ev['id'] = $r[0]['id']; -// $xyz = event_store($ev); - continue; - } - } - $r = q("SELECT `uid`, `edited`, `body` FROM `item` WHERE `mid` = '%s' AND `uid` = %d LIMIT 1", + $r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1", dbesc($item_id), intval($importer['channel_id']) ); @@ -3164,81 +3256,38 @@ logger('consume_feed: ' . print_r($datarray,true)); // Update content if 'updated' changes if($r) { - 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; - $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `edited` = '%s' WHERE `mid` = '%s' AND `uid` = %d LIMIT 1", - dbesc($datarray['title']), - dbesc($datarray['body']), - dbesc(datetime_convert('UTC','UTC',$datarray['edited'])), - dbesc($item_id), - intval($importer['channel_id']) - ); + update_feed_item($importer['channel_id'],$datarray); } continue; } - if(activity_match($datarray['verb'],ACTIVITY_FOLLOW)) { - logger('consume-feed: New follower'); - new_follower($importer,$contact,$datarray,$item); - return; - } - if(activity_match($datarray['verb'],ACTIVITY_UNFOLLOW)) { - lose_follower($importer,$contact,$datarray,$item); - return; - } - - if(activity_match($datarray['verb'],ACTIVITY_REQ_FRIEND)) { - logger('consume-feed: New friend request'); - new_follower($importer,$contact,$datarray,$item,true); - return; - } - if(activity_match($datarray['verb'],ACTIVITY_UNFRIEND)) { - lose_sharer($importer,$contact,$datarray,$item); - return; - } - - -// if(! is_array($contact)) -// return; - - - // This is my contact on another system, but it's really me. - // Turn this into a wall post. - - if($contact['remote_self']) { - $datarray['wall'] = 1; - } $datarray['parent_mid'] = $item_id; $datarray['uid'] = $importer['channel_id']; - $datarray['contact-id'] = $contact['id']; - - if(! link_compare($datarray['owner-link'],$contact['url'])) { - // The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery, - // but otherwise there's a possible data mixup on the sender's system. - // the tgroup delivery code called from item_store will correct it if it's a forum, - // but we're going to unconditionally correct it here so that the post will always be owned by our contact. +//FIXME + $datarray['owner_xchan'] = $datarray['author_xchan'] = $contact['xchan_hash']; + + if(! link_compare($author['owner_link'],$contact['xchan_url'])) { logger('consume_feed: Correcting item owner.', LOGGER_DEBUG); - $datarray['owner-name'] = $contact['name']; - $datarray['owner-link'] = $contact['url']; - $datarray['owner-avatar'] = $contact['thumb']; + $author['owner_name'] = $contact['name']; + $author['owner_link'] = $contact['url']; + $author['owner_avatar'] = $contact['thumb']; } - // We've allowed "followers" to reach this point so we can decide if they are - // posting an @-tag delivery, which followers are allowed to do for certain - // page types. Now that we've parsed the post, let's check if it is legit. Otherwise ignore it. + logger('consume_feed: author ' . print_r($author,true)); - if(($contact['rel'] == CONTACT_IS_FOLLOWER) && (! tgroup_check($importer['channel_id'],$datarray))) - continue; -logger('consume_feed: ' . print_r($datarray,true)); + logger('consume_feed: ' . print_r($datarray,true),LOGGER_DATA); -// $xx = item_store($datarray); + $xx = item_store($datarray); $r = $xx['item_id']; continue; @@ -3249,6 +3298,35 @@ logger('consume_feed: ' . print_r($datarray,true)); } +function update_feed_item($uid,$datarray) { + + logger('update_feed_item: ' . $uid . ' ' . print_r($datarray,true), LOGGER_DATA); + + +} + + +function handle_feed($uid,$abook_id,$url) { + + require_once('include/Contact.php'); + $channel = channelx_by_n($uid); + if(! $channel) + return; + $x = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d limit 1", + dbesc($abook_id), + intval($uid) + ); + + $recurse = 0; + $z = z_fetch_url($url,false,$recurse,array('novalidate' => true)); + +//logger('handle_feed:' . print_r($z,true)); + + if($z['success']) { + consume_feed($z['body'],$channel,$x[0],0); + consume_feed($z['body'],$channel,$x[0],1); + } +} function atom_author($tag,$name,$uri,$h,$w,$type,$photo) { @@ -3978,7 +4056,7 @@ function zot_feed($uid,$observer_xchan,$mindate) { } if($mindate != '0000-00-00 00:00:00') { - $sql_extra .= " and created > '$mindate' "; + $sql_extra .= " and ( created > '$mindate' or edited > '$mindate' ) "; $limit = ""; } else @@ -4262,6 +4340,9 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $parents_str = ids_to_querystr($r,'item_id'); + if($arr['top']) + $sql_extra = ' and id = parent ' . $sql_extra; + $items = q("SELECT item.*, item.id AS item_id FROM item WHERE $item_uids $item_restrict AND item.parent IN ( %s ) |