diff options
Diffstat (limited to 'include/items.php')
-rw-r--r-- | include/items.php | 705 |
1 files changed, 254 insertions, 451 deletions
diff --git a/include/items.php b/include/items.php index d6dd517ba..8a2faa623 100644 --- a/include/items.php +++ b/include/items.php @@ -10,18 +10,19 @@ use Zotlabs\Lib\MarkdownSoap; use Zotlabs\Lib\MessageFilter; use Zotlabs\Lib\ThreadListener; use Zotlabs\Lib\IConfig; +use Zotlabs\Lib\PConfig; use Zotlabs\Lib\Activity; use Zotlabs\Lib\Libsync; use Zotlabs\Lib\Libzot; +use Zotlabs\Lib\ActivityStreams; use Zotlabs\Access\PermissionLimits; use Zotlabs\Access\PermissionRoles; -use Zotlabs\Access\AccessList; +use Zotlabs\Lib\AccessList; use Zotlabs\Daemon\Master; require_once('include/bbcode.php'); require_once('include/oembed.php'); require_once('include/crypto.php'); -require_once('include/message.php'); require_once('include/feedutils.php'); require_once('include/photo/photo_driver.php'); require_once('include/permissions.php'); @@ -36,8 +37,6 @@ require_once('include/permissions.php'); */ function collect_recipients($item, &$private_envelope,$include_groups = true) { - require_once('include/group.php'); - $private_envelope = ((intval($item['item_private'])) ? true : false); $recipients = array(); @@ -48,7 +47,7 @@ function collect_recipients($item, &$private_envelope,$include_groups = true) { $allow_people = expand_acl($item['allow_cid']); if($include_groups) { - $allow_groups = expand_groups(expand_acl($item['allow_gid'])); + $allow_groups = AccessList::expand(expand_acl($item['allow_gid'])); } else { $allow_groups = []; @@ -73,7 +72,7 @@ function collect_recipients($item, &$private_envelope,$include_groups = true) { } $deny_people = expand_acl($item['deny_cid']); - $deny_groups = expand_groups(expand_acl($item['deny_gid'])); + $deny_groups = AccessList::expand(expand_acl($item['deny_gid'])); $deny = array_unique(array_merge($deny_people,$deny_groups)); @@ -132,7 +131,7 @@ function collect_recipients($item, &$private_envelope,$include_groups = true) { case 'sit': case 'any': case 'con': - if(!in_array($rr['xchan_network'], ['zot6', 'zot'])) + if($rr['xchan_network'] !== 'zot6') break; case 'pub': case '': @@ -345,6 +344,7 @@ function can_comment_on_post($observer_xchan, $item) { return true; break; case 'any connections': + case 'specific': case 'contacts': case '': if(local_channel() && get_abconfig(local_channel(),$item['owner_xchan'],'their_perms','post_comments')) { @@ -477,7 +477,7 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) { $arr['comment_policy'] = map_scope(PermissionLimits::Get($channel['channel_id'],'post_comments')); if ((! $arr['plink']) && (intval($arr['item_thread_top']))) { - $arr['plink'] = substr(z_root() . '/channel/' . $channel['channel_address'] . '/' . (filter_var($arr['mid'], FILTER_VALIDATE_URL) === false ? '?f=&mid=' : '') . urlencode($arr['mid']),0,190); + $arr['plink'] = $arr['mid']; } @@ -758,35 +758,17 @@ function get_item_elements($x,$allow_code = false) { // and not enough info to be able to look you up from your hash - which is the only thing stored with the post. $xchan_hash = import_author_xchan($x['author']); - if($xchan_hash) { + if($xchan_hash) $arr['author_xchan'] = $xchan_hash; - } - else { + else return []; - } - - // save a potentially expensive lookup if author == owner - $legacy_sig = false; - $owner_hash = ''; - if(isset($x['owner']['id']) && isset($x['owner']['key']) && isset($x['owner']['network']) && $x['owner']['network'] === 'zot6') { - $owner_hash = Libzot::make_xchan_hash($x['owner']['id'], $x['owner']['key']); - } - else { - $owner_hash = make_xchan_hash($x['owner']['guid'],$x['owner']['guid_sig']); - $legacy_sig = true; - } - if($arr['author_xchan'] === $owner_hash) { - $arr['owner_xchan'] = $arr['author_xchan']; + $xchan_hash = import_author_xchan($x['owner']); + if($xchan_hash) { + $arr['owner_xchan'] = $xchan_hash; } else { - $xchan_hash = import_author_xchan($x['owner']); - if($xchan_hash) { - $arr['owner_xchan'] = $xchan_hash; - } - else { - return []; - } + return []; } // Check signature on the body text received. @@ -800,20 +782,12 @@ function get_item_elements($x,$allow_code = false) { // check the supplied signature against the supplied content. // Note that we will purify the content which could change it. - $r = q("select xchan_pubkey, xchan_network from xchan where xchan_hash = '%s' limit 1", + $r = q("SELECT xchan_pubkey FROM xchan WHERE xchan_hash = '%s' LIMIT 1", dbesc($arr['author_xchan']) ); - if($r) { - if($r[0]['xchan_pubkey'] && $r[0]['xchan_network'] === 'zot6') { - $item_verified = false; - if($legacy_sig) { - $item_verified = Crypto::verify($x['body'], base64url_decode($arr['sig']), $r[0]['xchan_pubkey']); - } - else { - $item_verified = Libzot::verify($x['body'], $arr['sig'], $r[0]['xchan_pubkey']); - } - - if($item_verified) { + if ($r) { + if ($r[0]['xchan_pubkey']) { + if (Libzot::verify($x['body'], $arr['sig'], $r[0]['xchan_pubkey'])) { $arr['item_verified'] = 1; } else { @@ -935,71 +909,37 @@ function get_item_elements($x,$allow_code = false) { function import_author_xchan($x) { - $arr = [ - 'xchan' => $x, - 'xchan_hash' => '' - ]; - /** - * @hooks import_author_xchan - * Called when looking up an author of a post by xchan_hash to ensure they have an xchan record on our site. - * * \e array \b xchan - * * \e string \b xchan_hash - Thre returned value - */ - call_hooks('import_author_xchan', $arr); - if($arr['xchan_hash']) { - return $arr['xchan_hash']; + if (!$x) { + return false; } $y = false; - if((isset($x['id']) && isset($x['key'])) && (!isset($x['network']) || $x['network'] === 'zot6')) { + if (!array_key_exists('network', $x) || $x['network'] === 'zot6') { $y = Libzot::import_author_zot($x); } - if(!$y && isset($x['url']) && isset($x['network']) && $x['network'] === 'zot6') { - $r = q("SELECT xchan_hash FROM xchan WHERE xchan_url = '%s' AND xchan_network = 'zot6'", - dbesc($x['url']) - ); - if($r) - $y = $r[0]['xchan_hash']; - else - $y = discover_by_webbie($x['url'], 'zot6'); - } - - // if we were told that it's a zot6 connection, don't probe/import anything else - - if($y) + // if we were told that it's a zot connection, don't probe/import anything else + if (array_key_exists('network', $x) && $x['network'] === 'zot6') return $y; - if(!isset($x['network']) || $x['network'] === 'zot') { - $y = import_author_zot($x); - } - - if(isset($x['network']) || $x['network'] === 'zot') { - if($x['url']) { - // check if we already have the zot6 xchan of this xchan_url. if not import it. - $r = q("SELECT xchan_hash FROM xchan WHERE xchan_url = '%s' AND xchan_network = 'zot6'", - dbesc($x['url']) - ); - // TODO: fix dupplicate with line 960 - if(!$r) - discover_by_webbie($x['url'], 'zot6'); - } - - if($y) - return $y; - - } + $hookinfo = [ + 'xchan' => $x, + 'xchan_hash' => '' + ]; - // perform zot6 discovery - if($x['url']) { - $y = discover_by_webbie($x['url'], 'zot6'); - if($y) { - return $y; - } + /** + * @hooks import_author_xchan + * Called when looking up an author of a post by xchan_hash to ensure they have an xchan record on our site. + * * \e array \b xchan + * * \e string \b xchan_hash - Thre returned value + */ + call_hooks('import_author_xchan', $hookinfo); + if($hookinfo['xchan_hash']) { + return $hookinfo['xchan_hash']; } - if($x['network'] === 'rss') { + if(!$y && array_key_exists('network', $x) && $x['network'] === 'rss') { $y = import_author_rss($x); } @@ -1133,21 +1073,6 @@ function encode_item($item,$mirror = false,$zap_compat = false) { $x['type'] = 'activity'; $x['encoding'] = 'zot'; - $r = q("select channel_id from channel where channel_id = %d limit 1", - intval($item['uid']) - ); - - if($r) - $comment_scope = PermissionLimits::Get($item['uid'],'post_comments'); - else - $comment_scope = 0; - - $scope = $item['public_policy']; - if(! $scope) - $scope = 'public'; - - $c_scope = map_scope($comment_scope); - $key = get_config('system','prvkey'); // If we're trying to backup an item so that it's recoverable or for export/imprt, @@ -1240,10 +1165,7 @@ function encode_item($item,$mirror = false,$zap_compat = false) { $x['public_scope'] = $scope; - if($item['item_nocomment']) - $x['comment_scope'] = 'none'; - else - $x['comment_scope'] = $c_scope; + $x['comment_scope'] = $item['comment_policy']; if(! empty($item['term'])) $x['tags'] = encode_item_terms($item['term'],$mirror); @@ -1287,6 +1209,9 @@ function map_scope($scope, $strip = false) { return 'site: ' . App::get_hostname(); case PERMS_PENDING: return 'any connections'; +// uncomment after Hubzilla version 7.0 is running on the majority of active hubs +// case PERMS_SPECIFIC: +// return 'specific'; case PERMS_CONTACTS: default: return 'contacts'; @@ -1325,16 +1250,13 @@ function translate_scope($scope) { * @return array an associative array */ function encode_item_xchan($xchan) { - $ret = array(); + $ret = []; $ret['name'] = $xchan['xchan_name']; $ret['address'] = $xchan['xchan_addr']; $ret['url'] = $xchan['xchan_url']; $ret['network'] = $xchan['xchan_network']; $ret['photo'] = [ 'mimetype' => $xchan['xchan_photo_mimetype'], 'src' => $xchan['xchan_photo_m'] ]; - $ret['guid'] = $xchan['xchan_guid']; - $ret['guid_sig'] = $xchan['xchan_guid_sig']; - $ret['id'] = $xchan['xchan_guid']; $ret['id_sig'] = $xchan['xchan_guid_sig']; $ret['key'] = $xchan['xchan_pubkey']; @@ -1507,7 +1429,7 @@ 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((string)$x, ENT_COMPAT, 'UTF-8', false); } return $ret; } @@ -1566,143 +1488,6 @@ function encode_item_flags($item) { return $ret; } -function encode_mail($item,$extended = false) { - $x = []; - $x['type'] = 'mail'; - $x['encoding'] = 'zot'; - - if(array_key_exists('mail_obscured',$item) && intval($item['mail_obscured'])) { - if($item['title']) - $item['title'] = base64url_decode(str_rot47($item['title'])); - if($item['body']) - $item['body'] = base64url_decode(str_rot47($item['body'])); - } - - $x['message_id'] = $item['mid']; - $x['message_parent'] = $item['parent_mid']; - $x['created'] = $item['created']; - $x['expires'] = $item['expires']; - $x['title'] = $item['title']; - $x['body'] = $item['body']; - $x['from'] = encode_item_xchan($item['from']); - $x['to'] = encode_item_xchan($item['to']); - $x['raw'] = $item['mail_raw']; - $x['mimetype'] = $item['mail_mimetype']; - $x['sig'] = $item['sig']; - - if($item['attach']) - $x['attach'] = json_decode($item['attach'],true); - - $x['flags'] = array(); - - if(intval($item['mail_recalled'])) { - $x['flags'][] = 'recalled'; - $x['title'] = ''; - $x['body'] = ''; - } - - if($extended) { - $x['conv_guid'] = $item['conv_guid']; - if(intval($item['mail_deleted'])) - $x['flags'][] = 'deleted'; - if(intval($item['mail_replied'])) - $x['flags'][] = 'replied'; - if(intval($item['mail_isreply'])) - $x['flags'][] = 'isreply'; - if(intval($item['mail_seen'])) - $x['flags'][] = 'seen'; - } - - return $x; -} - - - -function get_mail_elements($x) { - - $arr = array(); - - if(intval($x['raw'])) { - $arr['mail_raw'] = intval($x['raw']); - $arr['body'] = $x['body']; - } - else { - $arr['body'] = (($x['body']) ? htmlspecialchars($x['body'], ENT_COMPAT,'UTF-8',false) : ''); - - $maxlen = get_max_import_size(); - - if($maxlen && mb_strlen($arr['body']) > $maxlen) { - $arr['body'] = mb_substr($arr['body'],0,$maxlen,'UTF-8'); - logger('message length exceeds max_import_size: truncated'); - } - } - - $arr['title'] = (($x['title'])? htmlspecialchars($x['title'],ENT_COMPAT,'UTF-8',false) : ''); - $arr['mail_mimetype'] = (($x['mimetype']) ? htmlspecialchars($x['mimetype'],ENT_COMPAT,'UTF-8',false) : 'text/bbcode'); - $arr['conv_guid'] = (($x['conv_guid'])? htmlspecialchars($x['conv_guid'],ENT_COMPAT,'UTF-8',false) : ''); - - $arr['created'] = datetime_convert('UTC','UTC',$x['created']); - if((! array_key_exists('expires',$x)) || ($x['expires'] <= NULL_DATE)) - $arr['expires'] = NULL_DATE; - else - $arr['expires'] = datetime_convert('UTC','UTC',$x['expires']); - - $arr['mail_flags'] = 0; - - if(array_key_exists('sig',$x)) - $arr['sig'] = $x['sig']; - - if($x['flags'] && is_array($x['flags'])) { - if(in_array('recalled',$x['flags'])) { - $arr['mail_recalled'] = 1; - } - if(in_array('replied',$x['flags'])) { - $arr['mail_replied'] = 1; - } - if(in_array('isreply',$x['flags'])) { - $arr['mail_isreply'] = 1; - } - if(in_array('seen',$x['flags'])) { - $arr['mail_seen'] = 1; - } - if(in_array('deleted',$x['flags'])) { - $arr['mail_deleted'] = 1; - } - } - - $key = get_config('system','pubkey'); - $arr['mail_obscured'] = 1; - if($arr['body']) { - $arr['body'] = str_rot47(base64url_encode($arr['body'])); - } - - if($arr['title']) { - $arr['title'] = str_rot47(base64url_encode($arr['title'])); - } - if($arr['created'] > datetime_convert()) - $arr['created'] = datetime_convert(); - - - $arr['mid'] = (($x['message_id']) ? htmlspecialchars($x['message_id'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['parent_mid'] = (($x['message_parent']) ? htmlspecialchars($x['message_parent'], ENT_COMPAT,'UTF-8',false) : ''); - - if($x['attach']) - $arr['attach'] = activity_sanitise($x['attach']); - - if(($xchan_hash = import_author_xchan($x['from'])) !== false) - $arr['from_xchan'] = $xchan_hash; - else - return array(); - - if(($xchan_hash = import_author_xchan($x['to'])) !== false) - $arr['to_xchan'] = $xchan_hash; - else - return array(); - - return $arr; -} - - function get_profile_elements($x) { $arr = array(); @@ -1823,9 +1608,9 @@ function item_store($arr, $allow_exec = false, $deliver = true) { return $ret; } - $arr['title'] = ((array_key_exists('title',$arr) && strlen($arr['title'])) ? trim($arr['title']) : ''); - $arr['summary'] = ((array_key_exists('summary',$arr) && strlen($arr['summary'])) ? trim($arr['summary']) : ''); - $arr['body'] = ((array_key_exists('body',$arr) && strlen($arr['body'])) ? trim($arr['body']) : ''); + $arr['title'] = ((array_key_exists('title',$arr) && $arr['title']) ? trim($arr['title']) : ''); + $arr['summary'] = ((array_key_exists('summary',$arr) && $arr['summary']) ? trim($arr['summary']) : ''); + $arr['body'] = ((array_key_exists('body',$arr) && $arr['body']) ? trim($arr['body']) : ''); $arr['allow_cid'] = ((x($arr,'allow_cid')) ? trim($arr['allow_cid']) : ''); $arr['allow_gid'] = ((x($arr,'allow_gid')) ? trim($arr['allow_gid']) : ''); @@ -2416,9 +2201,9 @@ function item_store_update($arr, $allow_exec = false, $deliver = true) { $arr['deny_gid'] = ((array_key_exists('deny_gid',$arr)) ? trim($arr['deny_gid']) : $orig[0]['deny_gid']); $arr['item_private'] = ((array_key_exists('item_private',$arr)) ? intval($arr['item_private']) : $orig[0]['item_private']); - $arr['title'] = ((array_key_exists('title',$arr) && strlen($arr['title'])) ? trim($arr['title']) : ''); - $arr['body'] = ((array_key_exists('body',$arr) && strlen($arr['body'])) ? trim($arr['body']) : ''); - $arr['html'] = ((array_key_exists('html',$arr) && strlen($arr['html'])) ? trim($arr['html']) : ''); + $arr['title'] = ((array_key_exists('title',$arr) && $arr['title']) ? trim($arr['title']) : ''); + $arr['body'] = ((array_key_exists('body',$arr) && $arr['body']) ? trim($arr['body']) : ''); + $arr['html'] = ((array_key_exists('html',$arr) && $arr['html']) ? trim($arr['html']) : ''); $arr['attach'] = ((array_key_exists('attach',$arr)) ? notags(trim($arr['attach'])) : $orig[0]['attach']); $arr['app'] = ((array_key_exists('app',$arr)) ? notags(trim($arr['app'])) : $orig[0]['app']); @@ -2624,9 +2409,14 @@ function send_status_notifications($post_id,$item) { $unfollowed = false; $parent = 0; + $is_reaction = false; + + $type = ((intval($item['item_private']) === 2) ? NOTIFY_MAIL : NOTIFY_COMMENT); if(array_key_exists('verb',$item) && (activity_match($item['verb'], ACTIVITY_LIKE) || activity_match($item['verb'], ACTIVITY_DISLIKE))) { + $type = NOTIFY_LIKE; + $r = q("select id from item where mid = '%s' and uid = %d limit 1", dbesc($item['thr_parent']), intval($item['uid']) @@ -2695,7 +2485,7 @@ function send_status_notifications($post_id,$item) { Enotify::submit(array( - 'type' => NOTIFY_COMMENT, + 'type' => $type, 'from_xchan' => $item['author_xchan'], 'to_xchan' => $r[0]['channel_hash'], 'item' => $item, @@ -2733,12 +2523,7 @@ function get_item_contact($item,$contacts) { */ function tag_deliver($uid, $item_id) { - $role = get_pconfig($uid,'system','permissions_role'); - $rolesettings = PermissionRoles::role_perms($role); - $channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal'; - - $is_group = (($channel_type === 'group') ? true : false); - + $is_group = get_pconfig($uid, 'system', 'group_actor'); $mention = false; /* @@ -2775,15 +2560,18 @@ function tag_deliver($uid, $item_id) { } if ($is_group && intval($item['item_private']) === 2 && intval($item['item_thread_top'])) { - // do not turn the groups own direkt messages into group items if($item['item_wall'] && $item['author_xchan'] === $u[0]['channel_hash']) return; // group delivery via DM - if(perm_is_allowed($uid,$item['owner_xchan'],'post_wall') || perm_is_allowed($uid,$item['owner_xchan'],'tag_deliver')) { + if(perm_is_allowed($uid,$item['owner_xchan'],'post_wall')) { logger('group DM delivery for ' . $u[0]['channel_address']); start_delivery_chain($u[0], $item, $item_id, 0, true, (($item['edited'] != $item['created']) || $item['item_deleted'])); + q("update item set item_blocked = %d where id = %d", + intval(ITEM_HIDDEN), + intval($item_id) + ); } return; } @@ -2796,13 +2584,6 @@ function tag_deliver($uid, $item_id) { return; } - /* this should not be required anymore due to the check above - if (strpos($item['body'],'[/share]')) { - logger('W2W post already shared'); - return; - } - */ - // group delivery via W2W logger('rewriting W2W post for ' . $u[0]['channel_address']); start_delivery_chain($u[0], $item, $item_id, 0, true, (($item['edited'] != $item['created']) || $item['item_deleted'])); @@ -2873,9 +2654,37 @@ function tag_deliver($uid, $item_id) { intval($uid) ); - if(($x) && intval($x[0]['item_uplink'])) { - start_delivery_chain($u[0],$item,$item_id,$x[0]); + if ($x) { + + // group comments don't normally require a second delivery chain + // but we create a linked Announce so they will show up in the home timeline + // on microblog platforms and this creates a second delivery chain + + if ($is_group && intval($x[0]['item_wall'])) { + // don't let the forked delivery chain recurse + if ($item['verb'] === 'Announce' && $item['author_xchan'] === $u['channel_hash']) { + return; + } + // don't announce moderated content until it has been approved + if (intval($item['item_blocked']) === ITEM_MODERATED) { + return; + } + + // don't boost likes and other response activities as it is likely that + // few platforms will handle this in an elegant way + + if (ActivityStreams::is_response_activity($item['verb'])) { + return; + } + logger('group_comment'); + start_delivery_chain($u[0], $item, $item_id, $x[0], true, (($item['edited'] != $item['created']) || $item['item_deleted'])); + + } + elseif (intval($x[0]['item_uplink'])) { + start_delivery_chain($u,$item,$item_id,$x[0]); + } } + } @@ -2912,7 +2721,6 @@ function tag_deliver($uid, $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. $body = preg_replace('/\[share(.*?)\[\/share\]/','',$item['body']); @@ -3117,13 +2925,7 @@ function item_community_tag($channel,$item) { */ function tgroup_check($uid, $item) { - - $role = get_pconfig($uid,'system','permissions_role'); - $rolesettings = PermissionRoles::role_perms($role); - $channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal'; - - $is_group = (($channel_type === 'group') ? true : false); - + $is_group = get_pconfig($uid, 'system', 'group_actor'); $mention = false; // check that the message originated elsewhere and is a top-level post @@ -3322,6 +3124,10 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false $arr = []; + q("update item set item_hidden = 1 where id = %d", + intval($item_id) + ); + if ($edit) { // process edit or delete action @@ -3352,7 +3158,7 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false } else { $arr['uuid'] = item_message_id(); - $arr['mid'] = z_root() . '/activity/' . $arr['uuid']; + $arr['mid'] = z_root() . '/item/' . $arr['uuid']; $arr['parent_mid'] = $arr['mid']; } @@ -3370,6 +3176,10 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false $arr['item_private'] = (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 1 : 0); + if ($channel['channel_allow_cid'] && empty($channel['channel_allow_gid'])) { + $arr['item_private'] = 2; + } + $arr['item_origin'] = 1; $arr['item_wall'] = 1; $arr['item_thread_top'] = 1; @@ -3379,7 +3189,7 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false "' portable_id='" . $item['author']['xchan_hash'] . "' avatar='" . $item['author']['xchan_photo_s'] . "' link='" . $item['plink'] . - "' auth='" . ((in_array($item['author']['xchan_network'], ['zot6','zot'])) ? 'true' : 'false') . + "' auth='" . (($item['author']['xchan_network'] === 'zot6') ? 'true' : 'false') . "' posted='" . $item['created'] . "' message_id='" . $item['mid'] . "']"; @@ -3389,6 +3199,29 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false $bb .= "[/share]"; $arr['body'] = $bb; + // Conversational objects shouldn't be copied, but other objects should. + if (in_array($item['obj_type'], [ 'Image', 'Event', 'Question' ])) { + $arr['obj'] = $item['obj']; + $t = json_decode($arr['obj'],true); + + if ($t !== NULL) { + $arr['obj'] = $t; + } + $arr['obj']['content'] = bbcode($bb); + $arr['obj']['source']['content'] = $bb; + $arr['obj']['id'] = $arr['mid']; + + if (! array_path_exists('obj/source/mediaType',$arr)) { + $arr['obj']['source']['mediaType'] = 'text/bbcode'; + } + + $arr['obj']['directMessage'] = (intval($arr['item_private']) === 2); + + } + + $arr['tgt_type'] = $item['tgt_type']; + $arr['target'] = $item['target']; + $arr['term'] = $item['term']; $arr['author_xchan'] = $channel['channel_hash']; @@ -3419,6 +3252,92 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false } + if ($group && $parent) { + logger('comment arrived in group', LOGGER_DEBUG); + $arr = []; + + // don't let this recurse. We checked for this before calling, but this ensures + // it doesn't sneak through another way because recursion is nasty. + + if ($item['verb'] === 'Announce' && $item['author_xchan'] === $channel['channel_hash']) { + return; + } + + // Don't send Announce activities for poll responses. + + if ($item['obj_type'] === 'Answer') { + return; + } + + if ($edit) { + if (intval($item['item_deleted'])) { + drop_item($item['id'],false,DROPITEM_PHASE1); + Master::Summon([ 'Notifier','drop',$item['id'] ]); + return; + } + return; + } + else { + $arr['uuid'] = item_message_id(); + $arr['mid'] = z_root() . '/activity/' . $arr['uuid']; + $arr['parent_mid'] = $item['parent_mid']; + //IConfig::Set($arr,'activitypub','context', str_replace('/item/','/conversation/',$item['parent_mid'])); + } + $arr['aid'] = $channel['channel_account_id']; + $arr['uid'] = $channel['channel_id']; + + $arr['verb'] = 'Announce'; + + if (is_array($item['obj'])) { + $arr['obj'] = $item['obj']; + } + elseif (is_string($item['obj']) && strlen($item['obj'])) { + $arr['obj'] = json_decode($item['obj'],true); + } + + if (! $arr['obj']) { + $arr['obj'] = $item['mid']; + } + + if (is_array($arr['obj'])) { + $obj_actor = ((isset($arr['obj']['actor'])) ? ((is_array($arr['obj']['actor'])) ? $arr['obj']['actor']['id'] : $arr['obj']['actor']) : $arr['obj']['attributedTo']); + $mention = Activity::get_actor_bbmention($obj_actor); + $arr['body'] = sprintf( t('🔁 Repeated %1$s\'s %2$s'), $mention, $arr['obj']['type']); + } + + $arr['author_xchan'] = $channel['channel_hash']; + + $arr['item_wall'] = 1; + + $arr['item_private'] = (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 1 : 0); + + $arr['item_origin'] = 1; + $arr['item_hidden'] = 1; + + $arr['item_thread_top'] = 0; + + $arr['allow_cid'] = $channel['channel_allow_cid']; + $arr['allow_gid'] = $channel['channel_allow_gid']; + $arr['deny_cid'] = $channel['channel_deny_cid']; + $arr['deny_gid'] = $channel['channel_deny_gid']; + $arr['comment_policy'] = map_scope(PermissionLimits::Get($channel['channel_id'],'post_comments')); + + $post = item_store($arr); + $post_id = $post['item_id']; + + if ($post_id) { + Master::Summon([ 'Notifier','tgroup',$post_id ]); + } + + q("update channel set channel_lastpost = '%s' where channel_id = %d", + dbesc(datetime_convert()), + intval($channel['channel_id']) + ); + + return; + } + + // 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 @@ -3559,173 +3478,54 @@ function check_item_source($uid, $item) { return false; } -function post_is_importable($item,$abook) { - if(! $abook) - return true; +// Checks an incoming item against the per-channel and per-connection content filter. +// This implements the backend of the 'Content Filter' system app - if(($abook['abook_channel']) && (! feature_enabled($abook['abook_channel'],'connfilter'))) - return true; +function post_is_importable($channel_id, $item, $abook) { - if(! $item) + if (! $item) { return false; - - if(! ($abook['abook_incl'] || $abook['abook_excl'])) - return true; - - return MessageFilter::evaluate($item,$abook['abook_incl'],$abook['abook_excl']); - -} - - -function mail_store($arr) { - - if(! $arr['channel_id']) { - logger('mail_store: no uid'); - return 0; } - $channel = channelx_by_n($arr['channel_id']); - - if(! $arr['mail_obscured']) { - if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false)) - $arr['body'] = escape_tags($arr['body']); - } + $incl = PConfig::get($channel_id, 'system', 'message_filter_incl', EMPTY_STR); + $excl = PConfig::get($channel_id, 'system', 'message_filter_excl', EMPTY_STR); - if(array_key_exists('attach',$arr)) { - if(is_array($arr['attach'])) { - $arr['attach'] = json_encode($arr['attach']); + if ($incl || $excl) { + $x = MessageFilter::evaluate($item, $incl, $excl); + if (! $x) { + logger('MessageFilter: channel blocked content', LOGGER_DEBUG, LOG_INFO); + return false; } } - else { - $arr['attach'] = ''; - } - - $arr['account_id'] = ((x($arr,'account_id')) ? intval($arr['account_id']) : 0); - $arr['mid'] = ((x($arr,'mid')) ? notags(trim($arr['mid'])) : random_string()); - $arr['from_xchan'] = ((x($arr,'from_xchan')) ? notags(trim($arr['from_xchan'])) : ''); - $arr['to_xchan'] = ((x($arr,'to_xchan')) ? notags(trim($arr['to_xchan'])) : ''); - $arr['created'] = ((x($arr,'created') !== false) ? datetime_convert('UTC','UTC',$arr['created']) : datetime_convert()); - $arr['expires'] = ((x($arr,'expires') !== false) ? datetime_convert('UTC','UTC',$arr['expires']) : NULL_DATE); - $arr['title'] = ((x($arr,'title')) ? trim($arr['title']) : ''); - $arr['parent_mid'] = ((x($arr,'parent_mid')) ? notags(trim($arr['parent_mid'])) : ''); - $arr['body'] = ((x($arr,'body')) ? trim($arr['body']) : ''); - $arr['sig'] = ((x($arr,'sig')) ? trim($arr['sig']) : ''); - $arr['conv_guid'] = ((x($arr,'conv_guid')) ? trim($arr['conv_guid']) : ''); - $arr['mail_mimetype'] = ((x($arr,'mail_mimetype')) ? trim($arr['mail_mimetype']) : 'text/bbcode'); - - $arr['mail_flags'] = ((x($arr,'mail_flags')) ? intval($arr['mail_flags']) : 0 ); - $arr['mail_raw'] = ((x($arr,'mail_raw')) ? intval($arr['mail_raw']) : 0 ); - - - if($arr['parent_mid']) { - $parent_item = q("select * from mail where mid = '%s' and channel_id = %d limit 1", - dbesc($arr['parent_mid']), - intval($arr['channel_id']) - ); - if(($parent_item) && (! $arr['conv_guid'])) { - $arr['conv_guid'] = $parent_item[0]['conv_guid']; - } - } - else { - logger('mail_store: missing parent'); - $arr['parent_mid'] = $arr['mid']; - } - - if($arr['from_xchan'] === $channel['channel_hash']) - $conversant = $arr['to_xchan']; - else - $conversant = $arr['from_xchan']; - - - if(! $arr['conv_guid']) { - $x = create_conversation($channel,$conversant,(($arr['title']) ? base64url_decode(str_rot47($arr['title'])) : '')); - $arr['conv_guid'] = (($x) ? $x['guid'] : ''); - } - - - $r = q("SELECT id FROM mail WHERE mid = '%s' AND channel_id = %d LIMIT 1", - dbesc($arr['mid']), - intval($arr['channel_id']) - ); - - if($r) { - logger('Duplicate item ignored. ' . print_r($arr,true)); - return 0; - } - - if(! $r && $arr['mail_recalled'] == 1) { - logger('Recalled item not found. ' . print_r($arr,true)); - return 0; - } - /** - * @hooks post_mail - * Called when a mail message has been composed. - */ - call_hooks('post_mail', $arr); - - if(x($arr,'cancel')) { - logger('Post cancelled by plugin.'); - return 0; + if(!feature_enabled($channel_id, 'connfilter')) { + return true; } - logger('mail_store: ' . print_r($arr,true), LOGGER_DATA); - - create_table_from_array('mail', $arr); - - // find the item we just created - - $r = q("SELECT id FROM mail WHERE mid = '%s' AND channel_id = %d ORDER BY id ASC ", - $arr['mid'], // already dbesc'd - intval($arr['channel_id']) - ); - - if($r) { - $current_post = $r[0]['id']; - logger('Created item ' . $current_post, LOGGER_DEBUG); - $arr['id'] = $current_post; // for notification - } - else { - logger('Could not locate created item'); - return 0; - } - if(count($r) > 1) { - logger('Duplicated post occurred. Removing duplicates.'); - q("DELETE FROM mail WHERE mid = '%s' AND channel_id = %d AND id != %d ", - $arr['mid'], - intval($arr['channel_id']), - intval($current_post) - ); + if (! $abook) { + return true; } - else { - - $notif_params = array( - 'from_xchan' => $arr['from_xchan'], - 'to_xchan' => $arr['to_xchan'], - 'type' => NOTIFY_MAIL, - 'item' => $arr, - 'verb' => ACTIVITY_POST, - 'otype' => 'mail' - ); - Enotify::submit($notif_params); - } + foreach ($abook as $ab) { + // check eligibility + if (intval($ab['abook_self'])) { + continue; + } + if (! ($ab['abook_incl'] || $ab['abook_excl'])) { + continue; + } - if($arr['conv_guid']) { - $c = q("update conv set updated = '%s' where guid = '%s' and uid = %d", - dbesc(datetime_convert()), - dbesc($arr['conv_guid']), - intval($arr['channel_id']) - ); + $evaluator = MessageFilter::evaluate($item, $ab['abook_incl'], $ab['abook_excl']); + // A negative assessment for any individual connections + // is an instant fail + if (! $evaluator) { + logger('MessageFilter: connection blocked content', LOGGER_DEBUG, LOG_INFO); + return false; + } } - /** - * @hooks post_mail_end - * Called when a mail message has been delivered. - */ - call_hooks('post_mail_end', $arr); - return $current_post; + return true; } @@ -3859,12 +3659,11 @@ function compare_permissions($obj1,$obj2) { * @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'])); + $allow_groups = AccessList::expand(expand_acl($obj['allow_gid'])); $deny_people = expand_acl($obj['deny_cid']); - $deny_groups = expand_groups(expand_acl($obj['deny_gid'])); + $deny_groups = AccessList::expand(expand_acl($obj['deny_gid'])); $recipients = array_unique(array_merge($allow_people,$allow_groups)); $deny = array_unique(array_merge($deny_people,$deny_groups)); $recipients = array_diff($recipients,$deny); @@ -4566,6 +4365,9 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $item_uids = " item.uid = " . intval($uid) . " "; } + if($arr['top']) + $sql_options .= " and item_thread_top = 1 "; + if($arr['star']) $sql_options .= " and item_starred = 1 "; @@ -4598,7 +4400,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $contact_str = ''; - $contacts = group_get_members($r[0]['id']); + $contacts = AccessList::members($uid, $r[0]['id']); if ($contacts) { foreach($contacts as $c) { if($contact_str) @@ -4614,7 +4416,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $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 $item_normal ) "; - $x = group_rec_byhash($uid,$r[0]['hash']); + $x = AccessList::by_hash($uid, $r[0]['hash']); $result['headline'] = sprintf( t('Privacy group: %s'),$x['gname']); } elseif($arr['cid'] && $uid) { @@ -4652,7 +4454,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C ); } - if(strlen($arr['file'])) { + if($arr['file']) { $sql_extra .= term_query('item',$arr['files'],TERM_FILE); } @@ -4721,7 +4523,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C if ($arr['total']) { $items = dbq("SELECT count(item.id) AS total FROM item WHERE $item_uids $item_restrict - $simple_update + $simple_update $sql_options $sql_extra $sql_nets $sql_extra3" ); if ($items) { @@ -4732,7 +4534,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $items = dbq("SELECT item.*, item.id AS item_id FROM item WHERE $item_uids $item_restrict - $simple_update + $simple_update $sql_options $sql_extra $sql_nets $sql_extra3 ORDER BY item.received DESC $pager_sql" ); @@ -4986,8 +4788,9 @@ function send_profile_photo_activity($channel,$photo,$profile) { $arr['body'] = sprintf($t,$channel['channel_name'],$ptext) . "\n\n" . $ltext; - $acl = new AccessList($channel); + $acl = new Zotlabs\Access\AccessList($channel); $x = $acl->get(); + $arr['allow_cid'] = $x['allow_cid']; $arr['allow_gid'] = $x['allow_gid']; |