function get() { if (!local_channel()) { notice(t('Permission denied.') . EOL); return; } $channel = \App::get_channel(); $is_owner = local_channel() && local_channel() == $channel['channel_id']; //check for updated items and remove them require_once 'include/sharedwithme.php'; apply_updates(); //drop single file - localuser if (argc() > 2 && argv(2) === 'drop') { $id = intval(argv(1)); q("DELETE FROM item WHERE id = %d AND uid = %d", intval($id), intval(local_channel())); goaway(z_root() . '/sharedwithme'); } //drop all files - localuser if (argc() > 1 && argv(1) === 'dropall') { q("DELETE FROM item WHERE verb = '%s' AND obj_type = '%s' AND uid = %d", dbesc(ACTIVITY_POST), dbesc(ACTIVITY_OBJ_FILE), intval(local_channel())); goaway(z_root() . '/sharedwithme'); } //list files $r = q("SELECT id, uid, object, item_unseen FROM item WHERE verb = '%s' AND obj_type = '%s' AND uid = %d AND owner_xchan != '%s'", dbesc(ACTIVITY_POST), dbesc(ACTIVITY_OBJ_FILE), intval(local_channel()), dbesc($channel['channel_hash'])); $items = array(); $ids = ''; if ($r) { foreach ($r as $rr) { $object = json_decode($rr['object'], true); $item = array(); $item['id'] = $rr['id']; $item['objfiletype'] = $object['filetype']; $item['objfiletypeclass'] = getIconFromType($object['filetype']); $item['objurl'] = rawurldecode(get_rel_link($object['link'], 'alternate')) . '?f=&zid=' . $channel['xchan_addr']; $item['objfilename'] = $object['filename']; $item['objfilesize'] = userReadableSize($object['filesize']); $item['objedited'] = $object['edited']; $item['unseen'] = $rr['item_unseen']; $items[] = $item; if ($item['unseen'] > 0) { $ids .= " '" . $rr['id'] . "',"; } } } if ($ids) { //remove trailing , $ids = rtrim($ids, ","); q("UPDATE item SET item_unseen = 0 WHERE id IN ( {$ids} ) AND uid = %d", intval(local_channel())); } $o = profile_tabs($a, $is_owner, $channel['channel_address']); $o .= replace_macros(get_markup_template('sharedwithme.tpl'), array('$header' => t('Files: shared with me'), '$name' => t('Name'), '$label_new' => t('NEW'), '$size' => t('Size'), '$lastmod' => t('Last Modified'), '$dropall' => t('Remove all files'), '$drop' => t('Remove this file'), '$items' => $items)); return $o; }
/** * @brief * * @param array $sender an associative array with * * \e string \b hash a xchan_hash * @param array $arr an associative array * * \e int \b verb * * \e int \b obj_type * * \e int \b mid * @param int $uid */ function remove_community_tag($sender, $arr, $uid) { if (!(activity_match($arr['verb'], ACTIVITY_TAG) && $arr['obj_type'] == ACTIVITY_OBJ_TAGTERM)) { return; } logger('remove_community_tag: invoked'); if (!get_pconfig($uid, 'system', 'blocktags')) { logger('remove_community tag: permission denied.'); return; } $r = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc($arr['mid']), intval($uid)); if (!$r) { logger('remove_community_tag: no item'); return; } if ($sender['hash'] != $r[0]['owner_xchan'] && $sender['hash'] != $r[0]['author_xchan']) { logger('remove_community_tag: sender not authorised.'); return; } $i = $r[0]; if ($i['target']) { $i['target'] = json_decode_plus($i['target']); } if ($i['object']) { $i['object'] = json_decode_plus($i['object']); } if (!($i['target'] && $i['object'])) { logger('remove_community_tag: no target/object'); return; } $message_id = $i['target']['id']; $r = q("select id from item where mid = '%s' and uid = %d limit 1", dbesc($message_id), intval($uid)); if (!$r) { logger('remove_community_tag: no parent message'); return; } q("delete from term where uid = %d and oid = %d and otype = %d and type = %d and term = '%s' and url = '%s'", intval($uid), intval($r[0]['id']), intval(TERM_OBJ_POST), intval(TERM_HASHTAG), dbesc($i['object']['title']), dbesc(get_rel_link($i['object']['link'], 'alternate'))); }
/** * @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 */ $u = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1", intval($uid)); if (!$u) { return; } $i = q("select * from item where id = %d and uid = %d limit 1", intval($item_id), intval($uid)); if (!$i) { return; } $i = fetch_post_tags($i); $item = $i[0]; if ($item['source_xchan'] && $item['item_flags'] & ITEM_UPLINK && $item['item_flags'] & ITEM_THREAD_TOP && $item['edited'] != $item['created']) { // this is an update (edit) to a post which was already processed by us and has a second delivery chain // Just start the second delivery chain to deliver the updated post proc_run('php', 'include/notifier.php', 'tgroup', $item['id']); return; } /* * Seems like a good place to plug in a poke notification. */ if (stristr($item['verb'], ACTIVITY_POKE)) { $poke_notify = true; 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) { require_once 'include/enotify.php'; notification(array('to_xchan' => $u[0]['channel_hash'], 'from_xchan' => $item['author_xchan'], 'type' => NOTIFY_POKE, 'item' => $item, 'link' => $i[0]['llink'], 'verb' => ACTIVITY_POKE, 'activity' => $verb, 'otype' => 'item')); } } /* * Do community tagging */ if ($item['obj_type'] === ACTIVITY_OBJ_TAGTERM) { // 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')) { logger('tag_deliver: community tag recipient: ' . $u[0]['channel_name']); $j_tgt = json_decode_plus($item['target']); if ($j_tgt && $j_tgt['id']) { $p = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc($j_tgt['id']), intval($u[0]['channel_id'])); if ($p) { $j_obj = json_decode_plus($item['object']); logger('tag_deliver: tag object: ' . print_r($j_obj, true), LOGGER_DATA); if ($j_obj && $j_obj['id'] && $j_obj['title']) { if (is_array($j_obj['link'])) { $taglink = get_rel_link($j_obj['link'], 'alternate'); } store_item_tag($u[0]['channel_id'], $p[0]['id'], TERM_OBJ_POST, TERM_HASHTAG, $j_obj['title'], $j_obj['id']); $x = q("update item set edited = '%s', received = '%s', changed = '%s' where mid = '%s' and uid = %d", dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($j_tgt['id']), intval($u[0]['channel_id'])); proc_run('php', 'include/notifier.php', 'edit_post', $p[0]['id']); } } } } else { logger('tag_deliver: tag permission denied for ' . $u[0]['channel_address']); } } /* * A "union" is a message which our channel has sourced from another channel. * This sets up a second delivery chain just like forum tags do. * Find out if this is a source-able post. */ $union = check_item_source($uid, $item); if ($union) { logger('check_item_source returns true'); } // This might be a followup (e.g. comment) by the original post author to a tagged forum // If so setup a second delivery chain if (!($item['item_flags'] & ITEM_THREAD_TOP)) { $x = q("select * from item where id = parent and parent = %d and uid = %d limit 1", intval($item['parent']), intval($uid)); if ($x && $x[0]['item_flags'] & ITEM_UPLINK) { start_delivery_chain($u[0], $item, $item_id, $x[0]); } } /* * 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) { logger('tag_deliver: post mentions: ' . print_r($terms, true), LOGGER_DATA); } $link = normalise_link($u[0]['xchan_url']); if ($terms) { foreach ($terms as $term) { 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_flags = ( item_flags | %d ) where id = %d", intval(ITEM_MENTIONSME), 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. $body = ''; if ($item['item_flags'] & ITEM_OBSCURED) { $key = get_config('system', 'prvkey'); if ($item['body']) { $body = crypto_unencapsulate(json_decode_plus($item['body']), $key); } } else { $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)) { $tagged = true; } $pattern = '/@\\!?\\[zrl\\=([^\\]]*?)\\]((?:.(?!\\[zrl\\=))*?)\\+\\[\\/zrl\\]/'; if (preg_match_all($pattern, $body, $matches, PREG_SET_ORDER)) { $max_forums = get_config('system', 'max_tagged_forums'); if (!$max_forums) { $max_forums = 2; } $matched_forums = 0; foreach ($matches as $match) { $matched_forums++; if ($term['url'] === $match[1] && $term['term'] === $match[2]) { if ($matched_forums <= $max_forums) { $plustagged = true; break; } logger('forum ' . $term['term'] . ' exceeded max_tagged_forums - ignoring'); } } } if (!($tagged || $plustagged)) { logger('tag_deliver: mention was in a reshare or exceeded max_tagged_forums - ignoring'); return; } $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. */ require_once 'include/enotify.php'; notification(array('to_xchan' => $u[0]['channel_hash'], 'from_xchan' => $item['author_xchan'], 'type' => NOTIFY_TAGSELF, 'item' => $item, 'link' => $i[0]['llink'], 'verb' => ACTIVITY_TAG, 'otype' => 'item')); // Just a normal tag? if (!$plustagged) { logger('tag_deliver: not a plus tag', LOGGER_DEBUG); return; } // plustagged - keep going, next check permissions if (!perm_is_allowed($uid, $item['author_xchan'], 'tag_deliver')) { logger('tag_delivery denied for uid ' . $uid . ' and xchan ' . $item['author_xchan']); return; } } if (!$mention && !$union) { logger('tag_deliver: no mention and no union.'); return; } // tgroup delivery - setup a second delivery chain // prevent delivery looping - only proceed // if the message originated elsewhere and is a top-level post if ($item['item_flags'] & ITEM_WALL || $item['item_flags'] & ITEM_ORIGIN || !($item['item_flags'] & ITEM_THREAD_TOP) || $item['id'] != $item['parent']) { logger('tag_deliver: item was local or a comment. rejected.'); return; } logger('tag_deliver: creating second delivery chain.'); start_delivery_chain($u[0], $item, $item_id, null); }
/** * Render actions localized */ function localize_item(&$item) { if (activity_match($item['verb'], ACTIVITY_LIKE) || activity_match($item['verb'], ACTIVITY_DISLIKE)) { if (!$item['object']) { return; } if ($item['item_flags'] & ITEM_THREAD_TOP) { return; } $obj = json_decode_plus($item['object']); if (!$obj && $item['object']) { logger('localize_item: failed to decode object: ' . print_r($item['object'], true)); } if ($obj['author'] && $obj['author']['link']) { $author_link = get_rel_link($obj['author']['link'], 'alternate'); } else { $author_link = ''; } $author_name = $obj['author'] && $obj['author']['name'] ? $obj['author']['name'] : ''; $item_url = get_rel_link($obj['link'], 'alternate'); $Bphoto = ''; switch ($obj['type']) { case ACTIVITY_OBJ_PHOTO: $post_type = t('photo'); break; case ACTIVITY_OBJ_EVENT: $post_type = t('event'); break; case ACTIVITY_OBJ_PERSON: $post_type = t('channel'); $author_name = $obj['title']; if ($obj['link']) { $author_link = get_rel_link($obj['link'], 'alternate'); $Bphoto = get_rel_link($obj['link'], 'photo'); } break; case ACTIVITY_OBJ_THING: $post_type = $obj['title']; if ($obj['owner']) { if (array_key_exists('name', $obj['owner'])) { $obj['owner']['name']; } if (array_key_exists('link', $obj['owner'])) { $author_link = get_rel_link($obj['owner']['link'], 'alternate'); } } if ($obj['link']) { $Bphoto = get_rel_link($obj['link'], 'photo'); } break; case ACTIVITY_OBJ_NOTE: default: $post_type = t('status'); if ($obj['mid'] != $obj['parent_mid']) { $post_type = t('comment'); } break; } // If we couldn't parse something useful, don't bother translating. // We need something better than zid here, probably magic_link(), but it needs writing if ($author_link && $author_name && $item_url) { $author = '[zrl=' . chanlink_url($item['author']['xchan_url']) . ']' . $item['author']['xchan_name'] . '[/zrl]'; $objauthor = '[zrl=' . chanlink_url($author_link) . ']' . $author_name . '[/zrl]'; $plink = '[zrl=' . zid($item_url) . ']' . $post_type . '[/zrl]'; if (activity_match($item['verb'], ACTIVITY_LIKE)) { $bodyverb = t('%1$s likes %2$s\'s %3$s'); } elseif (activity_match($item['verb'], ACTIVITY_DISLIKE)) { $bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s'); } $item['body'] = $item['localize'] = sprintf($bodyverb, $author, $objauthor, $plink); if ($Bphoto != "") { $item['body'] .= "\n\n\n" . '[zrl=' . chanlink_url($author_link) . '][zmg=80x80]' . $Bphoto . '[/zmg][/zrl]'; } } else { logger('localize_item like failed: link ' . $author_link . ' name ' . $author_name . ' url ' . $item_url); } } if (activity_match($item['verb'], ACTIVITY_FRIEND)) { if ($item['obj_type'] == "" || $item['obj_type'] !== ACTIVITY_OBJ_PERSON) { return; } $Aname = $item['author']['xchan_name']; $Alink = $item['author']['xchan_url']; $obj = json_decode_plus($item['object']); $Blink = $Bphoto = ''; if ($obj['link']) { $Blink = get_rel_link($obj['link'], 'alternate'); $Bphoto = get_rel_link($obj['link'], 'photo'); } $Bname = $obj['title']; $A = '[zrl=' . chanlink_url($Alink) . ']' . $Aname . '[/zrl]'; $B = '[zrl=' . chanlink_url($Blink) . ']' . $Bname . '[/zrl]'; if ($Bphoto != "") { $Bphoto = '[zrl=' . chanlink_url($Blink) . '][zmg=80x80]' . $Bphoto . '[/zmg][/zrl]'; } $item['body'] = $item['localize'] = sprintf(t('%1$s is now connected with %2$s'), $A, $B); $item['body'] .= "\n\n\n" . $Bphoto; } if (stristr($item['verb'], ACTIVITY_POKE)) { /** @FIXME for obscured private posts, until then leave untranslated */ return; $verb = urldecode(substr($item['verb'], strpos($item['verb'], '#') + 1)); if (!$verb) { return; } if ($item['obj_type'] == "" || $item['obj_type'] !== ACTIVITY_OBJ_PERSON) { return; } $Aname = $item['author']['xchan_name']; $Alink = $item['author']['xchan_url']; $obj = json_decode_plus($item['object']); $Blink = $Bphoto = ''; if ($obj['link']) { $Blink = get_rel_link($obj['link'], 'alternate'); $Bphoto = get_rel_link($obj['link'], 'photo'); } $Bname = $obj['title']; $A = '[zrl=' . chanlink_url($Alink) . ']' . $Aname . '[/zrl]'; $B = '[zrl=' . chanlink_url($Blink) . ']' . $Bname . '[/zrl]'; if ($Bphoto != "") { $Bphoto = '[zrl=' . chanlink_url($Blink) . '][zmg=80x80]' . $Bphoto . '[/zmg][/zrl]'; } // we can't have a translation string with three positions but no distinguishable text // So here is the translate string. $txt = t('%1$s poked %2$s'); // now translate the verb $txt = str_replace(t('poked'), t($verb), $txt); // then do the sprintf on the translation string $item['body'] = $item['localize'] = sprintf($txt, $A, $B); $item['body'] .= "\n\n\n" . $Bphoto; } if (stristr($item['verb'], ACTIVITY_MOOD)) { $verb = urldecode(substr($item['verb'], strpos($item['verb'], '#') + 1)); if (!$verb) { return; } $Aname = $item['author']['xchan_name']; $Alink = $item['author']['xchan_url']; $A = '[zrl=' . chanlink_url($Alink) . ']' . $Aname . '[/zrl]'; $txt = t('%1$s is %2$s', 'mood'); $item['body'] = sprintf($txt, $A, t($verb)); } /* // FIXME store parent item as object or target // (and update to json storage) if (activity_match($item['verb'],ACTIVITY_TAG)) { $r = q("SELECT * from `item`,`contact` WHERE `item`.`contact-id`=`contact`.`id` AND `item`.`mid`='%s';", dbesc($item['parent_mid'])); if(count($r)==0) return; $obj=$r[0]; $author = '[zrl=' . zid($item['author-link']) . ']' . $item['author-name'] . '[/zrl]'; $objauthor = '[zrl=' . zid($obj['author-link']) . ']' . $obj['author-name'] . '[/zrl]'; switch($obj['verb']){ case ACTIVITY_POST: switch ($obj['obj_type']){ case ACTIVITY_OBJ_EVENT: $post_type = t('event'); break; default: $post_type = t('status'); } break; default: if($obj['resource_id']){ $post_type = t('photo'); $m=array(); preg_match("/\[[zu]rl=([^]]*)\]/", $obj['body'], $m); $rr['plink'] = $m[1]; } else { $post_type = t('status'); } } $plink = '[zrl=' . $obj['plink'] . ']' . $post_type . '[/zrl]'; $parsedobj = parse_xml_string($xmlhead.$item['object']); $tag = sprintf('#[zrl=%s]%s[/zrl]', $parsedobj->id, $parsedobj->content); $item['body'] = sprintf( t('%1$s tagged %2$s\'s %3$s with %4$s'), $author, $objauthor, $plink, $tag ); } if (activity_match($item['verb'],ACTIVITY_FAVORITE)){ if ($item['obj_type']== "") return; $Aname = $item['author']['xchan_name']; $Alink = $item['author']['xchan_url']; $xmlhead="<"."?xml version='1.0' encoding='UTF-8' ?".">"; $obj = parse_xml_string($xmlhead.$item['object']); if(strlen($obj->id)) { $r = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc($obj->id), intval($item['uid']) ); if(count($r) && $r[0]['plink']) { $target = $r[0]; $Bname = $target['author-name']; $Blink = $target['author-link']; $A = '[zrl=' . zid($Alink) . ']' . $Aname . '[/zrl]'; $B = '[zrl=' . zid($Blink) . ']' . $Bname . '[/zrl]'; $P = '[zrl=' . $target['plink'] . ']' . t('post/item') . '[/zrl]'; $item['body'] = sprintf( t('%1$s marked %2$s\'s %3$s as favorite'), $A, $B, $P)."\n"; } } } */ /* $matches = null; if(strpos($item['body'],'[zrl') !== false) { if(preg_match_all('/@\[zrl=(.*?)\]/is',$item['body'],$matches,PREG_SET_ORDER)) { foreach($matches as $mtch) { if(! strpos($mtch[1],'zid=')) $item['body'] = str_replace($mtch[0],'@[zrl=' . zid($mtch[1]). ']',$item['body']); } } } if(strpos($item['body'],'[zmg') !== false) { // add zid's to public images if(preg_match_all('/\[zrl=(.*?)\/photos\/(.*?)\/image\/(.*?)\]\[zmg(.*?)\]h(.*?)\[\/zmg\]\[\/zrl\]/is',$item['body'],$matches,PREG_SET_ORDER)) { foreach($matches as $mtch) { $item['body'] = str_replace($mtch[0],'[zrl=' . zid( $mtch[1] . '/photos/' . $mtch[2] . '/image/' . $mtch[3]) . '][zmg' . $mtch[4] . ']h' . $mtch[5] . '[/zmg][/zrl]',$item['body']); } } } */ // add sparkle links to appropriate permalinks // $x = stristr($item['plink'],'/display/'); // if($x) { // $sparkle = false; // $y = best_link_url($item,$sparkle,true); // if($sparkle) // $item['plink'] = $y . '?f=&url=' . $item['plink']; // } // if item body was obscured and we changed it, re-obscure it // FIXME - we need a better filter than just the string 'data'; try and // match the fact that it's json encoded if ($item['item_flags'] & ITEM_OBSCURED && strlen($item['body']) && !strpos($item['body'], 'data')) { $item['body'] = json_encode(crypto_encapsulate($item['body'], get_config('system', 'pubkey'))); } }