diff options
Diffstat (limited to 'include/items.php')
-rwxr-xr-x | include/items.php | 1180 |
1 files changed, 633 insertions, 547 deletions
diff --git a/include/items.php b/include/items.php index 4608d5d55..1eb1a6446 100755 --- a/include/items.php +++ b/include/items.php @@ -1,4 +1,10 @@ -<?php /** @file */ +<?php +/** + * @file include/items.php + */ + +/** @todo deprecated in newer SabreDAV releases Sabre\HTTP\URLUtil */ +use Sabre\DAV\URLUtil; require_once('include/bbcode.php'); require_once('include/oembed.php'); @@ -6,8 +12,14 @@ require_once('include/crypto.php'); require_once('include/photo/photo_driver.php'); require_once('include/permissions.php'); - -function collect_recipients($item,&$private_envelope) { +/** + * @brief Collects recipients. + * + * @param array $item + * @param[out] boolean $private_envelope + * @return array containing the recipients + */ +function collect_recipients($item, &$private_envelope) { require_once('include/group.php'); @@ -25,9 +37,9 @@ function collect_recipients($item,&$private_envelope) { $recipients = array_unique(array_merge($allow_people,$allow_groups)); - // if you specifically deny somebody but haven't allowed anybody, we'll allow everybody in your + // if you specifically deny somebody but haven't allowed anybody, we'll allow everybody in your // address book minus the denied connections. The post is still private and can't be seen publicly - // as that would allow the denied person to see the post by logging out. + // as that would allow the denied person to see the post by logging out. if((! $item['allow_cid']) && (! $item['allow_gid'])) { $r = q("select * from abook where abook_channel = %d and not (abook_flags & %d)>0 ", @@ -57,17 +69,17 @@ function collect_recipients($item,&$private_envelope) { } else { - // if the post is marked private but there are no recipients and public_policy/scope = self, + // if the post is marked private but there are no recipients and public_policy/scope = self, // only add the author and owner as recipients. The ACL for the post may live on the hub of // a different clone. We need to get the post to that hub. // The post may be private by virtue of not being visible to anybody on the internet, - // but there are no envelope recipients, so set this to false. Delivery is controlled + // but there are no envelope recipients, so set this to false. Delivery is controlled // by the directives in $item['public_policy']. $private_envelope = false; require_once('include/identity.php'); - $sys = get_sys_channel(); + //$sys = get_sys_channel(); if(array_key_exists('public_policy',$item) && $item['public_policy'] !== 'self') { $r = q("select abook_xchan, xchan_network from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and not (abook_flags & %d)>0 ", @@ -84,7 +96,7 @@ function collect_recipients($item,&$private_envelope) { switch($policy) { case 'net': case 'aut': - case 'sit': + case 'sit': case 'any': case 'con': if($rr['xchan_network'] != 'zot') @@ -103,17 +115,16 @@ function collect_recipients($item,&$private_envelope) { } } - // This is a somewhat expensive operation but important. // Don't send this item to anybody who isn't allowed to see it $recipients = check_list_permissions($item['uid'],$recipients,'view_stream'); - // remove any upstream recipients from our list. + // remove any upstream recipients from our list. // If it is ourself we'll add it back in a second. - // This should prevent complex delivery chains from getting overly complex by not + // This should prevent complex delivery chains from getting overly complex by not // sending to anybody who is on our list of those who sent it to us. - + if($item['route']) { $route = explode(',',$item['route']); if(count($route)) { @@ -123,13 +134,12 @@ function collect_recipients($item,&$private_envelope) { } // add ourself just in case we have nomadic clones that need to get a copy. - + $recipients[] = $item['author_xchan']; if($item['owner_xchan'] != $item['author_xchan']) $recipients[] = $item['owner_xchan']; return $recipients; - } /** @@ -139,30 +149,35 @@ function collect_recipients($item,&$private_envelope) { * 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. + * Update: this may need to be the default, which will force people to opt-in to + * sending stuff privately to insecure platforms. + * + * @param int $channel_id + * @param array $arr + * @return array containing the sane xchan_hashes */ - -function filter_insecure($channel_id,$arr) { +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)) + 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 "); + $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; } @@ -173,30 +188,33 @@ function comments_are_now_closed($item) { if($d > $item['comments_closed']) return true; } + return false; } /** - * @function can_comment_on_post($observer_xchan,$item); + * @brief * * This function examines the comment_policy attached to an item and decides if the current observer has * sufficient privileges to comment. This will normally be called on a remote site where perm_is_allowed() * will not be suitable because the post owner does not have a local channel_id. * 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 + * 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. + * We also check the comments_closed date/time on the item if this is set. + * + * @param string $observer_xchan + * @param array $item + * @return boolean */ - -function can_comment_on_post($observer_xchan,$item) { +function can_comment_on_post($observer_xchan, $item) { // logger('can_comment_on_post: comment_policy: ' . $item['comment_policy'], LOGGER_DEBUG); if(! $observer_xchan) return false; - if($item['comment_policy'] === 'none') return false; @@ -205,15 +223,16 @@ function can_comment_on_post($observer_xchan,$item) { if($observer_xchan === $item['author_xchan'] || $observer_xchan === $item['owner_xchan']) return true; + switch($item['comment_policy']) { case 'self': if($observer_xchan === $item['author_xchan'] || $observer_xchan === $item['owner_xchan']) return true; break; case 'public': - // We don't allow public comments yet, until a policy - // for dealing with anonymous comments is in place with - // a means to moderate comments. Until that time, return + // We don't allow public comments yet, until a policy + // for dealing with anonymous comments is in place with + // a means to moderate comments. Until that time, return // false. return false; break; @@ -233,36 +252,36 @@ function can_comment_on_post($observer_xchan,$item) { return true; if(strstr($item['comment_policy'],'site:') && strstr($item['comment_policy'],get_app()->get_hostname())) return true; - + return false; } /** - * @function add_source_route($iid,$hash) - * Adds $hash to the item source route specified by $iid - * @param integer $iid - * item['id'] of target item - * @param string $hash - * xchan_hash of the channel that sent the item - * Modifies item pointed to by $iid + * @brief Adds $hash to the item source route specified by $iid. * - * $item['route'] contains a comma-separated list of xchans that sent the current message, + * $item['route'] contains a comma-separated list of xchans that sent the current message, * somewhat analogous to the * Received: header line in email. We can use this to perform - * loop detection and to avoid sending a particular item to any "upstream" sender (they - * already have a copy because they sent it to us). + * loop detection and to avoid sending a particular item to any "upstream" sender (they + * already have a copy because they sent it to us). + * + * Modifies item in the database pointed to by $iid. * + * @param integer $iid + * item['id'] of target item + * @param string $hash + * xchan_hash of the channel that sent the item */ - -function add_source_route($iid,$hash) { +function add_source_route($iid, $hash) { // logger('add_source_route ' . $iid . ' ' . $hash, LOGGER_DEBUG); if((! $iid) || (! $hash)) return; + $r = q("select route from item where id = %d limit 1", intval($iid) ); if($r) { - $new_route = (($r[0]['route']) ? $r[0]['route'] . ',' : '') . $hash; + $new_route = (($r[0]['route']) ? $r[0]['route'] . ',' : '') . $hash; q("update item set route = '%s' where id = %d", (dbesc($new_route)), intval($iid) @@ -271,17 +290,17 @@ function add_source_route($iid,$hash) { } - /** - * @function red_zrl_callback - * preg_match function when fixing 'naked' links in mod item.php - * Check if we've got a hubloc for the site and use a zrl if we do, a url if we don't. - * Remove any existing zid= param which may have been pasted by mistake - and will have - * the author's credentials. zid's are dynamic and can't really be passed around like - * that. + * @brief preg_match function when fixing 'naked' links in mod item.php. + * + * Check if we've got a hubloc for the site and use a zrl if we do, a url if we don't. + * Remove any existing zid= param which may have been pasted by mistake - and will have + * the author's credentials. zid's are dynamic and can't really be passed around like + * that. + * + * @param array $matches + * @return string */ - - function red_zrl_callback($matches) { require_once('include/hubloc.php'); $zrl = is_matrix_url($matches[2]); @@ -296,19 +315,24 @@ function red_zrl_callback($matches) { $matches[1] = ''; if($zrl) return $matches[1] . '#^[zrl=' . $matches[2] . ']' . $matches[2] . '[/zrl]'; + return $matches[1] . '#^[url=' . $matches[2] . ']' . $matches[2] . '[/url]'; } - -// If we've got a url or zrl tag with a naked url somewhere in the link text, -// escape it with quotes unless the naked url is a linked photo. - +/** + * If we've got a url or zrl tag with a naked url somewhere in the link text, + * escape it with quotes unless the naked url is a linked photo. + * + * @param array $matches + * @return string + */ function red_escape_zrl_callback($matches) { // Uncertain why the url/zrl forms weren't picked up by the non-greedy regex. - if((strpos($matches[3],'zmg') !== false) || (strpos($matches[3],'img') !== false) || (strpos($matches[3],'zrl') !== false) || (strpos($matches[3],'url') !== false)) + if((strpos($matches[3], 'zmg') !== false) || (strpos($matches[3], 'img') !== false) || (strpos($matches[3],'zrl') !== false) || (strpos($matches[3],'url') !== false)) return $matches[0]; + return '[' . $matches[1] . 'rl' . $matches[2] . ']' . $matches[3] . '"' . $matches[4] . '"' . $matches[5] . '[/' . $matches[6] . 'rl]'; } @@ -318,7 +342,6 @@ function red_escape_codeblock($m) { function red_unescape_codeblock($m) { return '[' . $m[2] . base64_decode($m[1]) . '[/' . $m[2] . ']'; - } @@ -334,28 +357,23 @@ function red_zrlify_img_callback($matches) { if($zrl) return '[zmg' . $matches[1] . ']' . $matches[2] . '[/zmg]'; + return $matches[0]; } - - /** - * @function post_activity_item($arr) - * - * post an activity - * - * @param array $arr + * @brief Post an activity. * * In its simplest form one needs only to set $arr['body'] to post a note to the logged in channel's wall. - * Much more complex activities can be created. Permissions are checked. No filtering, tag expansion + * Much more complex activities can be created. Permissions are checked. No filtering, tag expansion * or other processing is performed. * - * @returns array - * 'success' => true or false - * 'activity' => the resulting activity if successful + * @param array $arr + * @returns array + * * \e boolean \b success true or false + * * \e array \b activity the resulting activity if successful */ - function post_activity_item($arr) { $ret = array('success' => false); @@ -374,8 +392,8 @@ function post_activity_item($arr) { $channel = get_app()->get_channel(); $observer = get_app()->get_observer(); - $arr['aid'] = ((x($arr,'aid')) ? $arr['aid'] : $channel['channel_account_id']); - $arr['uid'] = ((x($arr,'uid')) ? $arr['uid'] : $channel['channel_id']); + $arr['aid'] = ((x($arr,'aid')) ? $arr['aid'] : $channel['channel_account_id']); + $arr['uid'] = ((x($arr,'uid')) ? $arr['uid'] : $channel['channel_id']); if(! perm_is_allowed($arr['uid'],$observer['xchan_hash'],(($is_comment) ? 'post_comments' : 'post_wall'))) { $ret['message'] = t('Permission denied'); @@ -409,26 +427,24 @@ function post_activity_item($arr) { $arr['body'] = json_encode(crypto_encapsulate($arr['body'],$key)); } - $arr['mid'] = ((x($arr,'mid')) ? $arr['mid'] : item_message_id()); - $arr['parent_mid'] = ((x($arr,'parent_mid')) ? $arr['parent_mid'] : $arr['mid']); - $arr['thr_parent'] = ((x($arr,'thr_parent')) ? $arr['thr_parent'] : $arr['mid']); + $arr['mid'] = ((x($arr,'mid')) ? $arr['mid'] : item_message_id()); + $arr['parent_mid'] = ((x($arr,'parent_mid')) ? $arr['parent_mid'] : $arr['mid']); + $arr['thr_parent'] = ((x($arr,'thr_parent')) ? $arr['thr_parent'] : $arr['mid']); - $arr['owner_xchan'] = ((x($arr,'owner_xchan')) ? $arr['owner_xchan'] : $channel['channel_hash']); - $arr['author_xchan'] = ((x($arr,'author_xchan')) ? $arr['author_xchan'] : $observer['xchan_hash']); + $arr['owner_xchan'] = ((x($arr,'owner_xchan')) ? $arr['owner_xchan'] : $channel['channel_hash']); + $arr['author_xchan'] = ((x($arr,'author_xchan')) ? $arr['author_xchan'] : $observer['xchan_hash']); - $arr['verb'] = ((x($arr,'verb')) ? $arr['verb'] : ACTIVITY_POST); - $arr['obj_type'] = ((x($arr,'obj_type')) ? $arr['obj_type'] : ACTIVITY_OBJ_NOTE); - if($is_comment) + $arr['verb'] = ((x($arr,'verb')) ? $arr['verb'] : ACTIVITY_POST); + $arr['obj_type'] = ((x($arr,'obj_type')) ? $arr['obj_type'] : ACTIVITY_OBJ_NOTE); + if(($is_comment) && ($arr['obj_type'] === ACTIVITY_OBJ_NOTE)) $arr['obj_type'] = ACTIVITY_OBJ_COMMENT; - $arr['allow_cid'] = ((x($arr,'allow_cid')) ? $arr['allow_cid'] : $channel['channel_allow_cid']); $arr['allow_gid'] = ((x($arr,'allow_gid')) ? $arr['allow_gid'] : $channel['channel_allow_gid']); $arr['deny_cid'] = ((x($arr,'deny_cid')) ? $arr['deny_cid'] : $channel['channel_deny_cid']); $arr['deny_gid'] = ((x($arr,'deny_gid')) ? $arr['deny_gid'] : $channel['channel_deny_gid']); - $arr['comment_policy'] = map_scope($channel['channel_w_comment']); - + $arr['comment_policy'] = map_scope($channel['channel_w_comment']); if ((! $arr['plink']) && (intval($arr['item_thread_top']))) { $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid']; @@ -446,8 +462,7 @@ function post_activity_item($arr) { return $ret; } - - $post = item_store($arr); + $post = item_store($arr); if($post['success']) $post_id = $post['item_id']; @@ -464,15 +479,15 @@ function post_activity_item($arr) { } return $ret; - } /** - * @function get_public_feed($channel,$params) - * generate an Atom feed + * @brief Generate an Atom feed. + * + * @param array $channel + * @param array $params */ - -function get_public_feed($channel,$params) { +function get_public_feed($channel, $params) { $type = 'xml'; $begin = NULL_DATE; @@ -493,7 +508,7 @@ function get_public_feed($channel,$params) { $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': header("Content-type: application/atom+json"); @@ -504,24 +519,26 @@ function get_public_feed($channel,$params) { break; } - - return get_feed_for($channel,get_observer_hash(),$params); + return get_feed_for($channel, get_observer_hash(), $params); } - - - +/** + * @brief + * + * @param array $channel + * @param string $observer_hash + * @param array $params + * @return string + */ function get_feed_for($channel, $observer_hash, $params) { if(! channel) http_status_exit(401); - if($params['pages']) { if(! perm_is_allowed($channel['channel_id'],$observer_hash,'view_pages')) http_status_exit(403); - } - else { + } else { if(! perm_is_allowed($channel['channel_id'],$observer_hash,'view_stream')) http_status_exit(403); } @@ -537,7 +554,6 @@ function get_feed_for($channel, $observer_hash, $params) { 'top' => $params['top'] ), $channel, $observer_hash, CLIENT_MODE_NORMAL, get_app()->module); - $feed_template = get_markup_template('atom_feed.tpl'); $atom = ''; @@ -570,7 +586,8 @@ function get_feed_for($channel, $observer_hash, $params) { if($item['item_private']) continue; - $atom .= atom_entry($item,$type,null,$owner,true); + /** @BUG $owner is undefined in this call */ + $atom .= atom_entry($item, $type, null, $owner, true); } } @@ -581,10 +598,17 @@ function get_feed_for($channel, $observer_hash, $params) { return $atom; } - +/** + * @brief + * + * @param array $item an associative array with + * * \b string \b verb + * @return string item's verb if set, default ACTIVITY_POST see boot.php + */ function construct_verb($item) { - if($item['verb']) + if ($item['verb']) return $item['verb']; + return ACTIVITY_POST; } @@ -603,11 +627,11 @@ function construct_activity_object($item) { if($r->title) $o .= '<title>' . xmlify($r->title) . '</title>' . "\r\n"; if($r->links) { - // FIXME!! + /** @FIXME!! */ if(substr($r->link,0,1) === '<') { $r->link = preg_replace('/\<link(.*?)\"\>/','<link$1"/>',$r->link); $o .= $r->link; - } + } else $o .= '<link rel="alternate" type="text/html" href="' . xmlify($r->link) . '" />' . "\r\n"; } @@ -618,7 +642,7 @@ function construct_activity_object($item) { } return ''; -} +} function construct_activity_target($item) { @@ -634,31 +658,36 @@ function construct_activity_target($item) { if($r->title) $o .= '<title>' . xmlify($r->title) . '</title>' . "\r\n"; if($r->links) { - // FIXME !!! + /** @FIXME !!! */ if(substr($r->link,0,1) === '<') { if(strstr($r->link,'&') && (! strstr($r->link,'&'))) $r->link = str_replace('&','&', $r->link); $r->link = preg_replace('/\<link(.*?)\"\>/','<link$1"/>',$r->link); $o .= $r->link; - } + } else $o .= '<link rel="alternate" type="text/html" href="' . xmlify($r->link) . '" />' . "\r\n"; } if($r->content) $o .= '<content type="html" >' . xmlify(bbcode($r->content)) . '</content>' . "\r\n"; + $o .= '</as:target>' . "\r\n"; + return $o; } return ''; } -/* limit_body_size() +/** + * @brief Limit lenght on imported system messages. + * + * The purpose of this function is to apply system message length limits to + * imported messages without including any embedded photos in the length. * - * The purpose of this function is to apply system message length limits to - * imported messages without including any embedded photos in the length + * @param string $body + * @return string */ - function limit_body_size($body) { $maxlen = get_max_import_size(); @@ -670,7 +699,6 @@ function limit_body_size($body) { $orig_body = $body; $new_body = ''; $textlen = 0; - $max_found = false; $img_start = strpos($orig_body, '[img'); $img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false); @@ -699,7 +727,6 @@ function limit_body_size($body) { $new_body = $new_body . substr($orig_body, $img_start, $img_end - $img_start); } else { - if( ($textlen + $img_end) > $maxlen ) { if($textlen < $maxlen) { $new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen); @@ -785,15 +812,15 @@ function get_item_elements($x) { if($arr['edited'] > datetime_convert()) $arr['edited'] = datetime_convert(); - $arr['expires'] = ((x($x,'expires') && $x['expires']) - ? datetime_convert('UTC','UTC',$x['expires']) + $arr['expires'] = ((x($x,'expires') && $x['expires']) + ? datetime_convert('UTC','UTC',$x['expires']) : NULL_DATE); - $arr['commented'] = ((x($x,'commented') && $x['commented']) - ? datetime_convert('UTC','UTC',$x['commented']) + $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']) + $arr['comments_closed'] = ((x($x,'comments_closed') && $x['comments_closed']) + ? datetime_convert('UTC','UTC',$x['comments_closed']) : NULL_DATE); $arr['title'] = (($x['title']) ? htmlspecialchars($x['title'], ENT_COMPAT,'UTF-8',false) : ''); @@ -864,7 +891,6 @@ function get_item_elements($x) { return array(); } - if($arr['sig']) { $r = q("select xchan_pubkey from xchan where xchan_hash = '%s' limit 1", dbesc($arr['author_xchan']) @@ -878,8 +904,7 @@ function get_item_elements($x) { // if it's a private post, encrypt it in the DB. // We have to do that here because we need to cleanse the input and prevent bad stuff from getting in, - // and we need plaintext to do that. - + // and we need plaintext to do that. if(intval($arr['item_private'])) { @@ -906,11 +931,9 @@ function get_item_elements($x) { $arr['item_restrict'] = $x['item_restrict']; $arr['item_flags'] = $x['item_flags']; $arr['attach'] = $x['attach']; - } return $arr; - } @@ -938,10 +961,17 @@ function import_author_xchan($x) { return(($y) ? $y : false); } - +/** + * @brief Imports an author from Diaspora. + * + * @param array $x an associative array with + * * \e string \b address + * @return boolean|string false on error, otherwise xchan_hash of the new entry + */ function import_author_diaspora($x) { if(! $x['address']) return false; + if(discover_by_webbie($x['address'])) { $r = q("select xchan_hash from xchan where xchan_addr = '%s' limit 1", dbesc($x['address']) @@ -949,12 +979,20 @@ function import_author_diaspora($x) { if($r) return $r[0]['xchan_hash']; } + return false; } - +/** + * @brief Imports an author from a RSS feed. + * + * @param array $x an associative array with + * * \e string \b url + * * \e string \b name + * * \e string \b guid + * @return boolean|string + */ function import_author_rss($x) { - if(! $x['url']) return false; @@ -967,7 +1005,7 @@ function import_author_rss($x) { } $name = trim($x['name']); - $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_url, xchan_name, xchan_network ) + $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_url, xchan_name, xchan_network ) values ( '%s', '%s', '%s', '%s', '%s' )", dbesc($x['guid']), dbesc($x['guid']), @@ -975,13 +1013,15 @@ function import_author_rss($x) { dbesc(($name) ? $name : t('(Unknown)')), dbesc('rss') ); + if($r && $x['photo']) { $photos = import_profile_photo($x['photo']['src'],$x['url']); if($photos) { + /** @bug $arr is undefined in this SQL query */ $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_url = '%s' and xchan_network = 'rss'", - dbesc(datetime_convert('UTC','UTC',$arr['photo_updated'])), + dbesc(datetime_convert('UTC', 'UTC', $arr['photo_updated'])), dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), @@ -994,7 +1034,6 @@ function import_author_rss($x) { } return false; - } function import_author_unknown($x) { @@ -1012,7 +1051,7 @@ function import_author_unknown($x) { $name = trim($x['name']); - $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_url, xchan_name, xchan_network ) + $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_url, xchan_name, xchan_network ) values ( '%s', '%s', '%s', '%s', '%s' )", dbesc($x['url']), dbesc($x['url']), @@ -1025,6 +1064,7 @@ function import_author_unknown($x) { $photos = import_profile_photo($x['photo']['src'],$x['url']); if($photos) { + /** @bug $arr is undefined in this SQL query */ $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_url = '%s' and xchan_network = 'unknown'", dbesc(datetime_convert('UTC','UTC',$arr['photo_updated'])), dbesc($photos[0]), @@ -1039,7 +1079,6 @@ function import_author_unknown($x) { } return false; - } function encode_item($item,$mirror = false) { @@ -1073,7 +1112,7 @@ function encode_item($item,$mirror = false) { $item['body'] = crypto_unencapsulate(json_decode_plus($item['body']),$key); } - // If we're trying to backup an item so that it's recoverable or for export/imprt, + // If we're trying to backup an item so that it's recoverable or for export/imprt, // add all the attributes we need to recover it if($mirror) { @@ -1146,11 +1185,16 @@ function encode_item($item,$mirror = false) { logger('encode_item: ' . print_r($x,true), LOGGER_DATA); return $x; - } - -function map_scope($scope,$strip = false) { +/** + * @brief + * + * @param int $scope + * @param boolean $strip (optional) default false + * @return string + */ +function map_scope($scope, $strip = false) { switch($scope) { case 0: return 'self'; @@ -1170,8 +1214,14 @@ function map_scope($scope,$strip = false) { default: return 'contacts'; } -} +} +/** + * @brief Returns a descriptive text for a given $scope. + * + * @param string $scope + * @return string translated string describing the scope + */ function translate_scope($scope) { if(! $scope || $scope === 'public') return t('Visible to anybody on the internet.'); @@ -1191,9 +1241,15 @@ function translate_scope($scope) { return t('Visible to specific connections.'); } +/** + * @brief + * + * @param array $xchan + * @return array an associative array + */ function encode_item_xchan($xchan) { - $ret = array(); + $ret['name'] = $xchan['xchan_name']; $ret['address'] = $xchan['xchan_addr']; $ret['url'] = (($xchan['hubloc_url']) ? $xchan['hubloc_url'] : $xchan['xchan_url']); @@ -1201,11 +1257,12 @@ function encode_item_xchan($xchan) { $ret['photo'] = array('mimetype' => $xchan['xchan_photo_mimetype'], 'src' => $xchan['xchan_photo_m']); $ret['guid'] = $xchan['xchan_guid']; $ret['guid_sig'] = $xchan['xchan_guid_sig']; + return $ret; } function encode_item_terms($terms) { - $ret = array(); + $ret = array(); $allowed_export_terms = array( TERM_UNKNOWN, TERM_HASHTAG, TERM_MENTION, TERM_CATEGORY, TERM_BOOKMARK ); @@ -1215,22 +1272,38 @@ function encode_item_terms($terms) { $ret[] = array('tag' => $term['term'], 'url' => $term['url'], 'type' => termtype($term['type'])); } } + return $ret; } +/** + * @brief + * + * @param int $t + * @return string + */ function termtype($t) { $types = array('unknown','hashtag','mention','category','private_category','file','search','thing','bookmark'); + return(($types[$t]) ? $types[$t] : 'unknown'); } +/** + * @brief + * + * @param array $t + * @return array|string empty string or array containing associative arrays with + * * \e string \b term + * * \e string \b url + * * \e int \b type + */ function decode_tags($t) { - if($t) { $ret = array(); foreach($t as $x) { $tag = array(); - $tag['term'] = htmlspecialchars($x['tag'], ENT_COMPAT,'UTF-8',false); - $tag['url'] = htmlspecialchars($x['url'], ENT_COMPAT,'UTF-8',false); + $tag['term'] = htmlspecialchars($x['tag'], ENT_COMPAT, 'UTF-8', false); + $tag['url'] = htmlspecialchars($x['url'], ENT_COMPAT, 'UTF-8', false); switch($x['type']) { case 'hashtag': $tag['type'] = TERM_HASHTAG; @@ -1263,14 +1336,19 @@ function decode_tags($t) { } $ret[] = $tag; } + return $ret; } - return ''; + return ''; } -// santise a potentially complex array - +/** + * @brief Santise a potentially complex array. + * + * @param array $arr + * @return array|string + */ function activity_sanitise($arr) { if($arr) { if(is_array($arr)) { @@ -1279,19 +1357,24 @@ function activity_sanitise($arr) { if(is_array($x)) $ret[$k] = activity_sanitise($x); else - $ret[$k] = htmlspecialchars($x, ENT_COMPAT,'UTF-8',false); + $ret[$k] = htmlspecialchars($x, ENT_COMPAT, 'UTF-8', false); } return $ret; } else { - return htmlspecialchars($arr, ENT_COMPAT,'UTF-8', false); + return htmlspecialchars($arr, ENT_COMPAT, 'UTF-8', false); } } + return ''; } -// sanitise a simple linear array - +/** + * @brief Sanitise a simple linear array. + * + * @param array $arr + * @return array|string + */ function array_sanitise($arr) { if($arr) { $ret = array(); @@ -1300,6 +1383,7 @@ function array_sanitise($arr) { } return $ret; } + return ''; } @@ -1322,7 +1406,7 @@ function encode_item_flags($item) { $ret[] = 'consensus'; if($item['item_private']) $ret[] = 'private'; - + return $ret; } @@ -1415,7 +1499,6 @@ function get_mail_elements($x) { return array(); return $arr; - } @@ -1441,23 +1524,25 @@ function get_profile_elements($x) { $arr['postcode'] = (($x['postcode']) ? htmlspecialchars($x['postcode'], ENT_COMPAT,'UTF-8',false) : ''); $arr['country'] = (($x['country']) ? htmlspecialchars($x['country'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['keywords'] = (($x['keywords'] && is_array($x['keywords'])) ? array_sanitise($x['keywords']) : array()); + $arr['keywords'] = (($x['keywords'] && is_array($x['keywords'])) ? array_sanitise($x['keywords']) : array()); return $arr; - } +/** + * @param object $feed + * @param array $item + * @param[out] array $author + * @return multitype:multitype: string NULL number Ambigous <NULL, string, number> Ambigous <mixed, string> Ambigous <multitype:multitype:string Ambigous <NULL, string> , multitype:multitype:string unknown > multitype:NULL unknown + */ +function get_atom_elements($feed, $item, &$author) { - -function get_atom_elements($feed,$item,&$author) { - - - $best_photo = array(); + //$best_photo = array(); $res = array(); $found_author = $item->get_author(); - if($found_author) { + if($found_author) { $author['author_name'] = unxmlify($found_author->get_name()); $author['author_link'] = unxmlify($found_author->get_link()); $author['author_is_feed'] = false; @@ -1527,7 +1612,7 @@ function get_atom_elements($feed,$item,&$author) { if($rawmedia && $rawmedia[0]['attribs']['']['url']) { $author['author_photo'] = strip_tags(unxmlify($rawmedia[0]['attribs']['']['url'])); } - } + } // No photo/profile-link on the item - look at the feed level @@ -1569,9 +1654,9 @@ function get_atom_elements($feed,$item,&$author) { $apps = $item->get_item_tags(NAMESPACE_STATUSNET,'notice_info'); if($apps && $apps[0]['attribs']['']['source']) { $res['app'] = strip_tags(unxmlify($apps[0]['attribs']['']['source'])); - } + } - /** + /* * If there's a copy of the body content which is guaranteed to have survived mangling in transit, use it. */ @@ -1585,24 +1670,22 @@ function get_atom_elements($feed,$item,&$author) { // 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 + // 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']); - } - $res['body'] = limit_body_size($res['body']); - // It isn't certain at this point whether our content is plaintext or html and we'd be foolish to trust - // the content type. Our own network only emits text normally, though it might have been converted to + // It isn't certain at this point whether our content is plaintext or html and we'd be foolish to trust + // the content type. Our own network only emits text normally, though it might have been converted to // html if we used a pubsubhubbub transport. But if we see even one html tag in our text, we will // have to assume it is all html and needs to be purified. - // It doesn't matter all that much security wise - because before this content is used anywhere, we are - // going to escape any tags we find regardless, but this lets us import a limited subset of html from - // the wild, by sanitising it and converting supported tags to bbcode before we rip out any remaining + // It doesn't matter all that much security wise - because before this content is used anywhere, we are + // going to escape any tags we find regardless, but this lets us import a limited subset of html from + // the wild, by sanitising it and converting supported tags to bbcode before we rip out any remaining // html. if((strpos($res['body'],'<') !== false) && (strpos($res['body'],'>') !== false)) { @@ -1616,8 +1699,6 @@ function get_atom_elements($feed,$item,&$author) { $res['body'] = purify_html($res['body']); $res['body'] = @html2bbcode($res['body']); - - } elseif(! $have_real_body) { @@ -1648,7 +1729,6 @@ function get_atom_elements($feed,$item,&$author) { ); } - $private = $item->get_item_tags(NAMESPACE_DFRN,'private'); if($private && intval($private[0]['data']) > 0) $res['item_private'] = ((intval($private[0]['data'])) ? 1 : 0); @@ -1659,18 +1739,16 @@ function get_atom_elements($feed,$item,&$author) { if($rawlocation) $res['location'] = unxmlify($rawlocation[0]['data']); - $rawcreated = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'published'); if($rawcreated) $res['created'] = unxmlify($rawcreated[0]['data']); - $rawedited = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'updated'); if($rawedited) $res['edited'] = unxmlify($rawedited[0]['data']); if((x($res,'edited')) && (! (x($res,'created')))) - $res['created'] = $res['edited']; + $res['created'] = $res['edited']; if(! $res['created']) $res['created'] = $item->get_date('c'); @@ -1731,7 +1809,7 @@ function get_atom_elements($feed,$item,&$author) { } // translate OStatus unfollow to activity streams if it happened to get selected - + if((x($res,'verb')) && ($res['verb'] === 'http://ostatus.org/schema/1.0/unfollow')) $res['verb'] = ACTIVITY_UNFOLLOW; @@ -1761,7 +1839,7 @@ function get_atom_elements($feed,$item,&$author) { 'url' => $termurl, 'term' => $termterm, ); - } + } } } @@ -1771,7 +1849,6 @@ function get_atom_elements($feed,$item,&$author) { $attach = $item->get_enclosures(); if($attach) { $res['attach'] = array(); - $att_arr = array(); foreach($attach as $att) { $len = intval($att->get_length()); $link = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_link())))); @@ -1786,6 +1863,7 @@ function get_atom_elements($feed,$item,&$author) { $title = ' '; if(! $type) $type = 'application/octet-stream'; + $res['attach'][] = array('href' => $link, 'length' => $len, 'type' => $type, 'title' => $title ); } } @@ -1799,7 +1877,7 @@ function get_atom_elements($feed,$item,&$author) { if($child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']) { $res['obj_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']) $obj['id'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data']; if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) @@ -1813,10 +1891,8 @@ function get_atom_elements($feed,$item,&$author) { // preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events $obj['orig'] = xmlify($body); if((strpos($body,'<') !== false) || (strpos($body,'>') !== false)) { - $body = purify_html($body); $body = html2bbcode($body); - } $obj['content'] = $body; @@ -1834,7 +1910,7 @@ function get_atom_elements($feed,$item,&$author) { if($child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']) { $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']) $obj['id'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data']; if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']) @@ -1845,13 +1921,12 @@ function get_atom_elements($feed,$item,&$author) { $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 $obj['orig'] = xmlify($body); if((strpos($body,'<') !== false) || (strpos($body,'>') !== false)) { - $body = purify_html($body); $body = html2bbcode($body); - } $obj['content'] = $body; @@ -1892,17 +1967,26 @@ function encode_rel_links($links) { $o .= 'media:height="' . $link['attribs'][NAMESPACE_MEDIA]['height'] . '" '; $o .= ' />' . "\n" ; } + return xmlify($o); } -function item_store($arr,$allow_exec = false) { +/** + * @brief + * + * @param array $arr + * @param boolean $allow_exec (optional) default false + * @return array + * * \e boolean \b success + * * \e int \b item_id + */ +function item_store($arr, $allow_exec = false) { $d = array('item' => $arr, 'allow_exec' => $allow_exec); call_hooks('item_store', $d ); $arr = $d['item']; $allow_exec = $d['allow_exec']; - $ret = array('success' => false, 'item_id' => 0); if(! $arr['uid']) { @@ -1911,9 +1995,9 @@ function item_store($arr,$allow_exec = false) { return $ret; } - $uplinked_comment = false; + //$uplinked_comment = false; - // If a page layout is provided, ensure it exists and belongs to us. + // If a page layout is provided, ensure it exists and belongs to us. if(array_key_exists('layout_mid',$arr) && $arr['layout_mid']) { $l = q("select item_type from item where mid = '%s' and uid = %d limit 1", @@ -1951,8 +2035,6 @@ function item_store($arr,$allow_exec = false) { $arr['item_private'] = ((x($arr,'item_private')) ? intval($arr['item_private']) : 0 ); $arr['item_flags'] = ((x($arr,'item_flags')) ? intval($arr['item_flags']) : 0 ); - - // only detect language if we have text content, and if the post is private but not yet // obscured, make it so. @@ -1962,7 +2044,6 @@ function item_store($arr,$allow_exec = false) { // apply the input filter here - if it is obscured it has been filtered already $arr['body'] = z_input_filter($arr['uid'],$arr['body'],$arr['mimetype']); - if(local_channel() && (! $arr['sig'])) { $channel = get_app()->get_channel(); if($channel['channel_hash'] === $arr['author_xchan']) { @@ -1972,7 +2053,7 @@ function item_store($arr,$allow_exec = false) { } $allowed_languages = get_pconfig($arr['uid'],'system','allowed_languages'); - + if((is_array($allowed_languages)) && ($arr['lang']) && (! array_key_exists($arr['lang'],$allowed_languages))) { $translate = array('item' => $arr, 'from' => $arr['lang'], 'to' => $allowed_languages, 'translated' => false); call_hooks('item_translate', $translate); @@ -1991,7 +2072,6 @@ function item_store($arr,$allow_exec = false) { if($arr['body']) $arr['body'] = json_encode(crypto_encapsulate($arr['body'],$key)); } - } if((x($arr,'object')) && is_array($arr['object'])) { @@ -2058,8 +2138,6 @@ function item_store($arr,$allow_exec = false) { if(! $arr['plink']) $arr['plink'] = $arr['llink']; - - if($arr['parent_mid'] === $arr['mid']) { $parent_id = 0; $parent_deleted = 0; @@ -2071,7 +2149,7 @@ function item_store($arr,$allow_exec = false) { $comments_closed = $arr['comments_closed']; $arr['item_thread_top'] = 1; } - else { + else { // find the parent and snarf the item id and ACL's // and anything else we need to inherit @@ -2083,6 +2161,16 @@ function item_store($arr,$allow_exec = false) { if($r) { + // in case item_store was killed before the parent's parent attribute got set, + // set it now. This happens with some regularity on Dreamhost. This will keep + // us from getting notifications for threads that exist but which we can't see. + + if(($r[0]['mid'] === $r[0]['parent_mid']) && (! intval($r[0]['parent']))) { + q("update item set parent = id where id = %d", + intval($r[0]['id']) + ); + } + if(comments_are_now_closed($r[0])) { logger('item_store: comments closed'); $ret['message'] = 'Comments closed.'; @@ -2098,7 +2186,7 @@ function item_store($arr,$allow_exec = false) { if($r[0]['mid'] != $r[0]['parent_mid']) { $arr['parent_mid'] = $r[0]['parent_mid']; - $z = q("SELECT * FROM `item` WHERE `mid` = '%s' AND `parent_mid` = '%s' AND `uid` = %d + $z = q("SELECT * FROM `item` WHERE `mid` = '%s' AND `parent_mid` = '%s' AND `uid` = %d ORDER BY `id` ASC LIMIT 1", dbesc($r[0]['parent_mid']), dbesc($r[0]['parent_mid']), @@ -2126,7 +2214,7 @@ function item_store($arr,$allow_exec = false) { if($r[0]['owner_xchan'] !== $arr['owner_xchan']) { $arr['owner_xchan'] = $r[0]['owner_xchan']; - $uplinked_comment = true; +// $uplinked_comment = true; } // if the parent is private, force privacy for the entire conversation @@ -2136,7 +2224,7 @@ function item_store($arr,$allow_exec = false) { // 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. + // weren't fixed up so it will still show the comment as private unless we fix it here. if(intval($r[0]['item_uplink']) && (! $r[0]['item_private'])) $arr['item_private'] = 0; @@ -2150,8 +2238,7 @@ function item_store($arr,$allow_exec = false) { if($parent_deleted) $arr['item_deleted'] = 1; - - + $r = q("SELECT `id` FROM `item` WHERE `mid` = '%s' AND `uid` = %d LIMIT 1", dbesc($arr['mid']), intval($arr['uid']) @@ -2184,7 +2271,7 @@ function item_store($arr,$allow_exec = false) { if(strlen($allow_cid) || strlen($allow_gid) || strlen($deny_cid) || strlen($deny_gid) || strlen($public_policy)) $private = 1; else - $private = $arr['item_private']; + $private = $arr['item_private']; $arr['parent'] = $parent_id; $arr['allow_cid'] = $allow_cid; @@ -2199,10 +2286,10 @@ function item_store($arr,$allow_exec = false) { dbesc_array($arr); - $r = dbq("INSERT INTO `item` (`" - . implode("`, `", array_keys($arr)) - . "`) VALUES ('" - . implode("', '", array_values($arr)) + $r = dbq("INSERT INTO `item` (`" + . implode("`, `", array_keys($arr)) + . "`) VALUES ('" + . implode("', '", array_values($arr)) . "')" ); // find the item we just created @@ -2256,7 +2343,7 @@ function item_store($arr,$allow_exec = false) { } $arr['term'] = $terms; - } + } call_hooks('post_remote_end',$arr); @@ -2275,9 +2362,16 @@ function item_store($arr,$allow_exec = false) { ); - send_status_notifications($current_post,$arr); + // If _creating_ a deleted item, don't propagate it further or send out notifications. + // We need to store the item details just in case the delete came in before the original post, + // so that we have an item in the DB that's marked deleted and won't store a fresh post + // that isn't aware that we were already told to delete it. + + if(! ($arr['item_restrict'] & ITEM_DELETED)) { + send_status_notifications($current_post,$arr); + tag_deliver($arr['uid'],$current_post); + } - tag_deliver($arr['uid'],$current_post); $ret['success'] = true; $ret['item_id'] = $current_post; @@ -2316,7 +2410,7 @@ function item_store_update($arr,$allow_exec = false) { logger('item_store_update: original post not found: ' . $orig_post_id); $ret['message'] = 'no original'; return $ret; - } + } // override the unseen flag with the original @@ -2325,9 +2419,9 @@ function item_store_update($arr,$allow_exec = false) { $arr['item_flags'] = intval($arr['item_flags']) | $orig[0]['item_flags']; $arr['item_restrict'] = intval($arr['item_restrict']) | $orig[0]['item_restrict']; - if(array_key_exists('edit',$arr)) - unset($arr['edit']); + unset($arr['edit']); + $arr['mimetype'] = ((x($arr,'mimetype')) ? notags(trim($arr['mimetype'])) : 'text/bbcode'); if(($arr['mimetype'] == 'application/x-php') && (! $allow_exec)) { @@ -2351,7 +2445,7 @@ function item_store_update($arr,$allow_exec = false) { } $allowed_languages = get_pconfig($arr['uid'],'system','allowed_languages'); - + if((is_array($allowed_languages)) && ($arr['lang']) && (! array_key_exists($arr['lang'],$allowed_languages))) { $translate = array('item' => $arr, 'from' => $arr['lang'], 'to' => $allowed_languages, 'translated' => false); call_hooks('item_translate', $translate); @@ -2370,10 +2464,8 @@ function item_store_update($arr,$allow_exec = false) { if($arr['body']) $arr['body'] = json_encode(crypto_encapsulate($arr['body'],$key)); } - } - if((x($arr,'object')) && is_array($arr['object'])) { activity_sanitise($arr['object']); $arr['object'] = json_encode($arr['object']); @@ -2389,7 +2481,6 @@ function item_store_update($arr,$allow_exec = false) { $arr['attach'] = json_encode($arr['attach']); } - unset($arr['id']); unset($arr['uid']); unset($arr['aid']); @@ -2436,15 +2527,13 @@ function item_store_update($arr,$allow_exec = false) { $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'] ); // $arr['item_flags'] = ((x($arr,'item_flags')) ? intval($arr['item_flags']) : $orig[0]['item_flags'] ); - + $arr['sig'] = ((x($arr,'sig')) ? $arr['sig'] : ''); $arr['layout_mid'] = ((array_key_exists('layout_mid',$arr)) ? dbesc($arr['layout_mid']) : $orig[0]['layout_mid'] ); $arr['public_policy'] = ((x($arr,'public_policy')) ? notags(trim($arr['public_policy'])) : $orig[0]['public_policy'] ); $arr['comment_policy'] = ((x($arr,'comment_policy')) ? notags(trim($arr['comment_policy'])) : $orig[0]['comment_policy'] ); - - call_hooks('post_remote_update',$arr); if(x($arr,'cancel')) { @@ -2466,11 +2555,11 @@ function item_store_update($arr,$allow_exec = false) { logger('item_store_update: ' . print_r($arr,true), LOGGER_DATA); $str = ''; - foreach($arr as $k => $v) { - if($str) - $str .= ","; - $str .= " `" . $k . "` = '" . $v . "' "; - } + foreach($arr as $k => $v) { + if($str) + $str .= ","; + $str .= " `" . $k . "` = '" . $v . "' "; + } $r = dbq("update `item` set " . $str . " where id = " . $orig_post_id ); @@ -2501,7 +2590,7 @@ function item_store_update($arr,$allow_exec = false) { } $arr['term'] = $terms; - } + } call_hooks('post_remote_update_end',$arr); @@ -2516,7 +2605,7 @@ function item_store_update($arr,$allow_exec = false) { function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id, $walltowall = false) { - // We won't be able to sign Diaspora comments for authenticated visitors + // 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. @@ -2527,9 +2616,9 @@ function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id, if($walltowall) { logger('wall to wall comment',LOGGER_DEBUG); // post will come across with the owner's identity. Throw a preamble onto the post to indicate the true author. - $signed_body = "\n\n" + $signed_body = "\n\n" . '![' . $datarray['author']['xchan_name'] . '](' . $datarray['author']['xchan_photo_m'] . ')' - . '[' . $datarray['author']['xchan_name'] . '](' . $datarray['author']['xchan_url'] . ')' . "\n\n" + . '[' . $datarray['author']['xchan_name'] . '](' . $datarray['author']['xchan_url'] . ')' . "\n\n" . $signed_body; } @@ -2539,8 +2628,9 @@ function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id, $signed_text = $datarray['mid'] . ';' . $parent_item['mid'] . ';' . $signed_body . ';' . $diaspora_handle; + /** @FIXME $uprvkey is undefined, do we still need this if-statement? */ if( $uprvkey !== false ) - $authorsig = base64_encode(rsa_sign($signed_text,$channel['channel_prvkey'],'sha256')); + $authorsig = base64_encode(rsa_sign($signed_text, $channel['channel_prvkey'], 'sha256')); else $authorsig = ''; @@ -2551,7 +2641,7 @@ function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id, $r = q("update item set diaspora_meta = '%s' where id = %d", dbesc(json_encode($y)), - intval($post_id) + intval($post_id) ); if(! $r) @@ -2601,7 +2691,6 @@ function send_status_notifications($post_id,$item) { $link = get_app()->get_baseurl() . '/display/' . $item['mid']; - $y = q("select id from notify where link = '%s' and uid = %d limit 1", dbesc($link), intval($item['uid']) @@ -2612,50 +2701,50 @@ function send_status_notifications($post_id,$item) { if(! $notify) return; + require_once('include/enotify.php'); notification(array( 'type' => NOTIFY_COMMENT, 'from_xchan' => $item['author_xchan'], 'to_xchan' => $r[0]['channel_hash'], 'item' => $item, - 'link' => $link, + 'link' => $link, 'verb' => ACTIVITY_POST, 'otype' => 'item', 'parent' => $parent, 'parent_mid' => $item['parent_mid'] )); - return; } - - - - function get_item_contact($item,$contacts) { if(! count($contacts) || (! is_array($item))) return false; + foreach($contacts as $contact) { if($contact['id'] == $item['contact-id']) { return $contact; break; // NOTREACHED } } + return false; } - -function tag_deliver($uid,$item_id) { - - // Called when we deliver things that might be tagged in ways that require delivery processing. - // Handles community tagging of posts and also look for mention tags - // and sets up a second delivery chain if appropriate - - $a = get_app(); +/** + * @brief Called when we deliver things that might be tagged in ways that require delivery processing. + * + * Handles community tagging of posts and also look for mention tags and sets up + * a second delivery chain if appropriate. + * + * @param int $uid + * @param int $item_id + */ +function tag_deliver($uid, $item_id) { $mention = false; - /** + /* * Fetch stuff we need - a channel and an item */ @@ -2664,7 +2753,7 @@ function tag_deliver($uid,$item_id) { ); if(! $u) return; - + $i = q("select * from item where id = %d and uid = %d limit 1", intval($item_id), intval($uid) @@ -2684,22 +2773,23 @@ function tag_deliver($uid,$item_id) { return; } - - /** + /* * Seems like a good place to plug in a poke notification. */ if (stristr($item['verb'],ACTIVITY_POKE)) { $poke_notify = true; - if(($item['obj_type'] == "") || ($item['obj_type'] !== ACTIVITY_OBJ_PERSON) || (! $item['object'])) - $poke_notify = false; + if(($item['obj_type'] == "") || ($item['obj_type'] !== ACTIVITY_OBJ_PERSON) || (! $item['object'])) + $poke_notify = false; $obj = json_decode_plus($item['object']); if($obj) { if($obj['id'] !== $u[0]['channel_hash']) $poke_notify = false; } + if($item['item_restrict'] & ITEM_DELETED) + $poke_notify = false; $verb = urldecode(substr($item['verb'],strpos($item['verb'],'#')+1)); if($poke_notify) { @@ -2717,7 +2807,7 @@ function tag_deliver($uid,$item_id) { } } - /** + /* * Do community tagging */ @@ -2726,7 +2816,7 @@ function tag_deliver($uid,$item_id) { // We received a community tag activity for a post. // See if we are the owner of the parent item and have given permission to tag our posts. // If so tag the parent post. - + logger('tag_deliver: community tag activity received'); if(($item['owner_xchan'] === $u[0]['channel_hash']) && (! get_pconfig($u[0]['channel_id'],'system','blocktags'))) { @@ -2751,7 +2841,7 @@ function tag_deliver($uid,$item_id) { dbesc(datetime_convert()), dbesc($j_tgt['id']), intval($u[0]['channel_id']) - ); + ); proc_run('php','include/notifier.php','edit_post',$p[0]['id']); } } @@ -2761,7 +2851,7 @@ 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. @@ -2787,11 +2877,10 @@ function tag_deliver($uid,$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 */ - $terms = get_terms_oftype($item['term'],TERM_MENTION); if($terms) @@ -2801,23 +2890,23 @@ function tag_deliver($uid,$item_id) { if($terms) { foreach($terms as $term) { - if(link_compare($term['url'],$link)) { + if(link_compare($term['url'],$link)) { $mention = true; break; } } - } + } if($mention) { logger('tag_deliver: mention found for ' . $u[0]['channel_name']); $r = q("update item set item_mentionsme = 1 where id = %d", 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. + // If it's private we may have to unobscure it momentarily so that we can parse it. $body = ''; @@ -2827,18 +2916,19 @@ function tag_deliver($uid,$item_id) { $body = crypto_unencapsulate(json_decode_plus($item['body']),$key); } else - $body = $item['body']; + $body = $item['body']; $body = preg_replace('/\[share(.*?)\[\/share\]/','',$body); $tagged = false; $plustagged = false; + $matches = array(); $pattern = '/@\!?\[zrl\=' . preg_quote($term['url'],'/') . '\]' . preg_quote($term['term'],'/') . '\[\/zrl\]/'; - if(preg_match($pattern,$body,$matches)) + if(preg_match($pattern,$body,$matches)) $tagged = true; - $pattern = '/@\!?\[zrl\=(.*?)\](.*?)\+\[\/zrl\]/'; + $pattern = '/@\!?\[zrl\=([^\]]*?)\]((?:.(?!\[zrl\=))*?)\+\[\/zrl\]/'; if(preg_match_all($pattern,$body,$matches,PREG_SET_ORDER)) { $max_forums = get_config('system','max_tagged_forums'); @@ -2865,7 +2955,7 @@ function tag_deliver($uid,$item_id) { $arr = array('channel_id' => $uid, 'item' => $item, 'body' => $body); call_hooks('tagged',$arr); - /** + /* * Kill two birds with one stone. As long as we're here, send a mention notification. */ @@ -2893,7 +2983,6 @@ function tag_deliver($uid,$item_id) { logger('tag_delivery denied for uid ' . $uid . ' and xchan ' . $item['author_xchan']); return; } - } if((! $mention) && (! $union)) { @@ -2912,25 +3001,18 @@ function tag_deliver($uid,$item_id) { logger('tag_deliver: creating second delivery chain.'); start_delivery_chain($u[0],$item,$item_id,null); - } /** - * @function tgroup_check($uid,$item) + * @brief This function is called pre-deliver to see if a post matches the criteria to be tag delivered. * - * 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. + * By then it would be too late to reject it. */ - - - function tgroup_check($uid,$item) { - $a = get_app(); - $mention = false; // check that the message originated elsewhere and is a top-level post @@ -2943,6 +3025,7 @@ function tgroup_check($uid,$item) { ); if($r) return true; + return false; } if(! perm_is_allowed($uid,$item['author_xchan'],'tag_deliver')) @@ -2964,13 +3047,12 @@ function tgroup_check($uid,$item) { if($terms) { foreach($terms as $term) { - if(link_compare($term['url'],$link)) { + if(link_compare($term['url'],$link)) { $mention = true; break; } } - } - + } if($mention) { logger('tgroup_check: mention found for ' . $u[0]['channel_name']); @@ -2992,12 +3074,12 @@ function tgroup_check($uid,$item) { $body = preg_replace('/\[share(.*?)\[\/share\]/','',$body); - // $pattern = '/@\!?\[zrl\=' . preg_quote($term['url'],'/') . '\]' . preg_quote($term['term'] . '+','/') . '\[\/zrl\]/'; - $pattern = '/@\!?\[zrl\=(.*?)\](.*?)\+\[\/zrl\]/'; + $pattern = '/@\!?\[zrl\=([^\]]*?)\]((?:.(?!\[zrl\=))*?)\+\[\/zrl\]/'; $found = false; + $matches = array(); if(preg_match_all($pattern,$body,$matches,PREG_SET_ORDER)) { $max_forums = get_config('system','max_tagged_forums'); @@ -3022,23 +3104,25 @@ function tgroup_check($uid,$item) { } return true; - } /** * 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. + * 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. + * + * @param array $channel + * @param array $item + * @param int $item_id + * @param boolean $parent */ - -function start_delivery_chain($channel,$item,$item_id,$parent) { - +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'] + $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); @@ -3046,6 +3130,7 @@ function start_delivery_chain($channel,$item,$item_id,$parent) { if((! $private) && $new_public_policy) $private = 1; + $item_wall = 1; $item_origin = 1; $item_uplink = 0; @@ -3068,7 +3153,7 @@ function start_delivery_chain($channel,$item,$item_id,$parent) { $r = q("update item set source_xchan = owner_xchan where id = %d", intval($item_id) ); - } + } $title = $item['title']; $body = $item['body']; @@ -3118,34 +3203,25 @@ function start_delivery_chain($channel,$item,$item_id,$parent) { if($r) proc_run('php','include/notifier.php','tgroup',$item_id); else - logger('start_delivery_chain: failed to update item'); - - return; + logger('start_delivery_chain: failed to update item'); } - - /** - * @function check_item_source($uid,$item) - * @param $uid - * @param $item + * @brief * - * @description - * Checks to see if this item owner is referenced as a source for this channel and if the post + * Checks to see if this item owner is referenced as a source for this channel and if the post * matches the rules for inclusion in this channel. Returns true if we should create a second delivery * chain and false if none of the rules apply, or if the item is private. + * + * @param int $uid + * @param array $item */ - - -function check_item_source($uid,$item) { - - +function check_item_source($uid, $item) { $r = q("select * from source where src_channel_id = %d and ( src_xchan = '%s' or src_xchan = '*' ) limit 1", intval($uid), dbesc(($item['source_xchan']) ? $item['source_xchan'] : $item['owner_xchan']) ); - if(! $r) return false; @@ -3154,18 +3230,15 @@ function check_item_source($uid,$item) { dbesc($item['owner_xchan']) ); - if(! $x) return false; - if(! ($x[0]['abook_their_perms'] & PERMS_A_REPUBLISH)) return false; if($item['item_private'] && (! ($x[0]['abook_flags'] & ABOOK_FLAG_FEED))) return false; - if($r[0]['src_channel_xchan'] === $item['owner_xchan']) return false; @@ -3176,6 +3249,7 @@ function check_item_source($uid,$item) { $text = prepare_text($item['body'],$item['mimetype']); $text = html2plain($text); + /** @BUG $items is undefined, should this be $item? */ $tags = ((count($items['term'])) ? $items['term'] : false); $words = explode("\n",$r[0]['src_patt']); @@ -3190,12 +3264,11 @@ function check_item_source($uid,$item) { return true; } } + return false; } - - function mail_store($arr) { if(! $arr['channel_id']) { @@ -3203,7 +3276,7 @@ function mail_store($arr) { return 0; } - if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false)) + if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false)) $arr['body'] = escape_tags($arr['body']); if(array_key_exists('attach',$arr) && is_array($arr['attach'])) @@ -3220,7 +3293,6 @@ function mail_store($arr) { $arr['body'] = ((x($arr,'body')) ? trim($arr['body']) : ''); $arr['mail_flags'] = ((x($arr,'mail_flags')) ? intval($arr['mail_flags']) : 0 ); - if(! $arr['parent_mid']) { logger('mail_store: missing parent'); @@ -3247,10 +3319,10 @@ function mail_store($arr) { logger('mail_store: ' . print_r($arr,true), LOGGER_DATA); - $r = dbq("INSERT INTO mail (`" - . implode("`, `", array_keys($arr)) - . "`) VALUES ('" - . implode("', '", array_values($arr)) + $r = dbq("INSERT INTO mail (`" + . implode("`, `", array_keys($arr)) + . "`) VALUES ('" + . implode("', '", array_values($arr)) . "')" ); // find the item we just created @@ -3286,9 +3358,9 @@ function mail_store($arr) { 'type' => NOTIFY_MAIL, 'item' => $arr, 'verb' => ACTIVITY_POST, - 'otype' => 'mail' + 'otype' => 'mail' ); - + notification($notif_params); } @@ -3296,35 +3368,35 @@ function mail_store($arr) { return $current_post; } - /** + * @brief Process atom feed and update anything/everything we might need to update. * - * consume_feed - process atom feed and update anything/everything we might need to update - * - * $xml = the (atom) feed to consume - RSS isn't as fully supported but may work for simple feeds. - * - * $importer = the contact_record (joined to user_record) of the local user who owns this relationship. - * It is this person's stuff that is going to be updated. - * $contact = the person who is sending us stuff. If not set, we MAY be processing a "follow" activity - * from an external network and MAY create an appropriate contact record. Otherwise, we MUST - * have a contact record. - * $hub = should we find a hub declation in the feed, pass it back to our calling process, who might (or + * $hub = should we find a hub declation in the feed, pass it back to our calling process, who might (or * might not) try and subscribe to it. * $datedir sorts in reverse order - * $pass - by default ($pass = 0) we cannot guarantee that a parent item has been - * imported prior to its children being seen in the stream unless we are certain - * of how the feed is arranged/ordered. - * With $pass = 1, we only pull parent items out of the stream. - * With $pass = 2, we only pull children (comments/likes). + * + * @param array $xml + * The (atom) feed to consume - RSS isn't as fully supported but may work for simple feeds. + * @param $importer + * The contact_record (joined to user_record) of the local user who owns this + * relationship. It is this person's stuff that is going to be updated. + * @param $contact + * The person who is sending us stuff. If not set, we MAY be processing a "follow" activity + * from an external network and MAY create an appropriate contact record. Otherwise, we MUST + * have a contact record. + * @param int $pass by default ($pass = 0) we cannot guarantee that a parent item has been + * imported prior to its children being seen in the stream unless we are certain + * of how the feed is arranged/ordered. + * * With $pass = 1, we only pull parent items out of the stream. + * * With $pass = 2, we only pull children (comments/likes). * * So running this twice, first with pass 1 and then with pass 2 will do the right * thing regardless of feed ordering. This won't be adequate in a fully-threaded * model where comments can have sub-threads. That would require some massive sorting * to get all the feed items into a mostly linear ordering, and might still require - * recursion. + * recursion. */ - -function consume_feed($xml,$importer,&$contact,$pass = 0) { +function consume_feed($xml, $importer, &$contact, $pass = 0) { require_once('library/simplepie/simplepie.inc'); @@ -3361,7 +3433,6 @@ function consume_feed($xml,$importer,&$contact,$pass = 0) { $when = datetime_convert('UTC','UTC','now','Y-m-d H:i:s'); } - if($deleted && is_array($contact)) { $r = q("SELECT * from item where mid = '%s' and author_xchan = '%s' and uid = %d limit 1", dbesc(base64url_encode($mid)), @@ -3376,7 +3447,7 @@ function consume_feed($xml,$importer,&$contact,$pass = 0) { logger('consume_feed: deleting item ' . $item['id'] . ' mid=' . base64url_decode($item['mid']), LOGGER_DEBUG); drop_item($item['id'],false); } - } + } } } } @@ -3407,7 +3478,6 @@ function consume_feed($xml,$importer,&$contact,$pass = 0) { if($pass == 1) continue; - // Have we seen it? If not, import it. $item_id = base64url_encode($item->get_id()); @@ -3418,24 +3488,21 @@ function consume_feed($xml,$importer,&$contact,$pass = 0) { $author['author_name'] = $contact['xchan_name']; if((! x($author,'author_link')) || ($author['author_is_feed'])) $author['author_link'] = $contact['xchan_url']; - if((! x($author,'author_photo'))|| ($author['author_is_feed'])) + if((! x($author,'author_photo'))|| ($author['author_is_feed'])) $author['author_photo'] = $contact['xchan_photo_m']; $datarray['author_xchan'] = ''; if($author['author_link'] != $contact['xchan_url']) { $x = import_author_unknown(array('name' => $author['author_name'],'url' => $author['author_link'],'photo' => array('src' => $author['author_photo']))); - if($x) + if($x) $datarray['author_xchan'] = $x; - } if(! $datarray['author_xchan']) $datarray['author_xchan'] = $contact['xchan_hash']; - $datarray['owner_xchan'] = $contact['xchan_hash']; - $r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1", dbesc($item_id), intval($importer['channel_id']) @@ -3444,8 +3511,8 @@ function consume_feed($xml,$importer,&$contact,$pass = 0) { // 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']) @@ -3459,15 +3526,12 @@ function consume_feed($xml,$importer,&$contact,$pass = 0) { $datarray['parent_mid'] = $parent_mid; $datarray['uid'] = $importer['channel_id']; - - logger('consume_feed: ' . print_r($datarray,true),LOGGER_DATA); $xx = item_store($datarray); $r = $xx['item_id']; continue; } - else { // Head post of a conversation. Have we seen it? If not, import it. @@ -3481,7 +3545,7 @@ function consume_feed($xml,$importer,&$contact,$pass = 0) { $author['author_name'] = $contact['xchan_name']; if((! x($author,'author_link')) || ($author['author_is_feed'])) $author['author_link'] = $contact['xchan_url']; - if((! x($author,'author_photo'))|| ($author['author_is_feed'])) + if((! x($author,'author_photo'))|| ($author['author_is_feed'])) $author['author_photo'] = $contact['xchan_photo_m']; } @@ -3494,17 +3558,14 @@ function consume_feed($xml,$importer,&$contact,$pass = 0) { if($author['author_link'] != $contact['xchan_url']) { $x = import_author_unknown(array('name' => $author['author_name'],'url' => $author['author_link'],'photo' => array('src' => $author['author_photo']))); - if($x) + if($x) $datarray['author_xchan'] = $x; - } if(! $datarray['author_xchan']) $datarray['author_xchan'] = $contact['xchan_hash']; - $datarray['owner_xchan'] = $contact['xchan_hash']; - $r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1", dbesc($item_id), intval($importer['channel_id']) @@ -3513,8 +3574,8 @@ function consume_feed($xml,$importer,&$contact,$pass = 0) { // 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']) @@ -3526,7 +3587,6 @@ function consume_feed($xml,$importer,&$contact,$pass = 0) { continue; } - $datarray['parent_mid'] = $item_id; $datarray['uid'] = $importer['channel_id']; @@ -3537,26 +3597,20 @@ function consume_feed($xml,$importer,&$contact,$pass = 0) { $author['owner_avatar'] = $contact['thumb']; } - logger('consume_feed: author ' . print_r($author,true),LOGGER_DEBUG); - + logger('consume_feed: author ' . print_r($author,true),LOGGER_DEBUG); logger('consume_feed: ' . print_r($datarray,true),LOGGER_DATA); $xx = item_store($datarray); $r = $xx['item_id']; continue; - } } } - - } function update_feed_item($uid,$datarray) { - logger('update_feed_item: not implemented! ' . $uid . ' ' . print_r($datarray,true), LOGGER_DATA); - } @@ -3566,6 +3620,7 @@ function handle_feed($uid,$abook_id,$url) { $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) @@ -3587,13 +3642,13 @@ function atom_author($tag,$name,$uri,$h,$w,$type,$photo) { $o = ''; if(! $tag) return $o; + $name = xmlify($name); $uri = xmlify($uri); $h = intval($h); $w = intval($w); $photo = xmlify($photo); - $o .= "<$tag>\r\n"; $o .= "<name>$name</name>\r\n"; $o .= "<uri>$uri</uri>\r\n"; @@ -3603,13 +3658,12 @@ function atom_author($tag,$name,$uri,$h,$w,$type,$photo) { call_hooks('atom_author', $o); $o .= "</$tag>\r\n"; + return $o; } function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) { - $a = get_app(); - if(! $item['parent']) return; @@ -3622,7 +3676,6 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) { else $body = $item['body']; - $o = "\r\n\r\n<entry>\r\n"; if(is_array($author)) @@ -3656,11 +3709,9 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) { if(($item['item_private']) || strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])) $o .= '<zot:private>' . (($item['item_private']) ? $item['item_private'] : 1) . '</zot:private>' . "\r\n"; - if($item['app']) $o .= '<statusnet:notice_info local_id="' . $item['id'] . '" source="' . xmlify($item['app']) . '" ></statusnet:notice_info>' . "\r\n"; - $verb = construct_verb($item); $o .= '<as:verb>' . xmlify($verb) . '</as:verb>' . "\r\n"; $actobj = construct_activity_object($item); @@ -3684,11 +3735,11 @@ function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) { // $mentioned = get_mentions($item,$tags); // if($mentioned) // $o .= $mentioned; - + call_hooks('atom_entry', $o); $o .= '</entry>' . "\r\n"; - + return $o; } @@ -3711,7 +3762,6 @@ function fix_private_photos($s, $uid, $item = null, $cid = 0) { logger('fix_private_photos: found photo ' . $image, LOGGER_DEBUG); - if(stristr($image , $site . '/photo/')) { // Only embed locally hosted photos $replace = false; @@ -3731,7 +3781,7 @@ function fix_private_photos($s, $uid, $item = null, $cid = 0) { // Check to see if we should replace this photo link with an embedded image // 1. No need to do so if the photo is public // 2. If there's a contact-id provided, see if they're in the access list - // for the photo. If so, embed it. + // for the photo. If so, embed it. // 3. Otherwise, if we have an item, see if the item permissions match the photo // permissions, regardless of order but first check to see if they're an exact // match to save some processing overhead. @@ -3740,7 +3790,7 @@ function fix_private_photos($s, $uid, $item = null, $cid = 0) { if($cid) { $recips = enumerate_permissions($r[0]); if(in_array($cid, $recips)) { - $replace = true; + $replace = true; } } elseif($item) { @@ -3773,7 +3823,7 @@ function fix_private_photos($s, $uid, $item = null, $cid = 0) { } } } - } + } $new_body = $new_body . substr($orig_body, 0, $img_start + $img_st_close) . $image . '[/zmg]'; $orig_body = substr($orig_body, $img_start + $img_st_close + $img_len + strlen('[/zmg]')); @@ -3794,11 +3844,12 @@ function fix_private_photos($s, $uid, $item = null, $cid = 0) { function has_permissions($obj) { if(($obj['allow_cid'] != '') || ($obj['allow_gid'] != '') || ($obj['deny_cid'] != '') || ($obj['deny_gid'] != '')) return true; + return false; } function compare_permissions($obj1,$obj2) { - // first part is easy. Check that these are exactly the same. + // first part is easy. Check that these are exactly the same. if(($obj1['allow_cid'] == $obj2['allow_cid']) && ($obj1['allow_gid'] == $obj2['allow_gid']) && ($obj1['deny_cid'] == $obj2['deny_cid']) @@ -3816,10 +3867,15 @@ function compare_permissions($obj1,$obj2) { return false; } -// returns an array of contact-ids that are allowed to see this object - +/** + * @brief Returns an array of contact-ids that are allowed to see this object. + * + * @param object $obj + * @return array + */ function enumerate_permissions($obj) { require_once('include/group.php'); + $allow_people = expand_acl($obj['allow_cid']); $allow_groups = expand_groups(expand_acl($obj['allow_gid'])); $deny_people = expand_acl($obj['deny_cid']); @@ -3827,6 +3883,7 @@ function enumerate_permissions($obj) { $recipients = array_unique(array_merge($allow_people,$allow_groups)); $deny = array_unique(array_merge($deny_people,$deny_groups)); $recipients = array_diff($recipients,$deny); + return $recipients; } @@ -3843,6 +3900,7 @@ function item_getfeedtags($item) { $ret[] = array('@',$term['url'],$term['term']); } } + return $ret; } @@ -3863,11 +3921,11 @@ function item_getfeedattach($item) { } } } + return $ret; } - function item_expire($uid,$days) { if((! $uid) || ($days < 1)) @@ -3882,13 +3940,17 @@ function item_expire($uid,$days) { $sql_extra = ((intval($expire_network_only)) ? " AND item_wall = 0 " : ""); - $r = q("SELECT * FROM `item` - WHERE `uid` = %d - AND `created` < %s - INTERVAL %s - AND `id` = `parent` + $expire_limit = get_config('system','expire_limit'); + if(! intval($expire_limit)) + $expire_limit = 5000; + + $r = q("SELECT * FROM `item` + WHERE `uid` = %d + AND `created` < %s - INTERVAL %s + AND `id` = `parent` $sql_extra AND item_retained = 0 - AND (item_restrict = 0 ) ", + AND (item_restrict = 0 ) LIMIT $expire_limit ", intval($uid), db_utcnow(), db_quoteinterval(intval($days).' DAY') ); @@ -3923,7 +3985,6 @@ function item_expire($uid,$days) { } // proc_run('php',"include/notifier.php","expire","$uid"); - } function retain_item($id) { @@ -3955,7 +4016,7 @@ function drop_items($items) { // Delete item with given item $id. $interactive means we're running interactively, and must check // permissions to carry out this act. If it is non-interactive, we are deleting something at the -// system's request and do not check permission. This is very important to know. +// system's request and do not check permission. This is very important to know. // Some deletion requests (those coming from remote sites) must be staged. // $stage = 0 => unstaged @@ -3964,7 +4025,6 @@ function drop_items($items) { function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = false) { - $a = get_app(); // locate item to be deleted @@ -3994,6 +4054,11 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal if(local_channel() && local_channel() == $item['uid']) $ok_to_delete = true; + // sys owned item, requires site admin to delete + $sys = get_sys_channel(); + if(is_site_admin() && $sys['channel_id'] == $item['uid']) + $ok_to_delete = true; + // author deletion $observer = $a->get_observer(); if($observer && $observer['xchan_hash'] && ($observer['xchan_hash'] === $item['author_xchan'])) @@ -4001,7 +4066,7 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal if($ok_to_delete) { - // set the deleted flag immediately on this item just in case the + // set the deleted flag immediately on this item just in case the // hook calls a remote process which loops. We'll delete it properly in a second. if(($linked_item) && (! $force)) { @@ -4035,18 +4100,17 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal return 1; // send the notification upstream/downstream as the case may be - // only send notifications to others if this is the owner's wall item. + // only send notifications to others if this is the owner's wall item. - // This isn't optimal. We somehow need to pass to this function whether or not - // to call the notifier, or we need to call the notifier from the calling function. + // This isn't optimal. We somehow need to pass to this function whether or not + // to call the notifier, or we need to call the notifier from the calling function. // We'll rely on the undocumented behaviour that DROPITEM_PHASE1 is (hopefully) only - // set if we know we're going to send delete notifications out to others. + // set if we know we're going to send delete notifications out to others. if((intval($item['item_wall']) && ($stage != DROPITEM_PHASE2)) || ($stage == DROPITEM_PHASE1)) proc_run('php','include/notifier.php','drop',$notify_id); goaway($a->get_baseurl() . '/' . $_SESSION['return_url']); - } else { if(! $interactive) @@ -4054,14 +4118,20 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal notice( t('Permission denied.') . EOL); goaway($a->get_baseurl() . '/' . $_SESSION['return_url']); } - } -// This function does not check for permission and does not send notifications and does not check recursion. -// It merely destroys all resources associated with an item. -// Please do not use without a suitable wrapper. - -function delete_item_lowlevel($item,$stage = DROPITEM_NORMAL,$force = false) { +/** + * @warning This function does not check for permission and does not send + * notifications and does not check recursion. + * It merely destroys all resources associated with an item. + * Please do not use without a suitable wrapper. + * + * @param array $item + * @param int $stage + * @param boolean $force + * @return boolean + */ +function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL, $force = false) { $linked_item = (($item['resource_id']) ? true : false); @@ -4116,15 +4186,13 @@ function delete_item_lowlevel($item,$stage = DROPITEM_NORMAL,$force = false) { break; } - - // immediately remove any undesired profile likes. + // immediately remove any undesired profile likes. q("delete from likes where iid = %d and channel_id = %d", intval($item['id']), intval($item['uid']) ); - // network deletion request. Keep the message structure so that we can deliver delete notifications. // Come back after several days (or perhaps a month) to do the lowlevel delete (DROPITEM_PHASE2). @@ -4146,7 +4214,7 @@ function delete_item_lowlevel($item,$stage = DROPITEM_NORMAL,$force = false) { intval(TERM_OBJ_POST) ); - // FIXME remove notifications for this item + /** @FIXME remove notifications for this item */ return true; } @@ -4167,26 +4235,31 @@ function first_post_date($uid,$wall = false) { // 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; } /** - * modified posted_dates() {below} to arrange the list in years, which we'll eventually - * use to make a menu of years with collapsible sub-menus for the months instead of the + * modified posted_dates() {below} to arrange the list in years, which we'll eventually + * use to make a menu of years with collapsible sub-menus for the months instead of the * current flat list of all representative dates. + * + * @param int $uid + * @param unknown $wall + * @param unknown $mindate + * @return array */ - -function list_post_dates($uid,$wall,$mindate) { +function list_post_dates($uid, $wall, $mindate) { $dnow = datetime_convert('',date_default_timezone_get(),'now','Y-m-d'); if($mindate) - $dthen = datetime_convert('',date_default_timezone_get(),$mindate); + $dthen = datetime_convert('',date_default_timezone_get(), $mindate); else - $dthen = first_post_date($uid,$wall); + $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 + // 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) @@ -4209,6 +4282,7 @@ function list_post_dates($uid,$wall,$mindate) { $ret[$dyear][] = array($str,$end_month,$start_month); $dnow = datetime_convert('','',$dnow . ' -1 month', 'Y-m-d'); } + return $ret; } @@ -4220,7 +4294,7 @@ function posted_dates($uid,$wall) { if(! $dthen) return array(); - // If it's near the end of a long month, backup to the 28th so that in + // 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) @@ -4247,7 +4321,7 @@ function posted_dates($uid,$wall) { function fetch_post_tags($items,$link = false) { $tag_finder = array(); - if($items) { + if($items) { foreach($items as $item) { if(is_array($item)) { if(array_key_exists('item_id',$item)) { @@ -4271,7 +4345,6 @@ function fetch_post_tags($items,$link = false) { ); } - for($x = 0; $x < count($items); $x ++) { if($tags) { foreach($tags as $t) { @@ -4302,7 +4375,6 @@ function fetch_post_tags($items,$link = false) { function zot_feed($uid,$observer_xchan,$arr) { - $result = array(); $mindate = null; $message_id = null; @@ -4315,9 +4387,9 @@ function zot_feed($uid,$observer_xchan,$arr) { $message_id = $arr['message_id']; } - if(! $mindate) $mindate = NULL_DATE; + $mindate = dbesc($mindate); logger('zot_feed: requested for uid ' . $uid . ' from observer ' . $observer_xchan, LOGGER_DEBUG); @@ -4334,12 +4406,11 @@ function zot_feed($uid,$observer_xchan,$arr) { $sql_extra = item_permissions_sql($uid); } + $limit = " LIMIT 100 "; + if($mindate != NULL_DATE) { $sql_extra .= " and ( created > '$mindate' or edited > '$mindate' ) "; - $limit = ""; } - else - $limit = " limit 0, 50 "; if($message_id) { $sql_extra .= " and mid = '" . dbesc($message_id) . "' "; @@ -4348,21 +4419,27 @@ function zot_feed($uid,$observer_xchan,$arr) { $items = array(); + /** @FIXME fix this part for PostgreSQL */ + + if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + return array(); + } + if(is_sys_channel($uid)) { require_once('include/security.php'); - $r = q("SELECT distinct parent, created from item + $r = q("SELECT parent, created from item WHERE uid != %d - and uid in (" . stream_perms_api_uids(PERMS_PUBLIC) . ") AND item_restrict = 0 + and uid in (" . stream_perms_api_uids(PERMS_PUBLIC,10,1) . ") AND item_restrict = 0 AND item_wall = 1 - and item_private = 0 $sql_extra ORDER BY created ASC $limit", + and item_private = 0 $sql_extra GROUP BY parent ORDER BY created ASC $limit", intval($uid) ); } else { - $r = q("SELECT distinct parent, created from item + $r = q("SELECT parent, created from item WHERE uid = %d AND item_restrict = 0 AND item_wall = 1 - $sql_extra ORDER BY created ASC $limit", + $sql_extra GROUP BY parent ORDER BY created ASC $limit", intval($uid) ); } @@ -4370,8 +4447,8 @@ function zot_feed($uid,$observer_xchan,$arr) { if($r) { $parents_str = ids_to_querystr($r,'parent'); $sys_query = ((is_sys_channel($uid)) ? $sql_extra : ''); - - $items = q("SELECT `item`.*, `item`.`id` AS `item_id` FROM `item` + + $items = q("SELECT `item`.*, `item`.`id` AS `item_id` FROM `item` WHERE `item`.`item_restrict` = 0 AND `item`.`parent` IN ( %s ) $sys_query ", dbesc($parents_str) @@ -4383,12 +4460,10 @@ function zot_feed($uid,$observer_xchan,$arr) { $items = fetch_post_tags($items); require_once('include/conversation.php'); $items = conv_sort($items,'ascending'); - } else $items = array(); - logger('zot_feed: number items: ' . count($items),LOGGER_DEBUG); foreach($items as $item) @@ -4409,13 +4484,13 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $sql_nets = ''; $sql_options = ''; $sql_extra2 = ''; - $sql_extra3 = ''; + $sql_extra3 = ''; $def_acl = ''; $item_uids = ' true '; - + if ($arr['uid']) $uid= $arr['uid']; - + if($channel) { $uid = $channel['channel_id']; $uidhash = $channel['channel_hash']; @@ -4431,61 +4506,60 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $sql_extra = " AND item.parent IN ( SELECT parent FROM item WHERE item_thread_top = 1 $sql_options ) "; if($arr['since_id']) - $sql_extra .= " and item.id > " . $since_id . " "; - - if($arr['gid'] && $uid) { - $r = q("SELECT * FROM `groups` WHERE id = %d AND uid = %d LIMIT 1", - intval($arr['group']), - intval($uid) - ); - if(! $r) { + $sql_extra .= " and item.id > " . $since_id . " "; + + if($arr['gid'] && $uid) { + $r = q("SELECT * FROM `groups` WHERE id = %d AND uid = %d LIMIT 1", + intval($arr['group']), + intval($uid) + ); + if(! $r) { $result['message'] = t('Collection not found.'); return $result; - } + } $contact_str = ''; - $contacts = group_get_members($group); - if($contacts) { + /** @FIXME $group is undefined */ + $contacts = group_get_members($group); + if ($contacts) { foreach($contacts as $c) { if($contact_str) $contact_str .= ','; - $contact_str .= "'" . $c['xchan'] . "'"; + + $contact_str .= "'" . $c['xchan'] . "'"; } - } - else { - $contact_str = ' 0 '; + } else { + $contact_str = ' 0 '; $result['message'] = t('Collection is empty.'); return $result; - } + } - $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str)) or allow_gid like '" . protect_sprintf('%<' . dbesc($r[0]['hash']) . '>%') . "' ) and id = parent and item_restrict = 0 ) "; + $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str)) or allow_gid like '" . protect_sprintf('%<' . dbesc($r[0]['hash']) . '>%') . "' ) and id = parent and item_restrict = 0 ) "; $x = group_rec_byhash($uid,$r[0]['hash']); $result['headline'] = sprintf( t('Collection: %s'),$x['name']); + } + elseif($arr['cid'] && $uid) { - } - elseif($arr['cid'] && $uid) { - - $r = q("SELECT abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d and not ( abook_flags & " . intval(ABOOK_FLAG_BLOCKED) . ")>0 limit 1", + $r = q("SELECT abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d and not ( abook_flags & " . intval(ABOOK_FLAG_BLOCKED) . ")>0 limit 1", intval($arr['cid']), intval(local_channel()) - ); - if($r) { - $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND uid = " . intval($arr['uid']) . " AND ( author_xchan = '" . dbesc($r[0]['abook_xchan']) . "' or owner_xchan = '" . dbesc($r[0]['abook_xchan']) . "' ) and item_restrict = 0 ) "; + ); + if ($r) { + $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND uid = " . intval($arr['uid']) . " AND ( author_xchan = '" . dbesc($r[0]['abook_xchan']) . "' or owner_xchan = '" . dbesc($r[0]['abook_xchan']) . "' ) and item_restrict = 0 ) "; $result['headline'] = sprintf( t('Connection: %s'),$r[0]['xchan_name']); - } - else { + } else { $result['message'] = t('Connection not found.'); return $result; - } - } + } + } - if($arr['datequery']) { - $sql_extra3 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$arr['datequery'])))); - } - if($arr['datequery2']) { - $sql_extra3 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$arr['datequery2'])))); - } + if ($arr['datequery']) { + $sql_extra3 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$arr['datequery'])))); + } + if ($arr['datequery2']) { + $sql_extra3 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$arr['datequery2'])))); + } if(! array_key_exists('nouveau',$arr)) { $sql_extra2 = " AND item.parent = item.id "; @@ -4493,6 +4567,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C } if($arr['search']) { + if(strpos($arr['search'],'#') === 0) $sql_extra .= term_query('item',substr($arr['search'],1),TERM_HASHTAG); else @@ -4511,24 +4586,20 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C ); } + if (($client_mode & CLIENT_MODE_UPDATE) && (! ($client_mode & CLIENT_MODE_LOAD))) { + // only setup pagination on initial page view + $pager_sql = ''; + } else { + $itemspage = (($channel) ? get_pconfig($uid,'system','itemspage') : 20); + $a->set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(get_app()->pager['itemspage']), intval(get_app()->pager['start'])); + } - if(($client_mode & CLIENT_MODE_UPDATE) && (! ($client_mode & CLIENT_MODE_LOAD))) { - - // only setup pagination on initial page view - $pager_sql = ''; - - } - else { - $itemspage = (($channel) ? get_pconfig($uid,'system','itemspage') : 20); - $a->set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); - $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(get_app()->pager['itemspage']), intval(get_app()->pager['start'])); - } - - if(isset($arr['start']) && isset($arr['records'])) - $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval($arr['records']), intval($arr['start'])); + if (isset($arr['start']) && isset($arr['records'])) + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval($arr['records']), intval($arr['start'])); - if(array_key_exists('cmin',$arr) || array_key_exists('cmax',$arr)) { - if(($arr['cmin'] != 0) || ($arr['cmax'] != 99)) { + if (array_key_exists('cmin',$arr) || array_key_exists('cmax',$arr)) { + if (($arr['cmin'] != 0) || ($arr['cmax'] != 99)) { // Not everybody who shows up in the network stream will be in your address book. // By default those that aren't are assumed to have closeness = 99; but this isn't @@ -4537,21 +4608,22 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $sql_nets .= " AND "; - if($arr['cmax'] == 99) + if ($arr['cmax'] == 99) $sql_nets .= " ( "; $sql_nets .= "( abook.abook_closeness >= " . intval($arr['cmin']) . " "; $sql_nets .= " AND abook.abook_closeness <= " . intval($arr['cmax']) . " ) "; - if($cmax == 99) + /** @fixme dead code, $cmax is undefined */ + if ($cmax == 99) $sql_nets .= " OR abook.abook_closeness IS NULL ) "; - } + } } $simple_update = (($client_mode & CLIENT_MODE_UPDATE) ? " and item.item_unseen = 1 " : ''); if($client_mode & CLIENT_MODE_LOAD) $simple_update = ''; - $start = dba_timer(); + //$start = dba_timer(); require_once('include/security.php'); $sql_extra .= item_permissions_sql($channel['channel_id']); @@ -4561,33 +4633,31 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C else $item_restrict = " AND item_type = 0 "; + if ($arr['nouveau'] && ($client_mode & CLIENT_MODE_LOAD) && $channel) { + // "New Item View" - show all items unthreaded in reverse created date order - if($arr['nouveau'] && ($client_mode & CLIENT_MODE_LOAD) && $channel) { - // "New Item View" - show all items unthreaded in reverse created date order - - $items = q("SELECT item.*, item.id AS item_id FROM item - WHERE $item_uids $item_restrict - $simple_update - $sql_extra $sql_nets - ORDER BY item.received DESC $pager_sql " - ); + $items = q("SELECT item.*, item.id AS item_id FROM item + WHERE $item_uids $item_restrict + $simple_update + $sql_extra $sql_nets + ORDER BY item.received DESC $pager_sql" + ); - require_once('include/items.php'); + require_once('include/items.php'); - xchan_query($items); + xchan_query($items); - $items = fetch_post_tags($items,true); - } - else { + $items = fetch_post_tags($items,true); + } else { - // Normal conversation view + // Normal conversation view - if($arr['order'] === 'post') + if($arr['order'] === 'post') $ordering = "created"; - else + else $ordering = "commented"; - if(($client_mode & CLIENT_MODE_LOAD) || ($client_mode == CLIENT_MODE_NORMAL)) { + if(($client_mode & CLIENT_MODE_LOAD) || ($client_mode == CLIENT_MODE_NORMAL)) { // Fetch a page full of parent items for this page @@ -4600,7 +4670,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C ORDER BY item.$ordering DESC $pager_sql ", intval(ABOOK_FLAG_BLOCKED) ); - + } else { // update @@ -4613,48 +4683,46 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C ); } - $first = dba_timer(); + //$first = dba_timer(); - // Then fetch all the children of the parents that are on this page + // Then fetch all the children of the parents that are on this page - if($r) { + if($r) { - $parents_str = ids_to_querystr($r,'item_id'); + $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 ) - $sql_extra ", - dbesc($parents_str) - ); + $items = q("SELECT item.*, item.id AS item_id FROM item + WHERE $item_uids $item_restrict + AND item.parent IN ( %s ) + $sql_extra ", + dbesc($parents_str) + ); - $second = dba_timer(); + //$second = dba_timer(); - xchan_query($items); + xchan_query($items); - $third = dba_timer(); + //$third = dba_timer(); - $items = fetch_post_tags($items,true); + $items = fetch_post_tags($items,true); - $fourth = dba_timer(); + //$fourth = dba_timer(); require_once('include/conversation.php'); - $items = conv_sort($items,$ordering); - - //logger('items: ' . print_r($items,true)); + $items = conv_sort($items,$ordering); - } - else { - $items = array(); - } + //logger('items: ' . print_r($items,true)); + } else { + $items = array(); + } - if($parents_str && $arr['mark_seen']) - $update_unseen = ' AND parent IN ( ' . dbesc($parents_str) . ' )'; - // FIXME finish mark unseen sql - } + if($parents_str && $arr['mark_seen']) + $update_unseen = ' AND parent IN ( ' . dbesc($parents_str) . ' )'; + /** @FIXME finish mark unseen sql */ + } return $items; } @@ -4675,11 +4743,11 @@ function update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remo $pagetitle = $remote_id; } - if($page_type) { + if($page_type) { - // store page info as an alternate message_id so we can access it via + // store page info as an alternate message_id so we can access it via // https://sitename/page/$channelname/$pagetitle - // if no pagetitle was given or it couldn't be transliterated into a url, use the first + // if no pagetitle was given or it couldn't be transliterated into a url, use the first // sixteen bytes of the mid - which makes the link portable and not quite as daunting // as the entire mid. If it were the post_id the link would be less portable. @@ -4703,17 +4771,17 @@ function update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remo ); } } - } - /** - * change access control for item with message_id $mid and channel_id $uid + * @brief Change access control for item with message_id $mid and channel_id $uid. + * + * @param string $xchan_hash + * @param string $mid + * @param int $uid */ - - -function item_add_cid($xchan_hash,$mid,$uid) { +function item_add_cid($xchan_hash, $mid, $uid) { $r = q("select id from item where mid = '%s' and uid = %d and allow_cid like '%s'", dbesc($mid), intval($uid), @@ -4744,7 +4812,7 @@ function item_remove_cid($xchan_hash,$mid,$uid) { } // Set item permissions based on results obtained from linkify_tags() -function set_linkified_perms($linkified, &$str_contact_allow, &$str_group_allow, $profile_uid, $parent_item = false) { +function set_linkified_perms($linkified, &$str_contact_allow, &$str_group_allow, $profile_uid, $parent_item = false, &$private) { $first_access_tag = true; foreach($linkified as $x) { @@ -4754,9 +4822,9 @@ function set_linkified_perms($linkified, &$str_contact_allow, &$str_group_allow, if ($first_access_tag && (! get_pconfig($profile_uid,'system','no_private_mention_acl_override'))) { // This is a tough call, hence configurable. The issue is that one can type in a @!privacy mention - // and also have a default ACL (perhaps from viewing a collection) and could be suprised that the + // and also have a default ACL (perhaps from viewing a collection) and could be suprised that the // privacy mention wasn't the only recipient. So the default is to wipe out the existing ACL if a - // private mention is found. This can be over-ridden if you wish private mentions to be in + // private mention is found. This can be over-ridden if you wish private mentions to be in // addition to the current ACL settings. $str_contact_allow = ''; @@ -4765,12 +4833,30 @@ function set_linkified_perms($linkified, &$str_contact_allow, &$str_group_allow, } if(strpos($access_tag,'cid:') === 0) { $str_contact_allow .= '<' . substr($access_tag,4) . '>'; - $access_tag = ''; + $access_tag = ''; + $private = 1; } elseif(strpos($access_tag,'gid:') === 0) { $str_group_allow .= '<' . substr($access_tag,4) . '>'; - $access_tag = ''; + $access_tag = ''; + $private = 1; } } } } + +/** + * We can't trust ITEM_ORIGIN to tell us if this is a local comment + * which needs to be relayed, because it was misconfigured at one point for several + * months and set for some remote items (in alternate delivery chains). This could + * cause looping, so use this hackish but accurate method. + * + * @param array $item + * @return boolean + */ +function comment_local_origin($item) { + if(stripos($item['mid'], get_app()->get_hostname()) && ($item['parent'] != $item['id'])) + return true; + + return false; +} |