예제 #1
0
파일: threads.php 프로젝트: vinzv/friendica
function add_shadow_entry($item)
{
    // Is this a shadow entry?
    if ($item['uid'] == 0) {
        return;
    }
    // Is there a shadow parent?
    $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND `uid` = 0 LIMIT 1", dbesc($item['parent-uri']));
    if (!count($r)) {
        return;
    }
    // Is there already a shadow entry?
    $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' AND `uid` = 0 LIMIT 1", dbesc($item['uri']));
    if (count($r)) {
        return;
    }
    // Preparing public shadow (removing user specific data)
    require_once "include/items.php";
    require_once "include/Contact.php";
    unset($item['id']);
    $item['uid'] = 0;
    $item['contact-id'] = get_contact($item['author-link'], 0);
    $public_shadow = item_store($item, false, false, true);
    logger("Stored public shadow for comment " . $item['uri'] . " under id " . $public_shadow, LOGGER_DEBUG);
}
예제 #2
0
 function get()
 {
     if (!local_channel()) {
         return;
     }
     $postid = $_REQUEST['postid'];
     if (!$postid) {
         return;
     }
     $emoji = $_REQUEST['emoji'];
     if ($_REQUEST['emoji']) {
         $i = q("select * from item where id = %d and uid = %d", intval($postid), intval(local_channel()));
         if (!$i) {
             return;
         }
         $channel = \App::get_channel();
         $n = array();
         $n['aid'] = $channel['channel_account_id'];
         $n['uid'] = $channel['channel_id'];
         $n['item_origin'] = true;
         $n['parent'] = $postid;
         $n['parent_mid'] = $i[0]['mid'];
         $n['mid'] = item_message_id();
         $n['verb'] = ACTIVITY_REACT . '#' . $emoji;
         $n['body'] = "\n\n[zmg=32x32]" . z_root() . '/images/emoji/' . $emoji . '.png[/zmg]' . "\n\n";
         $n['author_xchan'] = $channel['channel_hash'];
         $x = item_store($n);
         if ($x['success']) {
             $nid = $x['item_id'];
             \Zotlabs\Daemon\Master::Summon(array('Notifier', 'like', $nid));
         }
     }
 }
예제 #3
0
파일: impel.php 프로젝트: redmatrix/red
function impel_init(&$a)
{
    $ret = array('success' => false);
    if (!local_channel()) {
        json_return_and_die($ret);
    }
    logger('impel: ' . print_r($_REQUEST, true), LOGGER_DATA);
    $elm = $_REQUEST['element'];
    $x = base64url_decode($elm);
    if (!$x) {
        json_return_and_die($ret);
    }
    $j = json_decode($x, true);
    if (!$j) {
        json_return_and_die($ret);
    }
    $channel = $a->get_channel();
    $arr = array();
    switch ($j['type']) {
        case 'webpage':
            $arr['item_restrict'] = ITEM_WEBPAGE;
            $namespace = 'WEBPAGE';
            $installed_type = t('webpage');
            break;
        case 'block':
            $arr['item_restrict'] = ITEM_BUILDBLOCK;
            $namespace = 'BUILDBLOCK';
            $installed_type = t('block');
            break;
        case 'layout':
            $arr['item_restrict'] = ITEM_PDL;
            $namespace = 'PDL';
            $installed_type = t('layout');
            break;
        default:
            logger('mod_impel: unrecognised element type' . print_r($j, true));
            break;
    }
    $arr['uid'] = local_channel();
    $arr['aid'] = $channel['channel_account_id'];
    $arr['title'] = $j['title'];
    $arr['body'] = $j['body'];
    $arr['term'] = $j['term'];
    $arr['created'] = datetime_convert('UTC', 'UTC', $j['created']);
    $arr['edited'] = datetime_convert('UTC', 'UTC', $j['edited']);
    $arr['owner_xchan'] = get_observer_hash();
    $arr['author_xchan'] = $j['author_xchan'] ? $j['author_xchan'] : get_observer_hash();
    $arr['mimetype'] = $j['mimetype'] ? $j['mimetype'] : 'text/bbcode';
    if (!$j['mid']) {
        $j['mid'] = item_message_id();
    }
    $arr['mid'] = $arr['parent_mid'] = $j['mid'];
    if ($j['pagetitle']) {
        require_once 'library/urlify/URLify.php';
        $pagetitle = strtolower(URLify::transliterate($j['pagetitle']));
    }
    // Verify ability to use html or php!!!
    $execflag = false;
    if ($arr['mimetype'] === 'application/x-php') {
        $z = q("select account_id, account_roles, channel_pageflags from account left join channel on channel_account_id = account_id where channel_id = %d limit 1", intval(local_channel()));
        if ($z && ($z[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE || $z[0]['channel_pageflags'] & PAGE_ALLOWCODE)) {
            $execflag = true;
        }
    }
    $remote_id = 0;
    $z = q("select * from item_id where sid = '%s' and service = '%s' and uid = %d limit 1", dbesc($pagetitle), dbesc($namespace), intval(local_channel()));
    $i = q("select id from item where mid = '%s' and uid = %d limit 1", dbesc($arr['mid']), intval(local_channel()));
    if ($z && $i) {
        $remote_id = $z[0]['id'];
        $arr['id'] = $i[0]['id'];
        // don't update if it has the same timestamp as the original
        if ($arr['edited'] > $i[0]['edited']) {
            $x = item_store_update($arr, $execflag);
        }
    } else {
        $x = item_store($arr, $execflag);
    }
    if ($x['success']) {
        $item_id = $x['item_id'];
    }
    update_remote_id($channel, $item_id, $arr['item_restrict'], $pagetitle, $namespace, $remote_id, $arr['mid']);
    $ret['success'] = true;
    info(sprintf(t('%s element installed'), $installed_type));
    json_return_and_die(true);
}
예제 #4
0
function randpost_fetch(&$a, &$b)
{
    $fort_server = get_config('fortunate', 'server');
    if (!$fort_server) {
        return;
    }
    $r = q("select * from pconfig where cat = 'randpost' and k = 'enable'");
    if ($r) {
        foreach ($r as $rr) {
            if (!$rr['v']) {
                continue;
            }
            //			logger('randpost');
            // cronhooks run every 10-15 minutes typically
            // try to keep from posting frequently.
            $test = mt_rand(0, 100);
            if ($test == 25) {
                $c = q("select * from channel where channel_id = %d limit 1", intval($rr['uid']));
                if (!$c) {
                    continue;
                }
                $mention = '';
                require_once 'include/html2bbcode.php';
                $s = z_fetch_url('http://' . $fort_server . '/cookie.php?numlines=2&equal=1&rand=' . mt_rand());
                if (!$s['success']) {
                    continue;
                }
                $x = array();
                $x['uid'] = $c[0]['channel_id'];
                $x['aid'] = $c[0]['channel_account_id'];
                $x['mid'] = $x['parent_mid'] = item_message_id();
                $x['author_xchan'] = $x['owner_xchan'] = $c[0]['channel_hash'];
                $x['item_thread_top'] = 1;
                $x['item_origin'] = 1;
                $x['item_verified'] = 1;
                $x['item_wall'] = 1;
                // if it might be a quote make it a quote
                if (strpos($s['body'], '--')) {
                    $x['body'] = $mention . '[quote]' . html2bbcode($s['body']) . '[/quote]';
                } else {
                    $x['body'] = $mention . html2bbcode($s['body']);
                }
                $x['sig'] = base64url_encode(rsa_sign($x['body'], $c[0]['channel_prvkey']));
                $post = item_store($x);
                $post_id = $post['item_id'];
                $x['id'] = $post_id;
                call_hooks('post_local_end', $x);
                Zotlabs\Daemon\Master::Summon(array('Notifier', 'wall-new', $post_id));
            }
        }
    }
}
예제 #5
0
파일: zot.php 프로젝트: 23n/hubzilla
/**
 * @brief Deletes an imported item.
 *
 * @param array $sender
 *   * \e string \b hash a xchan_hash
 * @param array $item
 * @param int $uid
 * @param boolean $relay
 * @return boolean|int post_id
 */
function delete_imported_item($sender, $item, $uid, $relay)
{
    logger('delete_imported_item invoked', LOGGER_DEBUG);
    $ownership_valid = false;
    $item_found = false;
    $post_id = 0;
    $r = q("select id, author_xchan, owner_xchan, source_xchan, item_deleted from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' )\n\t\tand mid = '%s' and uid = %d limit 1", dbesc($sender['hash']), dbesc($sender['hash']), dbesc($sender['hash']), dbesc($item['mid']), intval($uid));
    if ($r) {
        if ($r[0]['author_xchan'] === $sender['hash'] || $r[0]['owner_xchan'] === $sender['hash'] || $r[0]['source_xchan'] === $sender['hash']) {
            $ownership_valid = true;
        }
        $post_id = $r[0]['id'];
        $item_found = true;
    } else {
        // perhaps the item is still in transit and the delete notification got here before the actual item did. Store it with the deleted flag set.
        // item_store() won't try to deliver any notifications or start delivery chains if this flag is set.
        // This means we won't end up with potentially even more delivery threads trying to push this delete notification.
        // But this will ensure that if the (undeleted) original post comes in at a later date, we'll reject it because it will have an older timestamp.
        logger('delete received for non-existent item - storing item data.');
        /** @BUG $arr is undefined here, so this is dead code */
        if ($arr['author_xchan'] === $sender['hash'] || $arr['owner_xchan'] === $sender['hash'] || $arr['source_xchan'] === $sender['hash']) {
            $ownership_valid = true;
            $item_result = item_store($arr);
            $post_id = $item_result['item_id'];
        }
    }
    if ($ownership_valid === false) {
        logger('delete_imported_item: failed: ownership issue');
        return false;
    }
    require_once 'include/items.php';
    if ($item_found) {
        if (intval($r[0]['item_deleted'])) {
            logger('delete_imported_item: item was already deleted');
            if (!$relay) {
                return false;
            }
            // This is a bit hackish, but may have to suffice until the notification/delivery loop is optimised
            // a bit further. We're going to strip the ITEM_ORIGIN on this item if it's a comment, because
            // it was already deleted, and we're already relaying, and this ensures that no other process or
            // code path downstream can relay it again (causing a loop). Since it's already gone it's not coming
            // back, and we aren't going to (or shouldn't at any rate) delete it again in the future - so losing
            // this information from the metadata should have no other discernible impact.
            if ($r[0]['id'] != $r[0]['parent'] && intval($r[0]['item_origin'])) {
                q("update item set item_origin = 0 where id = %d and uid = %d", intval($r[0]['id']), intval($r[0]['uid']));
            }
        }
        require_once 'include/items.php';
        // Use phased deletion to set the deleted flag, call both tag_deliver and the notifier to notify downstream channels
        // and then clean up after ourselves with a cron job after several days to do the delete_item_lowlevel() (DROPITEM_PHASE2).
        drop_item($post_id, false, DROPITEM_PHASE1);
        tag_deliver($uid, $post_id);
    }
    return $post_id;
}
예제 #6
0
/**
 * @brief Process atom feed and update anything/everything we might need to update.
 *
 * $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
 *
 * @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.
 */
function consume_feed($xml, $importer, &$contact, $pass = 0)
{
    require_once 'library/simplepie/simplepie.inc';
    if (!strlen($xml)) {
        logger('consume_feed: empty input');
        return;
    }
    $feed = new SimplePie();
    $feed->set_raw_data($xml);
    $feed->init();
    if ($feed->error()) {
        logger('consume_feed: Error parsing XML: ' . $feed->error());
    }
    $permalink = $feed->get_permalink();
    // Check at the feed level for updated contact name and/or photo
    // process any deleted entries
    $del_entries = $feed->get_feed_tags(NAMESPACE_TOMB, 'deleted-entry');
    if (is_array($del_entries) && count($del_entries) && $pass != 2) {
        foreach ($del_entries as $dentry) {
            $deleted = false;
            if (isset($dentry['attribs']['']['ref'])) {
                $mid = $dentry['attribs']['']['ref'];
                $deleted = true;
                if (isset($dentry['attribs']['']['when'])) {
                    $when = $dentry['attribs']['']['when'];
                    $when = datetime_convert('UTC', 'UTC', $when, 'Y-m-d H:i:s');
                } else {
                    $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)), dbesc($contact['xchan_hash']), intval($importer['channel_id']));
                if ($r) {
                    $item = $r[0];
                    if (!($item['item_restrict'] & ITEM_DELETED)) {
                        logger('consume_feed: deleting item ' . $item['id'] . ' mid=' . base64url_decode($item['mid']), LOGGER_DEBUG);
                        drop_item($item['id'], false);
                    }
                }
            }
        }
    }
    // Now process the feed
    if ($feed->get_item_quantity()) {
        logger('consume_feed: feed item count = ' . $feed->get_item_quantity(), LOGGER_DEBUG);
        $items = $feed->get_items();
        foreach ($items as $item) {
            $is_reply = false;
            $item_id = base64url_encode($item->get_id());
            logger('consume_feed: processing ' . $item_id, LOGGER_DEBUG);
            $rawthread = $item->get_item_tags(NAMESPACE_THREAD, 'in-reply-to');
            if (isset($rawthread[0]['attribs']['']['ref'])) {
                $is_reply = true;
                $parent_mid = base64url_encode($rawthread[0]['attribs']['']['ref']);
            }
            if ($is_reply) {
                if ($pass == 1) {
                    continue;
                }
                // Have we seen it? If not, import it.
                $item_id = base64url_encode($item->get_id());
                $author = array();
                $datarray = get_atom_elements($feed, $item, $author);
                if (!x($author, 'author_name') || $author['author_is_feed']) {
                    $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']) {
                    $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) {
                        $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']));
                // Update content if 'updated' changes
                if ($r) {
                    if (x($datarray, 'edited') !== false && datetime_convert('UTC', 'UTC', $datarray['edited']) !== $r[0]['edited']) {
                        // do not accept (ignore) an earlier edit than one we currently have.
                        if (datetime_convert('UTC', 'UTC', $datarray['edited']) < $r[0]['edited']) {
                            continue;
                        }
                        update_feed_item($importer['channel_id'], $datarray);
                    }
                    continue;
                }
                $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.
                $item_id = base64url_encode($item->get_id());
                $author = array();
                $datarray = get_atom_elements($feed, $item, $author);
                if (is_array($contact)) {
                    if (!x($author, 'author_name') || $author['author_is_feed']) {
                        $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']) {
                        $author['author_photo'] = $contact['xchan_photo_m'];
                    }
                }
                if (!x($author, 'author_name') || !x($author, 'author_link')) {
                    logger('consume_feed: no author information! ' . print_r($author, true));
                    continue;
                }
                $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) {
                        $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']));
                // Update content if 'updated' changes
                if ($r) {
                    if (x($datarray, 'edited') !== false && datetime_convert('UTC', 'UTC', $datarray['edited']) !== $r[0]['edited']) {
                        // do not accept (ignore) an earlier edit than one we currently have.
                        if (datetime_convert('UTC', 'UTC', $datarray['edited']) < $r[0]['edited']) {
                            continue;
                        }
                        update_feed_item($importer['channel_id'], $datarray);
                    }
                    continue;
                }
                $datarray['parent_mid'] = $item_id;
                $datarray['uid'] = $importer['channel_id'];
                if (!link_compare($author['owner_link'], $contact['xchan_url'])) {
                    logger('consume_feed: Correcting item owner.', LOGGER_DEBUG);
                    $author['owner_name'] = $contact['name'];
                    $author['owner_link'] = $contact['url'];
                    $author['owner_avatar'] = $contact['thumb'];
                }
                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;
            }
        }
    }
}
예제 #7
0
파일: diaspora.php 프로젝트: Mauru/red
function diaspora_like($importer, $xml, $msg)
{
    $a = get_app();
    $guid = notags(unxmlify($xml->guid));
    $parent_guid = notags(unxmlify($xml->parent_guid));
    $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
    $target_type = notags(unxmlify($xml->target_type));
    $positive = notags(unxmlify($xml->positive));
    $author_signature = notags(unxmlify($xml->author_signature));
    $parent_author_signature = $xml->parent_author_signature ? notags(unxmlify($xml->parent_author_signature)) : '';
    // likes on comments not supported here and likes on photos not supported by Diaspora
    //	if($target_type !== 'Post')
    //		return;
    $contact = diaspora_get_contact_by_handle($importer['channel_id'], $msg['author']);
    if (!$contact) {
        logger('diaspora_like: cannot find contact: ' . $msg['author']);
        return;
    }
    if (!perm_is_allowed($importer['channel_id'], $contact['xchan_hash'], 'post_comments')) {
        logger('diaspora_like: Ignoring this author.');
        return 202;
    }
    $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `mid` = '%s' LIMIT 1", intval($importer['channel_id']), dbesc($parent_guid));
    if (!count($r)) {
        logger('diaspora_like: parent item not found: ' . $guid);
        return;
    }
    $parent_item = $r[0];
    $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `mid` = '%s' LIMIT 1", intval($importer['channel_id']), dbesc($guid));
    if (count($r)) {
        if ($positive === 'true') {
            logger('diaspora_like: duplicate like: ' . $guid);
            return;
        }
        // Note: I don't think "Like" objects with positive = "false" are ever actually used
        // It looks like "RelayableRetractions" are used for "unlike" instead
        if ($positive === 'false') {
            logger('diaspora_like: received a like with positive set to "false"...ignoring');
            // perhaps call drop_item()
            // FIXME--actually don't unless it turns out that Diaspora does indeed send out "false" likes
            //  send notification via proc_run()
            return;
        }
    }
    $i = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($parent_item['author_xchan']));
    if ($i) {
        $item_author = $i[0];
    }
    // Note: I don't think "Like" objects with positive = "false" are ever actually used
    // It looks like "RelayableRetractions" are used for "unlike" instead
    if ($positive === 'false') {
        logger('diaspora_like: received a like with positive set to "false"');
        logger('diaspora_like: unlike received with no corresponding like...ignoring');
        return;
    }
    /* How Diaspora performs "like" signature checking:
    
    	   - If an item has been sent by the like author to the top-level post owner to relay on
    	     to the rest of the contacts on the top-level post, the top-level post owner should check
    	     the author_signature, then create a parent_author_signature before relaying the like on
    	   - If an item has been relayed on by the top-level post owner, the contacts who receive it
    	     check only the parent_author_signature. Basically, they trust that the top-level post
    	     owner has already verified the authenticity of anything he/she sends out
    	   - In either case, the signature that get checked is the signature created by the person
    	     who sent the salmon
    	*/
    // 2014-09-10 let's try this: signatures are failing. I'll try and make a signable string from
    // the parameters in the order they were presented in the post. This is how D* creates the signable string.
    $signed_data = $positive . ';' . $guid . ';' . $target_type . ';' . $parent_guid . ';' . $diaspora_handle;
    $key = $msg['key'];
    if ($parent_author_signature) {
        // If a parent_author_signature exists, then we've received the like
        // relayed from the top-level post owner. There's no need to check the
        // author_signature if the parent_author_signature is valid
        $parent_author_signature = base64_decode($parent_author_signature);
        if (!rsa_verify($signed_data, $parent_author_signature, $key, 'sha256')) {
            if (intval(get_config('system', 'ignore_diaspora_like_signature'))) {
                logger('diaspora_like: top-level owner verification failed. Proceeding anyway.');
            } else {
                logger('diaspora_like: top-level owner verification failed.');
                return;
            }
        }
    } else {
        // If there's no parent_author_signature, then we've received the like
        // from the like creator. In that case, the person is "like"ing
        // our post, so he/she must be a contact of ours and his/her public key
        // should be in $msg['key']
        $author_signature = base64_decode($author_signature);
        if (!rsa_verify($signed_data, $author_signature, $key, 'sha256')) {
            if (intval(get_config('system', 'ignore_diaspora_like_signature'))) {
                logger('diaspora_like: like creator verification failed. Proceeding anyway');
            } else {
                logger('diaspora_like: like creator verification failed.');
                return;
            }
        }
    }
    logger('diaspora_like: signature check complete.', LOGGER_DEBUG);
    // Phew! Everything checks out. Now create an item.
    // Find the original comment author information.
    // We need this to make sure we display the comment author
    // information (name and avatar) correctly.
    if (strcasecmp($diaspora_handle, $msg['author']) == 0) {
        $person = $contact;
    } else {
        $person = find_diaspora_person_by_handle($diaspora_handle);
        if (!is_array($person)) {
            logger('diaspora_like: unable to find author details');
            return;
        }
    }
    $uri = $diaspora_handle . ':' . $guid;
    $activity = ACTIVITY_LIKE;
    $post_type = $parent_item['resource_type'] === 'photo' ? t('photo') : t('status');
    $links = array(array('rel' => 'alternate', 'type' => 'text/html', 'href' => $parent_item['plink']));
    $objtype = $parent_item['resource_type'] === 'photo' ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE;
    $body = $parent_item['body'];
    $object = json_encode(array('type' => $post_type, 'id' => $parent_item['mid'], 'parent' => $parent_item['thr_parent'] ? $parent_item['thr_parent'] : $parent_item['parent_mid'], 'link' => $links, 'title' => $parent_item['title'], 'content' => $parent_item['body'], 'created' => $parent_item['created'], 'edited' => $parent_item['edited'], 'author' => array('name' => $item_author['xchan_name'], 'address' => $item_author['xchan_addr'], 'guid' => $item_author['xchan_guid'], 'guid_sig' => $item_author['xchan_guid_sig'], 'link' => array(array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item_author['xchan_url']), array('rel' => 'photo', 'type' => $item_author['xchan_photo_mimetype'], 'href' => $item_author['xchan_photo_m'])))));
    $bodyverb = t('%1$s likes %2$s\'s %3$s');
    $arr = array();
    $arr['uid'] = $importer['channel_id'];
    $arr['aid'] = $importer['channel_account_id'];
    $arr['mid'] = $guid;
    $arr['parent_mid'] = $parent_item['mid'];
    $arr['owner_xchan'] = $parent_item['owner_xchan'];
    $arr['author_xchan'] = $person['xchan_hash'];
    $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
    $alink = '[url=' . $parent_item['author-link'] . ']' . $parent_item['author-name'] . '[/url]';
    $plink = '[url=' . z_root() . '/display/' . $guid . ']' . $post_type . '[/url]';
    $arr['body'] = sprintf($bodyverb, $ulink, $alink, $plink);
    $arr['app'] = 'Diaspora';
    $arr['item_private'] = $parent_item['item_private'];
    $arr['verb'] = $activity;
    $arr['object-type'] = $objtype;
    $arr['object'] = $object;
    if (!$parent_author_signature) {
        $datarray['diaspora_meta'] = array('signer' => $diaspora_handle, 'body' => $text, 'signed_text' => $signed_data, 'signature' => base64_encode($author_signature));
    }
    $x = item_store($arr);
    if ($x) {
        $message_id = $x['item_id'];
    }
    // if the message isn't already being relayed, notify others
    // the existence of parent_author_signature means the parent_author or owner
    // is already relaying. The parent_item['origin'] indicates the message was created on our system
    if ($parent_item['item_flags'] & ITEM_ORIGIN && !$parent_author_signature) {
        proc_run('php', 'include/notifier.php', 'comment-import', $message_id);
    }
    return;
}
예제 #8
0
function photos_post(&$a)
{
    logger('mod-photos: photos_post: begin', LOGGER_DEBUG);
    logger('mod_photos: REQUEST ' . print_r($_REQUEST, true), LOGGER_DATA);
    logger('mod_photos: FILES ' . print_r($_FILES, true), LOGGER_DATA);
    $can_post = false;
    $visitor = 0;
    $page_owner_uid = $a->data['user']['uid'];
    $community_page = $a->data['user']['page-flags'] == PAGE_COMMUNITY ? true : false;
    if (local_user() && local_user() == $page_owner_uid) {
        $can_post = true;
    } else {
        if ($community_page && remote_user()) {
            $r = q("SELECT `uid` FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1", intval(remote_user()), intval($page_owner_uid));
            if (count($r)) {
                $can_post = true;
                $visitor = remote_user();
            }
        }
    }
    if (!$can_post) {
        notice(t('Permission denied.') . EOL);
        killme();
    }
    $r = q("SELECT `contact`.*, `user`.`nickname` FROM `contact` LEFT JOIN `user` ON `user`.`uid` = `contact`.`uid` \n\t\tWHERE `user`.`uid` = %d AND `self` = 1 LIMIT 1", intval($page_owner_uid));
    if (!count($r)) {
        notice(t('Contact information unavailable') . EOL);
        logger('photos_post: unable to locate contact record for page owner. uid=' . $page_owner_uid);
        killme();
    }
    $owner_record = $r[0];
    if ($a->argc > 3 && $a->argv[2] === 'album') {
        $album = hex2bin($a->argv[3]);
        if ($album === t('Profile Photos') || $album === 'Contact Photos' || $album === t('Contact Photos')) {
            goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']);
            return;
            // NOTREACHED
        }
        $r = q("SELECT count(*) FROM `photo` WHERE `album` = '%s' AND `uid` = %d", dbesc($album), intval($page_owner_uid));
        if (!count($r)) {
            notice(t('Album not found.') . EOL);
            goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']);
            return;
            // NOTREACHED
        }
        $newalbum = notags(trim($_POST['albumname']));
        if ($newalbum != $album) {
            q("UPDATE `photo` SET `album` = '%s' WHERE `album` = '%s' AND `uid` = %d", dbesc($newalbum), dbesc($album), intval($page_owner_uid));
            $newurl = str_replace(bin2hex($album), bin2hex($newalbum), $_SESSION['photo_return']);
            goaway($a->get_baseurl() . '/' . $newurl);
            return;
            // NOTREACHED
        }
        if ($_POST['dropalbum'] == t('Delete Album')) {
            $res = array();
            // get the list of photos we are about to delete
            if ($visitor) {
                $r = q("SELECT distinct(`resource-id`) as `rid` FROM `photo` WHERE `contact-id` = %d AND `uid` = %d AND `album` = '%s'", intval($visitor), intval($page_owner_uid), dbesc($album));
            } else {
                $r = q("SELECT distinct(`resource-id`) as `rid` FROM `photo` WHERE `uid` = %d AND `album` = '%s'", intval(local_user()), dbesc($album));
            }
            if (count($r)) {
                foreach ($r as $rr) {
                    $res[] = "'" . dbesc($rr['rid']) . "'";
                }
            } else {
                goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']);
                return;
                // NOTREACHED
            }
            $str_res = implode(',', $res);
            // remove the associated photos
            q("DELETE FROM `photo` WHERE `resource-id` IN ( {$str_res} ) AND `uid` = %d", intval($page_owner_uid));
            // find and delete the corresponding item with all the comments and likes/dislikes
            $r = q("SELECT `parent-uri` FROM `item` WHERE `resource-id` IN ( {$str_res} ) AND `uid` = %d", intval($page_owner_uid));
            if (count($r)) {
                foreach ($r as $rr) {
                    q("UPDATE `item` SET `deleted` = 1, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", dbesc(datetime_convert()), dbesc($rr['parent-uri']), intval($page_owner_uid));
                    $drop_id = intval($rr['id']);
                    // send the notification upstream/downstream as the case may be
                    if ($rr['visible']) {
                        proc_run('php', "include/notifier.php", "drop", "{$drop_id}");
                    }
                }
            }
        }
        goaway($a->get_baseurl() . '/photos/' . $a->data['user']['nickname']);
        return;
        // NOTREACHED
    }
    if ($a->argc > 2 && x($_POST, 'delete') && $_POST['delete'] == t('Delete Photo')) {
        // same as above but remove single photo
        if ($visitor) {
            $r = q("SELECT `id`, `resource-id` FROM `photo` WHERE `contact-id` = %d AND `uid` = %d AND `resource-id` = '%s' LIMIT 1", intval($visitor), intval($page_owner_uid), dbesc($a->argv[2]));
        } else {
            $r = q("SELECT `id`, `resource-id` FROM `photo` WHERE `uid` = %d AND `resource-id` = '%s' LIMIT 1", intval(local_user()), dbesc($a->argv[2]));
        }
        if (count($r)) {
            q("DELETE FROM `photo` WHERE `uid` = %d AND `resource-id` = '%s'", intval($page_owner_uid), dbesc($r[0]['resource-id']));
            $i = q("SELECT * FROM `item` WHERE `resource-id` = '%s' AND `uid` = %d LIMIT 1", dbesc($r[0]['resource-id']), intval($page_owner_uid));
            if (count($i)) {
                q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($i[0]['uri']), intval($page_owner_uid));
                $url = $a->get_baseurl();
                $drop_id = intval($i[0]['id']);
                if ($i[0]['visible']) {
                    proc_run('php', "include/notifier.php", "drop", "{$drop_id}");
                }
            }
        }
        goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']);
        return;
        // NOTREACHED
    }
    if ($a->argc > 2 && (x($_POST, 'desc') !== false || x($_POST, 'newtag') !== false) || x($_POST, 'albname') !== false) {
        $desc = x($_POST, 'desc') ? notags(trim($_POST['desc'])) : '';
        $rawtags = x($_POST, 'newtag') ? notags(trim($_POST['newtag'])) : '';
        $item_id = x($_POST, 'item_id') ? intval($_POST['item_id']) : 0;
        $albname = x($_POST, 'albname') ? notags(trim($_POST['albname'])) : '';
        $str_group_allow = perms2str($_POST['group_allow']);
        $str_contact_allow = perms2str($_POST['contact_allow']);
        $str_group_deny = perms2str($_POST['group_deny']);
        $str_contact_deny = perms2str($_POST['contact_deny']);
        $resource_id = $a->argv[2];
        if (!strlen($albname)) {
            $albname = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y');
        }
        if (x($_POST, 'rotate') !== false && intval($_POST['rotate']) == 1) {
            logger('rotate');
            $r = q("select * from photo where `resource-id` = '%s' and uid = %d and scale = 0 limit 1", dbesc($resource_id), intval($page_owner_uid));
            if (count($r)) {
                $ph = new Photo($r[0]['data']);
                if ($ph->is_valid()) {
                    $ph->rotate(270);
                    $width = $ph->getWidth();
                    $height = $ph->getHeight();
                    $x = q("update photo set data = '%s', height = %d, width = %d where `resource-id` = '%s' and uid = %d and scale = 0 limit 1", dbesc($ph->imageString()), intval($height), intval($width), dbesc($resource_id), intval($page_owner_uid));
                    if ($width > 640 || $height > 640) {
                        $ph->scaleImage(640);
                        $width = $ph->getWidth();
                        $height = $ph->getHeight();
                        $x = q("update photo set data = '%s', height = %d, width = %d where `resource-id` = '%s' and uid = %d and scale = 1 limit 1", dbesc($ph->imageString()), intval($height), intval($width), dbesc($resource_id), intval($page_owner_uid));
                    }
                    if ($width > 320 || $height > 320) {
                        $ph->scaleImage(320);
                        $width = $ph->getWidth();
                        $height = $ph->getHeight();
                        $x = q("update photo set data = '%s', height = %d, width = %d where `resource-id` = '%s' and uid = %d and scale = 2 limit 1", dbesc($ph->imageString()), intval($height), intval($width), dbesc($resource_id), intval($page_owner_uid));
                    }
                }
            }
        }
        $p = q("SELECT * FROM `photo` WHERE `resource-id` = '%s' AND `uid` = %d ORDER BY `scale` DESC", dbesc($resource_id), intval($page_owner_uid));
        if (count($p)) {
            $r = q("UPDATE `photo` SET `desc` = '%s', `album` = '%s', `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s' WHERE `resource-id` = '%s' AND `uid` = %d", dbesc($desc), dbesc($albname), dbesc($str_contact_allow), dbesc($str_group_allow), dbesc($str_contact_deny), dbesc($str_group_deny), dbesc($resource_id), intval($page_owner_uid));
        }
        /* Don't make the item visible if the only change was the album name */
        $visibility = 0;
        if ($p[0]['desc'] !== $desc || strlen($rawtags)) {
            $visibility = 1;
        }
        if (!$item_id) {
            // Create item container
            $title = '';
            $uri = item_new_uri($a->get_hostname(), $page_owner_uid);
            $arr = array();
            $arr['uid'] = $page_owner_uid;
            $arr['uri'] = $uri;
            $arr['parent-uri'] = $uri;
            $arr['type'] = 'photo';
            $arr['wall'] = 1;
            $arr['resource-id'] = $p[0]['resource-id'];
            $arr['contact-id'] = $owner_record['id'];
            $arr['owner-name'] = $owner_record['name'];
            $arr['owner-link'] = $owner_record['url'];
            $arr['owner-avatar'] = $owner_record['thumb'];
            $arr['author-name'] = $owner_record['name'];
            $arr['author-link'] = $owner_record['url'];
            $arr['author-avatar'] = $owner_record['thumb'];
            $arr['title'] = $title;
            $arr['allow_cid'] = $p[0]['allow_cid'];
            $arr['allow_gid'] = $p[0]['allow_gid'];
            $arr['deny_cid'] = $p[0]['deny_cid'];
            $arr['deny_gid'] = $p[0]['deny_gid'];
            $arr['last-child'] = 1;
            $arr['visible'] = $visibility;
            $arr['origin'] = 1;
            $arr['body'] = '[url=' . $a->get_baseurl() . '/photos/' . $a->data['user']['nickname'] . '/image/' . $p[0]['resource-id'] . ']' . '[img]' . $a->get_baseurl() . '/photo/' . $p[0]['resource-id'] . '-' . $p[0]['scale'] . '.jpg' . '[/img]' . '[/url]';
            $item_id = item_store($arr);
        }
        if ($item_id) {
            $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($item_id), intval($page_owner_uid));
        }
        if (count($r)) {
            $old_tag = $r[0]['tag'];
            $old_inform = $r[0]['inform'];
        }
        if (strlen($rawtags)) {
            $str_tags = '';
            $inform = '';
            // if the new tag doesn't have a namespace specifier (@foo or #foo) give it a hashtag
            $x = substr($rawtags, 0, 1);
            if ($x !== '@' && $x !== '#') {
                $rawtags = '#' . $rawtags;
            }
            $taginfo = array();
            $tags = get_tags($rawtags);
            if (count($tags)) {
                foreach ($tags as $tag) {
                    if (isset($profile)) {
                        unset($profile);
                    }
                    if (strpos($tag, '@') === 0) {
                        $name = substr($tag, 1);
                        if (strpos($name, '@') || strpos($name, 'http://')) {
                            $newname = $name;
                            $links = @lrdd($name);
                            if (count($links)) {
                                foreach ($links as $link) {
                                    if ($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page') {
                                        $profile = $link['@attributes']['href'];
                                    }
                                    if ($link['@attributes']['rel'] === 'salmon') {
                                        $salmon = '$url:' . str_replace(',', '%sc', $link['@attributes']['href']);
                                        if (strlen($inform)) {
                                            $inform .= ',';
                                        }
                                        $inform .= $salmon;
                                    }
                                }
                            }
                            $taginfo[] = array($newname, $profile, $salmon);
                        } else {
                            $newname = $name;
                            $alias = '';
                            $tagcid = 0;
                            if (strrpos($newname, '+')) {
                                $tagcid = intval(substr($newname, strrpos($newname, '+') + 1));
                            }
                            if ($tagcid) {
                                $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($tagcid), intval($profile_uid));
                            } elseif (strstr($name, '_') || strstr($name, ' ')) {
                                $newname = str_replace('_', ' ', $name);
                                $r = q("SELECT * FROM `contact` WHERE `name` = '%s' AND `uid` = %d LIMIT 1", dbesc($newname), intval($page_owner_uid));
                            } else {
                                $r = q("SELECT * FROM `contact` WHERE `attag` = '%s' OR `nick` = '%s' AND `uid` = %d ORDER BY `attag` DESC LIMIT 1", dbesc($name), dbesc($name), intval($page_owner_uid));
                            }
                            if (count($r)) {
                                $newname = $r[0]['name'];
                                $profile = $r[0]['url'];
                                $notify = 'cid:' . $r[0]['id'];
                                if (strlen($inform)) {
                                    $inform .= ',';
                                }
                                $inform .= $notify;
                            }
                        }
                        if ($profile) {
                            if (substr($notify, 0, 4) === 'cid:') {
                                $taginfo[] = array($newname, $profile, $notify, $r[0], '@[url=' . str_replace(',', '%2c', $profile) . ']' . $newname . '[/url]');
                            } else {
                                $taginfo[] = array($newname, $profile, $notify, null, $str_tags .= '@[url=' . $profile . ']' . $newname . '[/url]');
                            }
                            if (strlen($str_tags)) {
                                $str_tags .= ',';
                            }
                            $profile = str_replace(',', '%2c', $profile);
                            $str_tags .= '@[url=' . $profile . ']' . $newname . '[/url]';
                        }
                    }
                }
            }
            $newtag = $old_tag;
            if (strlen($newtag) && strlen($str_tags)) {
                $newtag .= ',';
            }
            $newtag .= $str_tags;
            $newinform = $old_inform;
            if (strlen($newinform) && strlen($inform)) {
                $newinform .= ',';
            }
            $newinform .= $inform;
            $r = q("UPDATE `item` SET `tag` = '%s', `inform` = '%s', `edited` = '%s', `changed` = '%s' WHERE `id` = %d AND `uid` = %d LIMIT 1", dbesc($newtag), dbesc($newinform), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($item_id), intval($page_owner_uid));
            $best = 0;
            foreach ($p as $scales) {
                if (intval($scales['scale']) == 2) {
                    $best = 2;
                    break;
                }
                if (intval($scales['scale']) == 4) {
                    $best = 4;
                    break;
                }
            }
            if (count($taginfo)) {
                foreach ($taginfo as $tagged) {
                    $uri = item_new_uri($a->get_hostname(), $page_owner_uid);
                    $arr = array();
                    $arr['uid'] = $page_owner_uid;
                    $arr['uri'] = $uri;
                    $arr['parent-uri'] = $uri;
                    $arr['type'] = 'activity';
                    $arr['wall'] = 1;
                    $arr['contact-id'] = $owner_record['id'];
                    $arr['owner-name'] = $owner_record['name'];
                    $arr['owner-link'] = $owner_record['url'];
                    $arr['owner-avatar'] = $owner_record['thumb'];
                    $arr['author-name'] = $owner_record['name'];
                    $arr['author-link'] = $owner_record['url'];
                    $arr['author-avatar'] = $owner_record['thumb'];
                    $arr['title'] = '';
                    $arr['allow_cid'] = $p[0]['allow_cid'];
                    $arr['allow_gid'] = $p[0]['allow_gid'];
                    $arr['deny_cid'] = $p[0]['deny_cid'];
                    $arr['deny_gid'] = $p[0]['deny_gid'];
                    $arr['last-child'] = 1;
                    $arr['visible'] = 1;
                    $arr['verb'] = ACTIVITY_TAG;
                    $arr['object-type'] = ACTIVITY_OBJ_PERSON;
                    $arr['target-type'] = ACTIVITY_OBJ_PHOTO;
                    $arr['tag'] = $tagged[4];
                    $arr['inform'] = $tagged[2];
                    $arr['origin'] = 1;
                    $arr['body'] = '[url=' . $tagged[1] . ']' . $tagged[0] . '[/url]' . ' ' . t('was tagged in a') . ' ' . '[url=' . $a->get_baseurl() . '/photos/' . $owner_record['nickname'] . '/image/' . $p[0]['resource-id'] . ']' . t('photo') . '[/url]' . ' ' . t('by') . ' ' . '[url=' . $owner_record['url'] . ']' . $owner_record['name'] . '[/url]';
                    $arr['body'] .= "\n\n" . '[url=' . $a->get_baseurl() . '/photos/' . $owner_record['nickname'] . '/image/' . $p[0]['resource-id'] . ']' . '[img]' . $a->get_baseurl() . "/photo/" . $p[0]['resource-id'] . '-' . $best . '.jpg' . '[/img][/url]' . "\n";
                    $arr['object'] = '<object><type>' . ACTIVITY_OBJ_PERSON . '</type><title>' . $tagged[0] . '</title><id>' . $tagged[1] . '/' . $tagged[0] . '</id>';
                    $arr['object'] .= '<link>' . xmlify('<link rel="alternate" type="text/html" href="' . $tagged[1] . '" />' . "\n");
                    if ($tagged[3]) {
                        $arr['object'] .= xmlify('<link rel="photo" type="image/jpeg" href="' . $tagged[3]['photo'] . '" />' . "\n");
                    }
                    $arr['object'] .= '</link></object>' . "\n";
                    $arr['target'] = '<target><type>' . ACTIVITY_OBJ_PHOTO . '</type><title>' . $p[0]['desc'] . '</title><id>' . $a->get_baseurl() . '/photos/' . $owner_record['nickname'] . '/image/' . $p[0]['resource-id'] . '</id>';
                    $arr['target'] .= '<link>' . xmlify('<link rel="alternate" type="text/html" href="' . $a->get_baseurl() . '/photos/' . $owner_record['nickname'] . '/image/' . $p[0]['resource-id'] . '" />' . "\n" . '<link rel="preview" type="image/jpeg" href="' . $a->get_baseurl() . "/photo/" . $p[0]['resource-id'] . '-' . $best . '.jpg' . '" />') . '</link></target>';
                    $item_id = item_store($arr);
                    if ($item_id) {
                        q("UPDATE `item` SET `plink` = '%s' WHERE `uid` = %d AND `id` = %d LIMIT 1", dbesc($a->get_baseurl() . '/display/' . $owner_record['nickname'] . '/' . $item_id), intval($page_owner_uid), intval($item_id));
                        proc_run('php', "include/notifier.php", "tag", "{$item_id}");
                    }
                }
            }
        }
        goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']);
        return;
        // NOTREACHED
    }
    /**
     * default post action - upload a photo
     */
    call_hooks('photo_post_init', $_POST);
    /**
     * Determine the album to use
     */
    $album = notags(trim($_REQUEST['album']));
    $newalbum = notags(trim($_REQUEST['newalbum']));
    logger('mod/photos.php: photos_post(): album= ' . $album . ' newalbum= ' . $newalbum, LOGGER_DEBUG);
    if (!strlen($album)) {
        if (strlen($newalbum)) {
            $album = $newalbum;
        } else {
            $album = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y');
        }
    }
    /**
     *
     * We create a wall item for every photo, but we don't want to
     * overwhelm the data stream with a hundred newly uploaded photos.
     * So we will make the first photo uploaded to this album in the last several hours
     * visible by default, the rest will become visible over time when and if
     * they acquire comments, likes, dislikes, and/or tags 
     *
     */
    $r = q("SELECT * FROM `photo` WHERE `album` = '%s' AND `uid` = %d AND `created` > UTC_TIMESTAMP() - INTERVAL 3 HOUR ", dbesc($album), intval($page_owner_uid));
    if (!count($r) || $album == t('Profile Photos')) {
        $visible = 1;
    } else {
        $visible = 0;
    }
    if (intval($_REQUEST['not_visible']) || $_REQUEST['not_visible'] === 'true') {
        $visible = 0;
    }
    $str_group_allow = perms2str(is_array($_REQUEST['group_allow']) ? $_REQUEST['group_allow'] : explode(',', $_REQUEST['group_allow']));
    $str_contact_allow = perms2str(is_array($_REQUEST['contact_allow']) ? $_REQUEST['contact_allow'] : explode(',', $_REQUEST['contact_allow']));
    $str_group_deny = perms2str(is_array($_REQUEST['group_deny']) ? $_REQUEST['group_deny'] : explode(',', $_REQUEST['group_deny']));
    $str_contact_deny = perms2str(is_array($_REQUEST['contact_deny']) ? $_REQUEST['contact_deny'] : explode(',', $_REQUEST['contact_deny']));
    $ret = array('src' => '', 'filename' => '', 'filesize' => 0);
    call_hooks('photo_post_file', $ret);
    if (x($ret, 'src') && x($ret, 'filesize')) {
        $src = $ret['src'];
        $filename = $ret['filename'];
        $filesize = $ret['filesize'];
    } else {
        $src = $_FILES['userfile']['tmp_name'];
        $filename = basename($_FILES['userfile']['name']);
        $filesize = intval($_FILES['userfile']['size']);
    }
    logger('photos: upload: received file: ' . $filename . ' as ' . $src . ' ' . $filesize . ' bytes', LOGGER_DEBUG);
    $maximagesize = get_config('system', 'maximagesize');
    if ($maximagesize && $filesize > $maximagesize) {
        notice(t('Image exceeds size limit of ') . $maximagesize . EOL);
        @unlink($src);
        $foo = 0;
        call_hooks('photo_post_end', $foo);
        return;
    }
    if (!$filesize) {
        notice(t('Image file is empty.') . EOL);
        @unlink($src);
        $foo = 0;
        call_hooks('photo_post_end', $foo);
        return;
    }
    logger('mod/photos.php: photos_post(): loading the contents of ' . $src, LOGGER_DEBUG);
    $imagedata = @file_get_contents($src);
    $ph = new Photo($imagedata);
    if (!$ph->is_valid()) {
        logger('mod/photos.php: photos_post(): unable to process image', LOGGER_DEBUG);
        notice(t('Unable to process image.') . EOL);
        @unlink($src);
        $foo = 0;
        call_hooks('photo_post_end', $foo);
        killme();
    }
    @unlink($src);
    $width = $ph->getWidth();
    $height = $ph->getHeight();
    $smallest = 0;
    $photo_hash = photo_new_resource();
    $r = $ph->store($page_owner_uid, $visitor, $photo_hash, $filename, $album, 0, 0, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny);
    if (!$r) {
        logger('mod/photos.php: photos_post(): image store failed', LOGGER_DEBUG);
        notice(t('Image upload failed.') . EOL);
        killme();
    }
    if ($width > 640 || $height > 640) {
        $ph->scaleImage(640);
        $ph->store($page_owner_uid, $visitor, $photo_hash, $filename, $album, 1, 0, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny);
        $smallest = 1;
    }
    if ($width > 320 || $height > 320) {
        $ph->scaleImage(320);
        $ph->store($page_owner_uid, $visitor, $photo_hash, $filename, $album, 2, 0, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny);
        $smallest = 2;
    }
    $basename = basename($filename);
    $uri = item_new_uri($a->get_hostname(), $page_owner_uid);
    // Create item container
    $arr = array();
    $arr['uid'] = $page_owner_uid;
    $arr['uri'] = $uri;
    $arr['parent-uri'] = $uri;
    $arr['type'] = 'photo';
    $arr['wall'] = 1;
    $arr['resource-id'] = $photo_hash;
    $arr['contact-id'] = $owner_record['id'];
    $arr['owner-name'] = $owner_record['name'];
    $arr['owner-link'] = $owner_record['url'];
    $arr['owner-avatar'] = $owner_record['thumb'];
    $arr['author-name'] = $owner_record['name'];
    $arr['author-link'] = $owner_record['url'];
    $arr['author-avatar'] = $owner_record['thumb'];
    $arr['title'] = '';
    $arr['allow_cid'] = $str_contact_allow;
    $arr['allow_gid'] = $str_group_allow;
    $arr['deny_cid'] = $str_contact_deny;
    $arr['deny_gid'] = $str_group_deny;
    $arr['last-child'] = 1;
    $arr['visible'] = $visible;
    $arr['origin'] = 1;
    $arr['body'] = '[url=' . $a->get_baseurl() . '/photos/' . $owner_record['nickname'] . '/image/' . $photo_hash . ']' . '[img]' . $a->get_baseurl() . "/photo/{$photo_hash}-{$smallest}.jpg" . '[/img]' . '[/url]';
    $item_id = item_store($arr);
    if ($item_id) {
        q("UPDATE `item` SET `plink` = '%s' WHERE `uid` = %d AND `id` = %d LIMIT 1", dbesc($a->get_baseurl() . '/display/' . $owner_record['nickname'] . '/' . $item_id), intval($page_owner_uid), intval($item_id));
    }
    if ($visible) {
        proc_run('php', "include/notifier.php", 'wall-new', $item_id);
    }
    call_hooks('photo_post_end', intval($item_id));
    // addon uploaders should call "killme()" [e.g. exit] within the photo_post_end hook
    // if they do not wish to be redirected
    goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']);
    // NOTREACHED
}
예제 #9
0
파일: zot.php 프로젝트: HaakonME/redmatrix
function import_items($channel, $items)
{
    if ($channel && $items) {
        $allow_code = false;
        $r = q("select account_id, account_roles, channel_pageflags from account left join channel on channel_account_id = account_id \n\t\t\twhere channel_id = %d limit 1", intval($channel['channel_id']));
        if ($r) {
            if ($r[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE || $r[0]['channel_pageflags'] & PAGE_ALLOWCODE) {
                $allow_code = true;
            }
        }
        foreach ($items as $i) {
            $item = get_item_elements($i, $allow_code);
            if (!$item) {
                continue;
            }
            $r = q("select id, edited from item where mid = '%s' and uid = %d limit 1", dbesc($item['mid']), intval($channel['channel_id']));
            if ($r) {
                if ($item['edited'] > $r[0]['edited']) {
                    $item['id'] = $r[0]['id'];
                    $item['uid'] = $channel['channel_id'];
                    item_store_update($item);
                    continue;
                }
            } else {
                $item['aid'] = $channel['channel_account_id'];
                $item['uid'] = $channel['channel_id'];
                $item_result = item_store($item);
            }
        }
    }
}
예제 #10
0
function pumpio_dopost(&$a, $client, $uid, $self, $post, $own_id, $threadcompletion = true)
{
    require_once 'include/items.php';
    require_once 'include/html2bbcode.php';
    if ($post->verb == "like" or $post->verb == "favorite") {
        return pumpio_dolike($a, $uid, $self, $post, $own_id);
    }
    if ($post->verb == "unlike" or $post->verb == "unfavorite") {
        return pumpio_dounlike($a, $uid, $self, $post, $own_id);
    }
    if ($post->verb == "delete") {
        return pumpio_dodelete($a, $uid, $self, $post, $own_id);
    }
    if ($post->verb != "update") {
        // Two queries for speed issues
        $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($post->object->id), intval($uid));
        if (count($r)) {
            return false;
        }
        $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1", dbesc($post->object->id), intval($uid));
        if (count($r)) {
            return false;
        }
    }
    // Only handle these three types
    if (!strstr("post|share|update", $post->verb)) {
        return false;
    }
    $receiptians = array();
    if (@is_array($post->cc)) {
        $receiptians = array_merge($receiptians, $post->cc);
    }
    if (@is_array($post->to)) {
        $receiptians = array_merge($receiptians, $post->to);
    }
    foreach ($receiptians as $receiver) {
        if (is_string($receiver->objectType)) {
            if ($receiver->id == "http://activityschema.org/collection/public") {
                $public = true;
            }
        }
    }
    $postarray = array();
    $postarray['network'] = NETWORK_PUMPIO;
    $postarray['gravity'] = 0;
    $postarray['uid'] = $uid;
    $postarray['wall'] = 0;
    $postarray['uri'] = $post->object->id;
    $postarray['object-type'] = NAMESPACE_ACTIVITY_SCHEMA . strtolower($post->object->objectType);
    if ($post->object->objectType != "comment") {
        $contact_id = pumpio_get_contact($uid, $post->actor);
        if (!$contact_id) {
            $contact_id = $self[0]['id'];
        }
        $postarray['parent-uri'] = $post->object->id;
        if (!$public) {
            $postarray['private'] = 1;
            $postarray['allow_cid'] = '<' . $self[0]['id'] . '>';
        }
    } else {
        $contact_id = 0;
        if (link_compare($post->actor->url, $own_id)) {
            $contact_id = $self[0]['id'];
            $post->actor->displayName = $self[0]['name'];
            $post->actor->url = $self[0]['url'];
            $post->actor->image->url = $self[0]['photo'];
        } else {
            // Take an existing contact, the contact of the note or - as a fallback - the id of the user
            $r = q("SELECT * FROM `contact` WHERE `url` = '%s' AND `uid` = %d AND `blocked` = 0 AND `readonly` = 0 LIMIT 1", dbesc($post->actor->url), intval($uid));
            if (count($r)) {
                $contact_id = $r[0]['id'];
            } else {
                $r = q("SELECT * FROM `contact` WHERE `url` = '%s' AND `uid` = %d AND `blocked` = 0 AND `readonly` = 0 LIMIT 1", dbesc($post->actor->url), intval($uid));
                if (count($r)) {
                    $contact_id = $r[0]['id'];
                } else {
                    $contact_id = $self[0]['id'];
                }
            }
        }
        $reply = new stdClass();
        $reply->verb = "note";
        $reply->cc = $post->cc;
        $reply->to = $post->to;
        $reply->object = new stdClass();
        $reply->object->objectType = $post->object->inReplyTo->objectType;
        $reply->object->content = $post->object->inReplyTo->content;
        $reply->object->id = $post->object->inReplyTo->id;
        $reply->actor = $post->object->inReplyTo->author;
        $reply->url = $post->object->inReplyTo->url;
        $reply->generator = new stdClass();
        $reply->generator->displayName = "pumpio";
        $reply->published = $post->object->inReplyTo->published;
        $reply->received = $post->object->inReplyTo->updated;
        $reply->url = $post->object->inReplyTo->url;
        pumpio_dopost($a, $client, $uid, $self, $reply, $own_id, false);
        $postarray['parent-uri'] = $post->object->inReplyTo->id;
    }
    if ($post->object->pump_io->proxyURL) {
        $postarray['extid'] = $post->object->pump_io->proxyURL;
    }
    $postarray['contact-id'] = $contact_id;
    $postarray['verb'] = ACTIVITY_POST;
    $postarray['owner-name'] = $post->actor->displayName;
    $postarray['owner-link'] = $post->actor->url;
    $postarray['owner-avatar'] = $post->actor->image->url;
    $postarray['author-name'] = $post->actor->displayName;
    $postarray['author-link'] = $post->actor->url;
    $postarray['author-avatar'] = $post->actor->image->url;
    $postarray['plink'] = $post->object->url;
    $postarray['app'] = $post->generator->displayName;
    $postarray['body'] = html2bbcode($post->object->content);
    if ($post->object->fullImage->url != "") {
        $postarray["body"] = "[url=" . $post->object->fullImage->url . "][img]" . $post->object->image->url . "[/img][/url]\n" . $postarray["body"];
    }
    if ($post->object->displayName != "") {
        $postarray['title'] = $post->object->displayName;
    }
    $postarray['created'] = datetime_convert('UTC', 'UTC', $post->published);
    $postarray['edited'] = datetime_convert('UTC', 'UTC', $post->received);
    if ($post->verb == "share") {
        if (!intval(get_config('system', 'wall-to-wall_share'))) {
            $postarray['body'] = "[share author='" . $post->object->author->displayName . "' profile='" . $post->object->author->url . "' avatar='" . $post->object->author->image->url . "' posted='" . datetime_convert('UTC', 'UTC', $post->object->created) . "' link='" . $post->links->self->href . "']" . $postarray['body'] . "[/share]";
        } else {
            // Let shares look like wall-to-wall posts
            $postarray['author-name'] = $post->object->author->displayName;
            $postarray['author-link'] = $post->object->author->url;
            $postarray['author-avatar'] = $post->object->author->image->url;
        }
    }
    if (trim($postarray['body']) == "") {
        return false;
    }
    $top_item = item_store($postarray);
    $postarray["id"] = $top_item;
    if ($top_item == 0 and $post->verb == "update") {
        $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s' , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", dbesc($postarray["title"]), dbesc($postarray["body"]), dbesc($postarray["edited"]), dbesc($postarray["uri"]), intval($uid));
    }
    if ($post->object->objectType == "comment") {
        if ($threadcompletion) {
            pumpio_fetchallcomments($a, $uid, $postarray['parent-uri']);
        }
        $user = q("SELECT * FROM `user` WHERE `uid` = %d AND `account_expired` = 0 LIMIT 1", intval($uid));
        if (!count($user)) {
            return $top_item;
        }
        $importer_url = $a->get_baseurl() . '/profile/' . $user[0]['nickname'];
        if (link_compare($own_id, $postarray['author-link'])) {
            return $top_item;
        }
        $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 AND `deleted` = 0", dbesc($postarray['parent-uri']), intval($uid));
        if (count($myconv)) {
            foreach ($myconv as $conv) {
                // now if we find a match, it means we're in this conversation
                if (!link_compare($conv['author-link'], $importer_url) and !link_compare($conv['author-link'], $own_id)) {
                    continue;
                }
                require_once 'include/enotify.php';
                $conv_parent = $conv['parent'];
                notification(array('type' => NOTIFY_COMMENT, 'notify_flags' => $user[0]['notify-flags'], 'language' => $user[0]['language'], 'to_name' => $user[0]['username'], 'to_email' => $user[0]['email'], 'uid' => $user[0]['uid'], 'item' => $postarray, 'link' => $a->get_baseurl() . '/display/' . urlencode(get_item_guid($top_item)), 'source_name' => $postarray['author-name'], 'source_link' => $postarray['author-link'], 'source_photo' => $postarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item', 'parent' => $conv_parent));
                // only send one notification
                break;
            }
        }
    }
    return $top_item;
}
예제 #11
0
/** @file */
function profile_activity($changed, $value)
{
    $a = get_app();
    if (!local_channel() || !is_array($changed) || !count($changed)) {
        return;
    }
    if (!get_pconfig(local_channel(), 'system', 'post_profilechange')) {
        return;
    }
    require_once 'include/items.php';
    $self = $a->get_channel();
    if (!count($self)) {
        return;
    }
    $arr = array();
    $arr['mid'] = $arr['parent_mid'] = item_message_id();
    $arr['uid'] = local_channel();
    $arr['aid'] = $self['channel_account_id'];
    $arr['owner_xchan'] = $arr['author_xchan'] = $self['xchan_hash'];
    $arr['item_wall'] = 1;
    $arr['item_origin'] = 1;
    $arr['item_thread_top'] = 1;
    $arr['verb'] = ACTIVITY_UPDATE;
    $arr['obj_type'] = ACTIVITY_OBJ_PROFILE;
    $arr['plink'] = z_root() . '/channel/' . $self['channel_address'] . '/?f=&mid=' . $arr['mid'];
    $A = '[url=' . z_root() . '/channel/' . $self['channel_address'] . ']' . $self['channel_name'] . '[/url]';
    $changes = '';
    $t = count($changed);
    $z = 0;
    foreach ($changed as $ch) {
        if (strlen($changes)) {
            if ($z == $t - 1) {
                $changes .= t(' and ');
            } else {
                $changes .= ', ';
            }
        }
        $z++;
        $changes .= $ch;
    }
    $prof = '[url=' . z_root() . '/profile/' . $self['channel_address'] . ']' . t('public profile') . '[/url]';
    if ($t == 1 && strlen($value)) {
        // if it's a url, the HTML quotes will mess it up, so link it and don't try and zidify it because we don't know what it points to.
        $value = preg_replace_callback("/([^\\]\\='" . '"' . "]|^|\\#\\^)(https?\\:\\/\\/[a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\@\\_\\~\\#\\%\$\\!\\+\\,]+)/ism", 'red_zrl_callback', $value);
        // take out the bookmark indicator
        if (substr($value, 0, 2) === '#^') {
            $value = str_replace('#^', '', $value);
        }
        $message = sprintf(t('%1$s changed %2$s to &ldquo;%3$s&rdquo;'), $A, $changes, $value);
        $message .= "\n\n" . sprintf(t('Visit %1$s\'s %2$s'), $A, $prof);
    } else {
        $message = sprintf(t('%1$s has an updated %2$s, changing %3$s.'), $A, $prof, $changes);
    }
    $arr['body'] = $message;
    $links = array();
    $links[] = array('rel' => 'alternate', 'type' => 'text/html', 'href' => z_root() . '/profile/' . $self['channel_address']);
    $links[] = array('rel' => 'photo', 'type' => $self['xchan_photo_mimetype'], 'href' => $self['xchan_photo_l']);
    $arr['object'] = json_encode(array('type' => ACTIVITY_OBJ_PROFILE, 'title' => $self['channel_name'], 'id' => $self['xchan_url'] . '/' . $self['xchan_hash'], 'link' => $links));
    $arr['allow_cid'] = $self['channel_allow_cid'];
    $arr['allow_gid'] = $self['channel_allow_gid'];
    $arr['deny_cid'] = $self['channel_deny_cid'];
    $arr['deny_gid'] = $self['channel_deny_gid'];
    $res = item_store($arr);
    $i = $res['item_id'];
    if ($i) {
        // FIXME - limit delivery in notifier.php to those specificed in the perms argument
        proc_run('php', "include/notifier.php", "activity", "{$i}", 'PERMS_R_PROFILE');
    }
}
예제 #12
0
function diaspora_like($importer, $xml, $msg)
{
    $a = get_app();
    $guid = notags(unxmlify($xml->guid));
    $parent_guid = notags(unxmlify($xml->parent_guid));
    $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
    $target_type = notags(unxmlify($xml->target_type));
    $positive = notags(unxmlify($xml->positive));
    $author_signature = notags(unxmlify($xml->author_signature));
    $parent_author_signature = $xml->parent_author_signature ? notags(unxmlify($xml->parent_author_signature)) : '';
    // likes on comments not supported here and likes on photos not supported by Diaspora
    if ($target_type !== 'Post') {
        return;
    }
    $contact = diaspora_get_contact_by_handle($importer['uid'], $msg['author']);
    if (!$contact) {
        logger('diaspora_like: cannot find contact: ' . $msg['author']);
        return;
    }
    if ($contact['rel'] == CONTACT_IS_FOLLOWER || $contact['blocked'] || $contact['readonly']) {
        logger('diaspora_like: Ignoring this author.');
        return 202;
    }
    $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1", intval($importer['uid']), dbesc($parent_guid));
    if (!count($r)) {
        logger('diaspora_like: parent item not found: ' . $guid);
        return;
    }
    $parent_item = $r[0];
    $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1", intval($importer['uid']), dbesc($guid));
    if (count($r)) {
        if ($positive === 'true') {
            logger('diaspora_like: duplicate like: ' . $guid);
            return;
        }
        if ($positive === 'false') {
            q("UPDATE `item` SET `deleted` = 1 WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($r[0]['id']), intval($importer['uid']));
            // FIXME
            //  send notification via proc_run()
            return;
        }
    }
    if ($positive === 'false') {
        logger('diaspora_like: unlike received with no corresponding like');
        return;
    }
    $author_signed_data = $guid . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $diaspora_handle;
    $author_signature = base64_decode($author_signature);
    if (strcasecmp($diaspora_handle, $msg['author']) == 0) {
        $person = $contact;
        $key = $msg['key'];
    } else {
        $person = find_diaspora_person_by_handle($diaspora_handle);
        if (is_array($person) && x($person, 'pubkey')) {
            $key = $person['pubkey'];
        } else {
            logger('diaspora_like: unable to find author details');
            return;
        }
    }
    if (!rsa_verify($author_signed_data, $author_signature, $key, 'sha256')) {
        logger('diaspora_like: verification failed.');
        return;
    }
    if ($parent_author_signature) {
        $owner_signed_data = $guid . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $diaspora_handle;
        $parent_author_signature = base64_decode($parent_author_signature);
        $key = $msg['key'];
        if (!rsa_verify($owner_signed_data, $parent_author_signature, $key, 'sha256')) {
            logger('diaspora_like: owner verification failed.');
            return;
        }
    }
    // Phew! Everything checks out. Now create an item.
    $uri = $diaspora_handle . ':' . $guid;
    $activity = ACTIVITY_LIKE;
    $post_type = $parent_item['resource-id'] ? t('photo') : t('status');
    $objtype = $parent_item['resource-id'] ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE;
    $link = xmlify('<link rel="alternate" type="text/html" href="' . $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $parent_item['id'] . '" />' . "\n");
    $body = $parent_item['body'];
    $obj = <<<EOT

\t<object>
\t\t<type>{$objtype}</type>
\t\t<local>1</local>
\t\t<id>{$parent_item['uri']}</id>
\t\t<link>{$link}</link>
\t\t<title></title>
\t\t<content>{$body}</content>
\t</object>
EOT;
    $bodyverb = t('%1$s likes %2$s\'s %3$s');
    $arr = array();
    $arr['uri'] = $uri;
    $arr['uid'] = $importer['uid'];
    $arr['guid'] = $guid;
    $arr['contact-id'] = $contact['id'];
    $arr['type'] = 'activity';
    $arr['wall'] = $parent_item['wall'];
    $arr['gravity'] = GRAVITY_LIKE;
    $arr['parent'] = $parent_item['id'];
    $arr['parent-uri'] = $parent_item['uri'];
    $arr['owner-name'] = $parent_item['name'];
    $arr['owner-link'] = $parent_item['url'];
    $arr['owner-avatar'] = $parent_item['thumb'];
    $arr['author-name'] = $person['name'];
    $arr['author-link'] = $person['url'];
    $arr['author-avatar'] = x($person, 'thumb') ? $person['thumb'] : $person['photo'];
    $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
    $alink = '[url=' . $parent_item['author-link'] . ']' . $parent_item['author-name'] . '[/url]';
    $plink = '[url=' . $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $parent_item['id'] . ']' . $post_type . '[/url]';
    $arr['body'] = sprintf($bodyverb, $ulink, $alink, $plink);
    $arr['app'] = 'Diaspora';
    $arr['private'] = $parent_item['private'];
    $arr['verb'] = $activity;
    $arr['object-type'] = $objtype;
    $arr['object'] = $obj;
    $arr['visible'] = 1;
    $arr['unseen'] = 1;
    $arr['last-child'] = 0;
    $message_id = item_store($arr);
    if ($message_id) {
        q("update item set plink = '%s' where id = %d limit 1", dbesc($a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id), intval($message_id));
    }
    if (!$parent_author_signature) {
        q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($message_id), dbesc($author_signed_data), dbesc(base64_encode($author_signature)), dbesc($diaspora_handle));
    }
    // if the message isn't already being relayed, notify others
    // the existence of parent_author_signature means the parent_author or owner
    // is already relaying. The parent_item['origin'] indicates the message was created on our system
    if ($parent_item['origin'] && !$parent_author_signature) {
        proc_run('php', 'include/notifier.php', 'comment', $message_id);
    }
    return;
}
예제 #13
0
function ostatus_completion($conversation_url, $uid, $item = array())
{
    $a = get_app();
    $item_stored = -1;
    $conversation_url = ostatus_convert_href($conversation_url);
    // If the thread shouldn't be completed then store the item and go away
    if (intval(get_config('system', 'ostatus_poll_interval')) == -2 and count($item) > 0) {
        //$arr["app"] .= " (OStatus-NoCompletion)";
        $item_stored = item_store($item, true);
        return $item_stored;
    }
    // Get the parent
    $parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `id` IN\n\t\t\t(SELECT `parent` FROM `item` WHERE `id` IN\n\t\t\t\t(SELECT `oid` FROM `term` WHERE `uid` = %d AND `otype` = %d AND `type` = %d AND `url` = '%s'))", intval($uid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION), dbesc($conversation_url));
    if ($parents) {
        $parent = $parents[0];
    } elseif (count($item) > 0) {
        $parent = $item;
        $parent["type"] = "remote";
        $parent["verb"] = ACTIVITY_POST;
        $parent["visible"] = 1;
    } else {
        // Preset the parent
        $r = q("SELECT `id` FROM `contact` WHERE `self` AND `uid`=%d", $uid);
        if (!$r) {
            return -2;
        }
        $parent = array();
        $parent["id"] = 0;
        $parent["parent"] = 0;
        $parent["uri"] = "";
        $parent["contact-id"] = $r[0]["id"];
        $parent["type"] = "remote";
        $parent["verb"] = ACTIVITY_POST;
        $parent["visible"] = 1;
    }
    $conv = str_replace("/conversation/", "/api/statusnet/conversation/", $conversation_url) . ".as";
    $pageno = 1;
    $items = array();
    logger('fetching conversation url ' . $conv . ' for user ' . $uid);
    do {
        $conv_arr = z_fetch_url($conv . "?page=" . $pageno);
        // If it is a non-ssl site and there is an error, then try ssl or vice versa
        if (!$conv_arr["success"] and substr($conv, 0, 7) == "http://") {
            $conv = str_replace("http://", "https://", $conv);
            $conv_as = fetch_url($conv . "?page=" . $pageno);
        } elseif (!$conv_arr["success"] and substr($conv, 0, 8) == "https://") {
            $conv = str_replace("https://", "http://", $conv);
            $conv_as = fetch_url($conv . "?page=" . $pageno);
        } else {
            $conv_as = $conv_arr["body"];
        }
        $conv_as = str_replace(',"statusnet:notice_info":', ',"statusnet_notice_info":', $conv_as);
        $conv_as = json_decode($conv_as);
        if (@is_array($conv_as->items)) {
            $items = array_merge($items, $conv_as->items);
        } else {
            break;
        }
        $pageno++;
    } while (true);
    logger('fetching conversation done. Found ' . count($items) . ' items');
    if (!sizeof($items)) {
        if (count($item) > 0) {
            //$arr["app"] .= " (OStatus-NoConvFetched)";
            $item_stored = item_store($item, true);
            if ($item_stored) {
                logger("Conversation " . $conversation_url . " couldn't be fetched. Item uri " . $item["uri"] . " stored: " . $item_stored, LOGGER_DEBUG);
                ostatus_store_conversation($item_id, $conversation_url);
            }
            return $item_stored;
        } else {
            return -3;
        }
    }
    $items = array_reverse($items);
    $r = q("SELECT `nurl` FROM `contact` WHERE `uid` = %d AND `self`", intval($uid));
    $importer = $r[0];
    foreach ($items as $single_conv) {
        // Test - remove before flight
        //$tempfile = tempnam(get_temppath(), "conversation");
        //file_put_contents($tempfile, json_encode($single_conv));
        $mention = false;
        if (isset($single_conv->object->id)) {
            $single_conv->id = $single_conv->object->id;
        }
        $plink = ostatus_convert_href($single_conv->id);
        if (isset($single_conv->object->url)) {
            $plink = ostatus_convert_href($single_conv->object->url);
        }
        if (@(!$single_conv->id)) {
            continue;
        }
        logger("Got id " . $single_conv->id, LOGGER_DEBUG);
        if ($first_id == "") {
            $first_id = $single_conv->id;
            // The first post of the conversation isn't our first post. There are three options:
            // 1. Our conversation hasn't the "real" thread starter
            // 2. This first post is a post inside our thread
            // 3. This first post is a post inside another thread
            if ($first_id != $parent["uri"] and $parent["uri"] != "") {
                $new_parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `id` IN\n\t\t\t\t\t\t\t(SELECT `parent` FROM `item`\n\t\t\t\t\t\t\t\tWHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s')) LIMIT 1", intval($uid), dbesc($first_id), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
                if ($new_parents) {
                    if ($new_parents[0]["parent"] == $parent["parent"]) {
                        // Option 2: This post is already present inside our thread - but not as thread starter
                        logger("Option 2: uri present in our thread: " . $first_id, LOGGER_DEBUG);
                        $first_id = $parent["uri"];
                    } else {
                        // Option 3: Not so good. We have mixed parents. We have to see how to clean this up.
                        // For now just take the new parent.
                        $parent = $new_parents[0];
                        $first_id = $parent["uri"];
                        logger("Option 3: mixed parents for uri " . $first_id, LOGGER_DEBUG);
                    }
                } else {
                    // Option 1: We hadn't got the real thread starter
                    // We have to clean up our existing messages.
                    $parent["id"] = 0;
                    $parent["uri"] = $first_id;
                    logger("Option 1: we have a new parent: " . $first_id, LOGGER_DEBUG);
                }
            } elseif ($parent["uri"] == "") {
                $parent["id"] = 0;
                $parent["uri"] = $first_id;
            }
        }
        $parent_uri = $parent["uri"];
        // "context" only seems to exist on older servers
        if (isset($single_conv->context->inReplyTo->id)) {
            $parent_exists = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1", intval($uid), dbesc($single_conv->context->inReplyTo->id), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
            if ($parent_exists) {
                $parent_uri = $single_conv->context->inReplyTo->id;
            }
        }
        // This is the current way
        if (isset($single_conv->object->inReplyTo->id)) {
            $parent_exists = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1", intval($uid), dbesc($single_conv->object->inReplyTo->id), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
            if ($parent_exists) {
                $parent_uri = $single_conv->object->inReplyTo->id;
            }
        }
        $message_exists = q("SELECT `id`, `parent`, `uri` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1", intval($uid), dbesc($single_conv->id), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
        if ($message_exists) {
            logger("Message " . $single_conv->id . " already existed on the system", LOGGER_DEBUG);
            if ($parent["id"] != 0) {
                $existing_message = $message_exists[0];
                // We improved the way we fetch OStatus messages, this shouldn't happen very often now
                // To-Do: we have to change the shadow copies as well. This way here is really ugly.
                if ($existing_message["parent"] != $parent["id"]) {
                    logger('updating id ' . $existing_message["id"] . ' with parent ' . $existing_message["parent"] . ' to parent ' . $parent["id"] . ' uri ' . $parent["uri"] . ' thread ' . $parent_uri, LOGGER_DEBUG);
                    // Update the parent id of the selected item
                    $r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s' WHERE `id` = %d", intval($parent["id"]), dbesc($parent["uri"]), intval($existing_message["id"]));
                    // Update the parent uri in the thread - but only if it points to itself
                    $r = q("UPDATE `item` SET `thr-parent` = '%s' WHERE `id` = %d AND `uri` = `thr-parent`", dbesc($parent_uri), intval($existing_message["id"]));
                    // try to change all items of the same parent
                    $r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s' WHERE `parent` = %d", intval($parent["id"]), dbesc($parent["uri"]), intval($existing_message["parent"]));
                    // Update the parent uri in the thread - but only if it points to itself
                    $r = q("UPDATE `item` SET `thr-parent` = '%s' WHERE (`parent` = %d) AND (`uri` = `thr-parent`)", dbesc($parent["uri"]), intval($existing_message["parent"]));
                    // Now delete the thread
                    delete_thread($existing_message["parent"]);
                }
            }
            // The item we are having on the system is the one that we wanted to store via the item array
            if (isset($item["uri"]) and $item["uri"] == $existing_message["uri"]) {
                $item = array();
                $item_stored = 0;
            }
            continue;
        }
        if (is_array($single_conv->to)) {
            foreach ($single_conv->to as $to) {
                if ($importer["nurl"] == normalise_link($to->id)) {
                    $mention = true;
                }
            }
        }
        $actor = $single_conv->actor->id;
        if (isset($single_conv->actor->url)) {
            $actor = $single_conv->actor->url;
        }
        $contact = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s' AND `network` != '%s'", $uid, normalise_link($actor), NETWORK_STATUSNET);
        if (count($contact)) {
            logger("Found contact for url " . $actor, LOGGER_DEBUG);
            $contact_id = $contact[0]["id"];
        } else {
            logger("No contact found for url " . $actor, LOGGER_DEBUG);
            // Adding a global contact
            // To-Do: Use this data for the post
            $global_contact_id = get_contact($actor, 0);
            logger("Global contact " . $global_contact_id . " found for url " . $actor, LOGGER_DEBUG);
            $contact_id = $parent["contact-id"];
        }
        $arr = array();
        $arr["network"] = NETWORK_OSTATUS;
        $arr["uri"] = $single_conv->id;
        $arr["plink"] = $plink;
        $arr["uid"] = $uid;
        $arr["contact-id"] = $contact_id;
        $arr["parent-uri"] = $parent_uri;
        $arr["created"] = $single_conv->published;
        $arr["edited"] = $single_conv->published;
        $arr["owner-name"] = $single_conv->actor->displayName;
        if ($arr["owner-name"] == '') {
            $arr["owner-name"] = $single_conv->actor->contact->displayName;
        }
        if ($arr["owner-name"] == '') {
            $arr["owner-name"] = $single_conv->actor->portablecontacts_net->displayName;
        }
        $arr["owner-link"] = $actor;
        $arr["owner-avatar"] = $single_conv->actor->image->url;
        $arr["author-name"] = $arr["owner-name"];
        $arr["author-link"] = $actor;
        $arr["author-avatar"] = $single_conv->actor->image->url;
        $arr["body"] = add_page_info_to_body(html2bbcode($single_conv->content));
        if (isset($single_conv->status_net->notice_info->source)) {
            $arr["app"] = strip_tags($single_conv->status_net->notice_info->source);
        } elseif (isset($single_conv->statusnet->notice_info->source)) {
            $arr["app"] = strip_tags($single_conv->statusnet->notice_info->source);
        } elseif (isset($single_conv->statusnet_notice_info->source)) {
            $arr["app"] = strip_tags($single_conv->statusnet_notice_info->source);
        } elseif (isset($single_conv->provider->displayName)) {
            $arr["app"] = $single_conv->provider->displayName;
        } else {
            $arr["app"] = "OStatus";
        }
        //$arr["app"] .= " (Conversation)";
        $arr["object"] = json_encode($single_conv);
        $arr["verb"] = $parent["verb"];
        $arr["visible"] = $parent["visible"];
        $arr["location"] = $single_conv->location->displayName;
        $arr["coord"] = trim($single_conv->location->lat . " " . $single_conv->location->lon);
        // Is it a reshared item?
        if (isset($single_conv->verb) and $single_conv->verb == "share" and isset($single_conv->object)) {
            if (is_array($single_conv->object)) {
                $single_conv->object = $single_conv->object[0];
            }
            logger("Found reshared item " . $single_conv->object->id);
            // $single_conv->object->context->conversation;
            if (isset($single_conv->object->object->id)) {
                $arr["uri"] = $single_conv->object->object->id;
            } else {
                $arr["uri"] = $single_conv->object->id;
            }
            if (isset($single_conv->object->object->url)) {
                $plink = ostatus_convert_href($single_conv->object->object->url);
            } else {
                $plink = ostatus_convert_href($single_conv->object->url);
            }
            if (isset($single_conv->object->object->content)) {
                $arr["body"] = add_page_info_to_body(html2bbcode($single_conv->object->object->content));
            } else {
                $arr["body"] = add_page_info_to_body(html2bbcode($single_conv->object->content));
            }
            $arr["plink"] = $plink;
            $arr["created"] = $single_conv->object->published;
            $arr["edited"] = $single_conv->object->published;
            $arr["author-name"] = $single_conv->object->actor->displayName;
            if ($arr["owner-name"] == '') {
                $arr["author-name"] = $single_conv->object->actor->contact->displayName;
            }
            $arr["author-link"] = $single_conv->object->actor->url;
            $arr["author-avatar"] = $single_conv->object->actor->image->url;
            $arr["app"] = $single_conv->object->provider->displayName . "#";
            //$arr["verb"] = $single_conv->object->verb;
            $arr["location"] = $single_conv->object->location->displayName;
            $arr["coord"] = trim($single_conv->object->location->lat . " " . $single_conv->object->location->lon);
        }
        if ($arr["location"] == "") {
            unset($arr["location"]);
        }
        if ($arr["coord"] == "") {
            unset($arr["coord"]);
        }
        // Copy fields from given item array
        if (isset($item["uri"]) and ($item["uri"] == $arr["uri"] or $item["uri"] == $single_conv->id)) {
            $copy_fields = array("owner-name", "owner-link", "owner-avatar", "author-name", "author-link", "author-avatar", "gravity", "body", "object-type", "object", "verb", "created", "edited", "coord", "tag", "title", "attach", "app", "type", "location", "contact-id", "uri");
            foreach ($copy_fields as $field) {
                if (isset($item[$field])) {
                    $arr[$field] = $item[$field];
                }
            }
            //$arr["app"] .= " (OStatus)";
        }
        $newitem = item_store($arr);
        if (!$newitem) {
            logger("Item wasn't stored " . print_r($arr, true), LOGGER_DEBUG);
            continue;
        }
        if (isset($item["uri"]) and $item["uri"] == $arr["uri"]) {
            $item = array();
            $item_stored = $newitem;
        }
        logger('Stored new item ' . $plink . ' for parent ' . $arr["parent-uri"] . ' under id ' . $newitem, LOGGER_DEBUG);
        // Add the conversation entry (but don't fetch the whole conversation)
        ostatus_store_conversation($newitem, $conversation_url);
        if ($mention) {
            $u = q("SELECT `notify-flags`, `language`, `username`, `email` FROM user WHERE uid = %d LIMIT 1", intval($uid));
            $r = q("SELECT `parent` FROM `item` WHERE `id` = %d", intval($newitem));
            notification(array('type' => NOTIFY_TAGSELF, 'notify_flags' => $u[0]["notify-flags"], 'language' => $u[0]["language"], 'to_name' => $u[0]["username"], 'to_email' => $u[0]["email"], 'uid' => $uid, 'item' => $arr, 'link' => $a->get_baseurl() . '/display/' . urlencode(get_item_guid($newitem)), 'source_name' => $arr["author-name"], 'source_link' => $arr["author-link"], 'source_photo' => $arr["author-avatar"], 'verb' => ACTIVITY_TAG, 'otype' => 'item', 'parent' => $r[0]["parent"]));
        }
        // If the newly created item is the top item then change the parent settings of the thread
        // This shouldn't happen anymore. This is supposed to be absolote.
        if ($arr["uri"] == $first_id) {
            logger('setting new parent to id ' . $newitem);
            $new_parents = q("SELECT `id`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($uid), intval($newitem));
            if ($new_parents) {
                $parent = $new_parents[0];
            }
        }
    }
    if ($item_stored < 0 and count($item) > 0) {
        //$arr["app"] .= " (OStatus-NoConvFound)";
        $item_stored = item_store($item, true);
        if ($item_stored) {
            logger("Uri " . $item["uri"] . " wasn't found in conversation " . $conversation_url, LOGGER_DEBUG);
            ostatus_store_conversation($item_stored, $conversation_url);
        }
    }
    return $item_stored;
}
예제 #14
0
function import_items($channel, $items, $sync = false, $relocate = null)
{
    if ($channel && $items) {
        $allow_code = false;
        $r = q("select account_id, account_roles, channel_pageflags from account left join channel on channel_account_id = account_id \n\t\t\twhere channel_id = %d limit 1", intval($channel['channel_id']));
        if ($r) {
            if ($r[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE || $r[0]['channel_pageflags'] & PAGE_ALLOWCODE) {
                $allow_code = true;
            }
        }
        $deliver = false;
        // Don't deliver any messages or notifications when importing
        foreach ($items as $i) {
            $item_result = false;
            $item = get_item_elements($i, $allow_code);
            if (!$item) {
                continue;
            }
            if ($relocate && $item['mid'] === $item['parent_mid']) {
                item_url_replace($channel, $item, $relocate['url'], z_root(), $relocate['channel_address']);
            }
            $r = q("select id, edited from item where mid = '%s' and uid = %d limit 1", dbesc($item['mid']), intval($channel['channel_id']));
            if ($r) {
                // flags may have changed and we are probably relocating the post,
                // so force an update even if we have the same timestamp
                if ($item['edited'] >= $r[0]['edited']) {
                    $item['id'] = $r[0]['id'];
                    $item['uid'] = $channel['channel_id'];
                    $item_result = item_store_update($item, $allow_code, $deliver);
                }
            } else {
                $item['aid'] = $channel['channel_account_id'];
                $item['uid'] = $channel['channel_id'];
                $item_result = item_store($item, $allow_code, $deliver);
            }
            if ($sync && $item['item_wall']) {
                // deliver singletons if we have any
                if ($item_result && $item_result['success']) {
                    Zotlabs\Daemon\Master::Summon(['Notifier', 'single_activity', $item_result['item_id']]);
                }
            }
        }
    }
}
예제 #15
0
function subthread_content(&$a)
{
    if (!local_user() && !remote_user()) {
        return;
    }
    $activity = ACTIVITY_FOLLOW;
    $item_id = $a->argc > 1 ? notags(trim($a->argv[1])) : 0;
    $r = q("SELECT * FROM `item` WHERE `parent` = '%s' OR `parent-uri` = '%s' and parent = id LIMIT 1", dbesc($item_id), dbesc($item_id));
    if (!$item_id || !count($r)) {
        logger('subthread: no item ' . $item_id);
        return;
    }
    $item = $r[0];
    $owner_uid = $item['uid'];
    if (!can_write_wall($a, $owner_uid)) {
        return;
    }
    $remote_owner = null;
    if (!$item['wall']) {
        // The top level post may have been written by somebody on another system
        $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($item['contact-id']), intval($item['uid']));
        if (!count($r)) {
            return;
        }
        if (!$r[0]['self']) {
            $remote_owner = $r[0];
        }
    }
    // this represents the post owner on this system.
    $r = q("SELECT `contact`.*, `user`.`nickname` FROM `contact` LEFT JOIN `user` ON `contact`.`uid` = `user`.`uid`\n\t\tWHERE `contact`.`self` = 1 AND `contact`.`uid` = %d LIMIT 1", intval($owner_uid));
    if (count($r)) {
        $owner = $r[0];
    }
    if (!$owner) {
        logger('like: no owner');
        return;
    }
    if (!$remote_owner) {
        $remote_owner = $owner;
    }
    // This represents the person posting
    if (local_user() && local_user() == $owner_uid) {
        $contact = $owner;
    } else {
        $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($_SESSION['visitor_id']), intval($owner_uid));
        if (count($r)) {
            $contact = $r[0];
        }
    }
    if (!$contact) {
        return;
    }
    $uri = item_new_uri($a->get_hostname(), $owner_uid);
    $post_type = $item['resource-id'] ? t('photo') : t('status');
    $objtype = $item['resource-id'] ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE;
    $link = xmlify('<link rel="alternate" type="text/html" href="' . $a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . '" />' . "\n");
    $body = $item['body'];
    $obj = <<<EOT

\t<object>
\t\t<type>{$objtype}</type>
\t\t<local>1</local>
\t\t<id>{$item['uri']}</id>
\t\t<link>{$link}</link>
\t\t<title></title>
\t\t<content>{$body}</content>
\t</object>
EOT;
    $bodyverb = t('%1$s is following %2$s\'s %3$s');
    if (!isset($bodyverb)) {
        return;
    }
    $arr = array();
    $arr['uri'] = $uri;
    $arr['uid'] = $owner_uid;
    $arr['contact-id'] = $contact['id'];
    $arr['type'] = 'activity';
    $arr['wall'] = $item['wall'];
    $arr['origin'] = 1;
    $arr['gravity'] = GRAVITY_LIKE;
    $arr['parent'] = $item['id'];
    $arr['parent-uri'] = $item['uri'];
    $arr['thr-parent'] = $item['uri'];
    $arr['owner-name'] = $remote_owner['name'];
    $arr['owner-link'] = $remote_owner['url'];
    $arr['owner-avatar'] = $remote_owner['thumb'];
    $arr['author-name'] = $contact['name'];
    $arr['author-link'] = $contact['url'];
    $arr['author-avatar'] = $contact['thumb'];
    $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
    $alink = '[url=' . $item['author-link'] . ']' . $item['author-name'] . '[/url]';
    $plink = '[url=' . $a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . ']' . $post_type . '[/url]';
    $arr['body'] = sprintf($bodyverb, $ulink, $alink, $plink);
    $arr['verb'] = $activity;
    $arr['object-type'] = $objtype;
    $arr['object'] = $obj;
    $arr['allow_cid'] = $item['allow_cid'];
    $arr['allow_gid'] = $item['allow_gid'];
    $arr['deny_cid'] = $item['deny_cid'];
    $arr['deny_gid'] = $item['deny_gid'];
    $arr['visible'] = 1;
    $arr['unseen'] = 1;
    $arr['last-child'] = 0;
    $post_id = item_store($arr);
    if (!$item['visible']) {
        $r = q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($item['id']), intval($owner_uid));
    }
    $arr['id'] = $post_id;
    call_hooks('post_local_end', $arr);
    killme();
}
예제 #16
0
파일: map.php 프로젝트: anaqreon/ownmapp
/**
 * API: map_shareUserLocation
 * Share real-time location data by generating an access token and posting it. 
 * $data contains the ACL specified by the user. The access token is returned
 * @param type $data
 */
function map_shareUserLocation($data)
{
    $resource_type = 'locserv';
    $token = random_string();
    //Extract the ACL for permissions
    $args = array();
    $args['allow_cid'] = perms2str($data['contact_allow']);
    $args['allow_gid'] = perms2str($data['group_allow']);
    $args['deny_cid'] = perms2str($data['contact_deny']);
    $args['deny_gid'] = perms2str($data['group_deny']);
    $args['token'] = $token;
    array_key_exists('token', $args) ? $token = $args['token'] : ($token = '');
    $channel = App::get_channel();
    $observer = App::get_observer();
    $acl = new Zotlabs\Access\AccessList($channel);
    if (array_key_exists('allow_cid', $args)) {
        $acl->set($args);
    }
    $ac = $acl->get();
    $mid = item_message_id();
    // Generate a unique message ID
    $arr = array();
    // Initialize the array of parameters for the post
    // If this were an actual location, ACTIVITY_OBJ_LOCATION would make sense,
    // but since this is actually an access token to retrieve location data, we'll
    // have to use something more vague
    $objtype = ACTIVITY_OBJ_THING;
    //check if item for this object exists
    $y = q("SELECT mid FROM item WHERE obj_type = '%s' AND resource_type = '%s' AND resource_id = '%s' AND uid = %d LIMIT 1", dbesc(ACTIVITY_POST), dbesc($resource_type), dbesc($token), intval($channel['channel_id']));
    if ($y) {
        notice('Error posting access token. Item already exists.');
        logger('map plugin: Error posting access token. item already exists: ' . json_encode($y));
        die;
    }
    $body = $channel['channel_name'] . ' shared their location with you. ';
    $link = z_root() . '/map/?action=getLatestLocation&token=' . $token;
    /*
     * The local map plugin link for the receiver only needs the token. The plugin
     * will look up the stored item table record and use the object->locationDataType
     * to determine what kind of location data has been shared. This will allow it
     * to make the proper request for data to the sharer's hub. For example, if the
     * object->locationDataType is a dynamicMarker, then the receiver will request
     * only the most recent location associated with that token
     */
    $body .= '[url=' . z_root() . '/map?action=getLatestLocation&token=' . $token . ']Click here to view[/url]';
    // Encode object according to Activity Streams: http://activitystrea.ms/specs/json/1.0/
    $object = json_encode(array('type' => $objtype, 'title' => 'location data access token', 'locationDataType' => 'dynamicMarker', 'id' => $token, 'url' => $link));
    if (intval($data['visible']) || $data['visible'] === 'true') {
        $visible = 1;
    } else {
        $visible = 0;
    }
    $item_hidden = $visible ? 0 : 1;
    $arr['aid'] = $channel['channel_account_id'];
    $arr['uid'] = $channel['channel_id'];
    $arr['mid'] = $mid;
    $arr['parent_mid'] = $mid;
    $arr['item_hidden'] = $item_hidden;
    $arr['resource_type'] = $resource_type;
    $arr['resource_id'] = $token;
    $arr['owner_xchan'] = $channel['channel_hash'];
    $arr['author_xchan'] = $observer['xchan_hash'];
    $arr['title'] = 'Shared Location';
    $arr['allow_cid'] = $ac['allow_cid'];
    $arr['allow_gid'] = $ac['allow_gid'];
    $arr['deny_cid'] = $ac['deny_cid'];
    $arr['deny_gid'] = $ac['deny_gid'];
    $arr['item_wall'] = 0;
    $arr['item_origin'] = 1;
    $arr['item_thread_top'] = 1;
    $arr['item_private'] = intval($acl->is_private());
    $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid'];
    $arr['verb'] = ACTIVITY_POST;
    $arr['obj_type'] = $objtype;
    $arr['object'] = $object;
    $arr['body'] = $body;
    $post = item_store($arr);
    $item_id = $post['item_id'];
    if ($item_id) {
        proc_run('php', "include/notifier.php", "activity", $item_id);
        echo json_encode(array('item' => $arr, 'status' => true));
    } else {
        echo json_encode(array('item' => null, 'status' => false));
    }
    die;
}
예제 #17
0
/**
 * @brief Activity for files.
 *
 * @param int $channel_id
 * @param array $object
 * @param string $allow_cid
 * @param string $allow_gid
 * @param string $deny_cid
 * @param string $deny_gid
 * @param string $verb
 * @param boolean $no_activity
 */
function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $verb, $notify)
{
    require_once 'include/items.php';
    $poster = get_app()->get_observer();
    //if we got no object something went wrong
    if (!$object) {
        return;
    }
    //turn strings into arrays
    $arr_allow_cid = expand_acl($allow_cid);
    $arr_allow_gid = expand_acl($allow_gid);
    $arr_deny_cid = expand_acl($deny_cid);
    $arr_deny_gid = expand_acl($deny_gid);
    //filter out receivers which do not have permission to view filestorage
    $arr_allow_cid = check_list_permissions($channel_id, $arr_allow_cid, 'view_storage');
    $is_dir = intval($object['is_dir']) ? true : false;
    //do not send activity for folders for now
    if ($is_dir) {
        return;
    }
    //check for recursive perms if we are in a folder
    if ($object['folder']) {
        $folder_hash = $object['folder'];
        $r_perms = recursive_activity_recipients($arr_allow_cid, $arr_allow_gid, $arr_deny_cid, $arr_deny_gid, $folder_hash);
        //split up returned perms
        $arr_allow_cid = $r_perms['allow_cid'];
        $arr_allow_gid = $r_perms['allow_gid'];
        $arr_deny_cid = $r_perms['deny_cid'];
        $arr_deny_gid = $r_perms['deny_gid'];
        //filter out receivers which do not have permission to view filestorage
        $arr_allow_cid = check_list_permissions($channel_id, $arr_allow_cid, 'view_storage');
    }
    $mid = item_message_id();
    $arr = array();
    $arr['item_wall'] = 1;
    $arr['item_origin'] = 1;
    $arr['item_unseen'] = 1;
    $objtype = ACTIVITY_OBJ_FILE;
    $private = $arr_allow_cid[0] || $arr_allow_gid[0] || $arr_deny_cid[0] || $arr_deny_gid[0] ? 1 : 0;
    $jsonobject = json_encode($object);
    //check if item for this object exists
    $y = q("SELECT mid FROM item WHERE verb = '%s' AND obj_type = '%s' AND resource_id = '%s' AND uid = %d LIMIT 1", dbesc(ACTIVITY_POST), dbesc($objtype), dbesc($object['hash']), intval(local_channel()));
    if ($y) {
        $update = true;
        $object['d_mid'] = $y[0]['mid'];
        //attach mid of the old object
        $u_jsonobject = json_encode($object);
        //we have got the relevant info - delete the old item before we create the new one
        $z = q("DELETE FROM item WHERE obj_type = '%s' AND verb = '%s' AND mid = '%s'", dbesc(ACTIVITY_OBJ_FILE), dbesc(ACTIVITY_POST), dbesc($y[0]['mid']));
    }
    if ($update && $verb == 'post') {
        //send update activity and create a new one
        //updates should be sent to everybody with recursive perms and all eventual former allowed members ($object['allow_cid'] etc.).
        $u_arr_allow_cid = array_unique(array_merge($arr_allow_cid, expand_acl($object['allow_cid'])));
        $u_arr_allow_gid = array_unique(array_merge($arr_allow_gid, expand_acl($object['allow_gid'])));
        $u_arr_deny_cid = array_unique(array_merge($arr_deny_cid, expand_acl($object['deny_cid'])));
        $u_arr_deny_gid = array_unique(array_merge($arr_deny_gid, expand_acl($object['deny_gid'])));
        $u_mid = item_message_id();
        $arr['aid'] = get_account_id();
        $arr['uid'] = $channel_id;
        $arr['mid'] = $u_mid;
        $arr['parent_mid'] = $u_mid;
        $arr['author_xchan'] = $poster['xchan_hash'];
        $arr['owner_xchan'] = $poster['xchan_hash'];
        $arr['title'] = '';
        //updates should be visible to everybody -> perms may have changed
        $arr['allow_cid'] = '';
        $arr['allow_gid'] = '';
        $arr['deny_cid'] = '';
        $arr['deny_gid'] = '';
        $arr['item_hidden'] = 1;
        $arr['item_private'] = 0;
        $arr['verb'] = ACTIVITY_UPDATE;
        $arr['obj_type'] = $objtype;
        $arr['object'] = $u_jsonobject;
        $arr['resource_id'] = $object['hash'];
        $arr['resource_type'] = 'attach';
        $arr['body'] = '';
        $post = item_store($arr);
        $item_id = $post['item_id'];
        if ($item_id) {
            proc_run('php', "include/notifier.php", "activity", $item_id);
        }
        call_hooks('post_local_end', $arr);
        $update = false;
        //notice( t('File activity updated') . EOL);
    }
    if (!$notify) {
        return;
    }
    $arr = array();
    $arr['aid'] = get_account_id();
    $arr['uid'] = $channel_id;
    $arr['mid'] = $mid;
    $arr['parent_mid'] = $mid;
    $arr['item_wall'] = 1;
    $arr['item_origin'] = 1;
    $arr['item_unseen'] = 1;
    $arr['author_xchan'] = $poster['xchan_hash'];
    $arr['owner_xchan'] = $poster['xchan_hash'];
    $arr['title'] = '';
    $arr['allow_cid'] = perms2str($arr_allow_cid);
    $arr['allow_gid'] = perms2str($arr_allow_gid);
    $arr['deny_cid'] = perms2str($arr_deny_cid);
    $arr['deny_gid'] = perms2str($arr_deny_gid);
    $arr['item_hidden'] = 1;
    $arr['item_private'] = $private;
    $arr['verb'] = $update ? ACTIVITY_UPDATE : ACTIVITY_POST;
    $arr['obj_type'] = $objtype;
    $arr['resource_id'] = $object['hash'];
    $arr['resource_type'] = 'attach';
    $arr['object'] = $update ? $u_jsonobject : $jsonobject;
    $arr['body'] = '';
    $post = item_store($arr);
    $item_id = $post['item_id'];
    if ($item_id) {
        proc_run('php', "include/notifier.php", "activity", $item_id);
    }
    call_hooks('post_local_end', $arr);
    //(($verb === 'post') ?  notice( t('File activity posted') . EOL) : notice( t('File activity dropped') . EOL));
    return;
}
예제 #18
0
 function get()
 {
     if (!local_channel() && !remote_channel()) {
         return;
     }
     $item_id = argc() > 2 ? notags(trim(argv(2))) : 0;
     if (argv(1) === 'sub') {
         $activity = ACTIVITY_FOLLOW;
     } elseif (argv(1) === 'unsub') {
         $activity = ACTIVITY_UNFOLLOW;
     }
     $r = q("SELECT parent FROM item WHERE id = '%s'", dbesc($item_id));
     if ($r) {
         $r = q("select * from item where id = parent and id = %d limit 1", dbesc($r[0]['parent']));
     }
     if (!$item_id || !$r) {
         logger('subthread: no item ' . $item_id);
         return;
     }
     $item = $r[0];
     $owner_uid = $item['uid'];
     $observer = \App::get_observer();
     $ob_hash = $observer ? $observer['xchan_hash'] : '';
     if (!perm_is_allowed($owner_uid, $ob_hash, 'post_comments')) {
         return;
     }
     $sys = get_sys_channel();
     $owner_uid = $item['uid'];
     $owner_aid = $item['aid'];
     // if this is a "discover" item, (item['uid'] is the sys channel),
     // fallback to the item comment policy, which should've been
     // respected when generating the conversation thread.
     // Even if the activity is rejected by the item owner, it should still get attached
     // to the local discover conversation on this site.
     if ($owner_uid != $sys['channel_id'] && !perm_is_allowed($owner_uid, $observer['xchan_hash'], 'post_comments')) {
         notice(t('Permission denied') . EOL);
         killme();
     }
     $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($item['owner_xchan']));
     if ($r) {
         $thread_owner = $r[0];
     } else {
         killme();
     }
     $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($item['author_xchan']));
     if ($r) {
         $item_author = $r[0];
     } else {
         killme();
     }
     $mid = item_message_id();
     $post_type = $item['resource_type'] === 'photo' ? t('photo') : t('status');
     $links = array(array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item['plink']));
     $objtype = $item['resource_type'] === 'photo' ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE;
     $body = $item['body'];
     $obj = json_encode(array('type' => $objtype, 'id' => $item['mid'], 'parent' => $item['thr_parent'] ? $item['thr_parent'] : $item['parent_mid'], 'link' => $links, 'title' => $item['title'], 'content' => $item['body'], 'created' => $item['created'], 'edited' => $item['edited'], 'author' => array('name' => $item_author['xchan_name'], 'address' => $item_author['xchan_addr'], 'guid' => $item_author['xchan_guid'], 'guid_sig' => $item_author['xchan_guid_sig'], 'link' => array(array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item_author['xchan_url']), array('rel' => 'photo', 'type' => $item_author['xchan_photo_mimetype'], 'href' => $item_author['xchan_photo_m'])))));
     if (!intval($item['item_thread_top'])) {
         $post_type = 'comment';
     }
     if ($activity === ACTIVITY_FOLLOW) {
         $bodyverb = t('%1$s is following %2$s\'s %3$s');
     }
     if ($activity === ACTIVITY_UNFOLLOW) {
         $bodyverb = t('%1$s stopped following %2$s\'s %3$s');
     }
     $arr = array();
     $arr['mid'] = $mid;
     $arr['aid'] = $owner_aid;
     $arr['uid'] = $owner_uid;
     $arr['parent'] = $item['id'];
     $arr['parent_mid'] = $item['mid'];
     $arr['thr_parent'] = $item['mid'];
     $arr['owner_xchan'] = $thread_owner['xchan_hash'];
     $arr['author_xchan'] = $observer['xchan_hash'];
     $arr['item_origin'] = 1;
     $arr['item_notshown'] = 1;
     if (intval($item['item_wall'])) {
         $arr['item_wall'] = 1;
     } else {
         $arr['item_wall'] = 0;
     }
     $ulink = '[zrl=' . $item_author['xchan_url'] . ']' . $item_author['xchan_name'] . '[/zrl]';
     $alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]';
     $plink = '[zrl=' . z_root() . '/display/' . $item['mid'] . ']' . $post_type . '[/zrl]';
     $arr['body'] = sprintf($bodyverb, $alink, $ulink, $plink);
     $arr['verb'] = $activity;
     $arr['obj_type'] = $objtype;
     $arr['object'] = $obj;
     $arr['allow_cid'] = $item['allow_cid'];
     $arr['allow_gid'] = $item['allow_gid'];
     $arr['deny_cid'] = $item['deny_cid'];
     $arr['deny_gid'] = $item['deny_gid'];
     $post = item_store($arr);
     $post_id = $post['item_id'];
     $arr['id'] = $post_id;
     call_hooks('post_local_end', $arr);
     killme();
 }
예제 #19
0
function item_post(&$a)
{
    // This will change. Figure out who the observer is and whether or not
    // they have permission to post here. Else ignore the post.
    if (!local_channel() && !remote_channel() && !x($_REQUEST, 'commenter')) {
        return;
    }
    require_once 'include/security.php';
    $uid = local_channel();
    $channel = null;
    $observer = null;
    /**
     * Is this a reply to something?
     */
    $parent = x($_REQUEST, 'parent') ? intval($_REQUEST['parent']) : 0;
    $parent_mid = x($_REQUEST, 'parent_mid') ? trim($_REQUEST['parent_mid']) : '';
    $remote_xchan = x($_REQUEST, 'remote_xchan') ? trim($_REQUEST['remote_xchan']) : false;
    $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($remote_xchan));
    if ($r) {
        $remote_observer = $r[0];
    } else {
        $remote_xchan = $remote_observer = false;
    }
    $profile_uid = x($_REQUEST, 'profile_uid') ? intval($_REQUEST['profile_uid']) : 0;
    require_once 'include/identity.php';
    $sys = get_sys_channel();
    if ($sys && $profile_uid && $sys['channel_id'] == $profile_uid && is_site_admin()) {
        $uid = intval($sys['channel_id']);
        $channel = $sys;
        $observer = $sys;
    }
    if (x($_REQUEST, 'dropitems')) {
        require_once 'include/items.php';
        $arr_drop = explode(',', $_REQUEST['dropitems']);
        drop_items($arr_drop);
        $json = array('success' => 1);
        echo json_encode($json);
        killme();
    }
    call_hooks('post_local_start', $_REQUEST);
    //	 logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA);
    $api_source = x($_REQUEST, 'api_source') && $_REQUEST['api_source'] ? true : false;
    $consensus = intval($_REQUEST['consensus']);
    // 'origin' (if non-zero) indicates that this network is where the message originated,
    // for the purpose of relaying comments to other conversation members.
    // If using the API from a device (leaf node) you must set origin to 1 (default) or leave unset.
    // If the API is used from another network with its own distribution
    // and deliveries, you may wish to set origin to 0 or false and allow the other
    // network to relay comments.
    // If you are unsure, it is prudent (and important) to leave it unset.
    $origin = $api_source && array_key_exists('origin', $_REQUEST) ? intval($_REQUEST['origin']) : 1;
    // To represent message-ids on other networks - this will create an item_id record
    $namespace = $api_source && array_key_exists('namespace', $_REQUEST) ? strip_tags($_REQUEST['namespace']) : '';
    $remote_id = $api_source && array_key_exists('remote_id', $_REQUEST) ? strip_tags($_REQUEST['remote_id']) : '';
    $owner_hash = null;
    $message_id = x($_REQUEST, 'message_id') && $api_source ? strip_tags($_REQUEST['message_id']) : '';
    $created = x($_REQUEST, 'created') ? datetime_convert('UTC', 'UTC', $_REQUEST['created']) : datetime_convert();
    $post_id = x($_REQUEST, 'post_id') ? intval($_REQUEST['post_id']) : 0;
    $app = x($_REQUEST, 'source') ? strip_tags($_REQUEST['source']) : '';
    $return_path = x($_REQUEST, 'return') ? $_REQUEST['return'] : '';
    $preview = x($_REQUEST, 'preview') ? intval($_REQUEST['preview']) : 0;
    $categories = x($_REQUEST, 'category') ? escape_tags($_REQUEST['category']) : '';
    $webpage = x($_REQUEST, 'webpage') ? intval($_REQUEST['webpage']) : 0;
    $pagetitle = x($_REQUEST, 'pagetitle') ? escape_tags(urlencode($_REQUEST['pagetitle'])) : '';
    $layout_mid = x($_REQUEST, 'layout_mid') ? escape_tags($_REQUEST['layout_mid']) : '';
    $plink = x($_REQUEST, 'permalink') ? escape_tags($_REQUEST['permalink']) : '';
    $obj_type = x($_REQUEST, 'obj_type') ? escape_tags($_REQUEST['obj_type']) : ACTIVITY_OBJ_NOTE;
    // allow API to bulk load a bunch of imported items with sending out a bunch of posts.
    $nopush = x($_REQUEST, 'nopush') ? intval($_REQUEST['nopush']) : 0;
    /*
     * Check service class limits
     */
    if ($uid && !x($_REQUEST, 'parent') && !x($_REQUEST, 'post_id')) {
        $ret = item_check_service_class($uid, $_REQUEST['webpage'] == ITEM_WEBPAGE ? true : false);
        if (!$ret['success']) {
            notice(t($ret['message']) . EOL);
            if (x($_REQUEST, 'return')) {
                goaway($a->get_baseurl() . "/" . $return_path);
            }
            killme();
        }
    }
    if ($pagetitle) {
        require_once 'library/urlify/URLify.php';
        $pagetitle = strtolower(URLify::transliterate($pagetitle));
    }
    $item_flags = $item_restrict = 0;
    $route = '';
    $parent_item = null;
    $parent_contact = null;
    $thr_parent = '';
    $parid = 0;
    $r = false;
    if ($parent || $parent_mid) {
        if (!x($_REQUEST, 'type')) {
            $_REQUEST['type'] = 'net-comment';
        }
        if ($obj_type == ACTIVITY_OBJ_POST) {
            $obj_type = ACTIVITY_OBJ_COMMENT;
        }
        if ($parent) {
            $r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1", intval($parent));
        } elseif ($parent_mid && $uid) {
            // This is coming from an API source, and we are logged in
            $r = q("SELECT * FROM `item` WHERE `mid` = '%s' AND `uid` = %d LIMIT 1", dbesc($parent_mid), intval($uid));
        }
        // if this isn't the real parent of the conversation, find it
        if ($r !== false && count($r)) {
            $parid = $r[0]['parent'];
            $parent_mid = $r[0]['mid'];
            if ($r[0]['id'] != $r[0]['parent']) {
                $r = q("SELECT * FROM `item` WHERE `id` = `parent` AND `parent` = %d LIMIT 1", intval($parid));
            }
        }
        if ($r === false || !count($r)) {
            notice(t('Unable to locate original post.') . EOL);
            if (x($_REQUEST, 'return')) {
                goaway($a->get_baseurl() . "/" . $return_path);
            }
            killme();
        }
        // can_comment_on_post() needs info from the following xchan_query
        xchan_query($r);
        $parent_item = $r[0];
        $parent = $r[0]['id'];
        // multi-level threading - preserve the info but re-parent to our single level threading
        $thr_parent = $parent_mid;
        $route = $parent_item['route'];
    }
    if (!$observer) {
        $observer = $a->get_observer();
    }
    if ($parent) {
        logger('mod_item: item_post parent=' . $parent);
        $can_comment = false;
        if (array_key_exists('owner', $parent_item) && $parent_item['owner']['abook_flags'] & ABOOK_FLAG_SELF) {
            $can_comment = perm_is_allowed($profile_uid, $observer['xchan_hash'], 'post_comments');
        } else {
            $can_comment = can_comment_on_post($observer['xchan_hash'], $parent_item);
        }
        if (!$can_comment) {
            notice(t('Permission denied.') . EOL);
            if (x($_REQUEST, 'return')) {
                goaway($a->get_baseurl() . "/" . $return_path);
            }
            killme();
        }
    } else {
        if (!perm_is_allowed($profile_uid, $observer['xchan_hash'], 'post_wall')) {
            notice(t('Permission denied.') . EOL);
            if (x($_REQUEST, 'return')) {
                goaway($a->get_baseurl() . "/" . $return_path);
            }
            killme();
        }
    }
    // is this an edited post?
    $orig_post = null;
    if ($namespace && $remote_id) {
        // It wasn't an internally generated post - see if we've got an item matching this remote service id
        $i = q("select iid from item_id where service = '%s' and sid = '%s' limit 1", dbesc($namespace), dbesc($remote_id));
        if ($i) {
            $post_id = $i[0]['iid'];
        }
    }
    if ($post_id) {
        $i = q("SELECT * FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($post_id));
        if (!count($i)) {
            killme();
        }
        $orig_post = $i[0];
    }
    if (!$channel) {
        if ($uid && $uid == $profile_uid) {
            $channel = $a->get_channel();
        } else {
            // posting as yourself but not necessarily to a channel you control
            $r = q("select * from channel left join account on channel_account_id = account_id where channel_id = %d LIMIT 1", intval($profile_uid));
            if ($r) {
                $channel = $r[0];
            }
        }
    }
    if (!$channel) {
        logger("mod_item: no channel.");
        if (x($_REQUEST, 'return')) {
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        killme();
    }
    $owner_xchan = null;
    $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($channel['channel_hash']));
    if ($r && count($r)) {
        $owner_xchan = $r[0];
    } else {
        logger("mod_item: no owner.");
        if (x($_REQUEST, 'return')) {
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        killme();
    }
    $walltowall = false;
    $walltowall_comment = false;
    if ($remote_xchan) {
        $observer = $remote_observer;
    }
    if ($observer) {
        logger('mod_item: post accepted from ' . $observer['xchan_name'] . ' for ' . $owner_xchan['xchan_name'], LOGGER_DEBUG);
        // wall-to-wall detection.
        // For top-level posts, if the author and owner are different it's a wall-to-wall
        // For comments, We need to additionally look at the parent and see if it's a wall post that originated locally.
        if ($observer['xchan_name'] != $owner_xchan['xchan_name']) {
            if ($parent_item && ($parent_item['item_flags'] & (ITEM_WALL | ITEM_ORIGIN)) == (ITEM_WALL | ITEM_ORIGIN)) {
                $walltowall_comment = true;
                $walltowall = true;
            }
            if (!$parent) {
                $walltowall = true;
            }
        }
    }
    $public_policy = x($_REQUEST, 'public_policy') ? escape_tags($_REQUEST['public_policy']) : map_scope($channel['channel_r_stream'], true);
    if ($webpage) {
        $public_policy = '';
    }
    if ($public_policy) {
        $private = 1;
    }
    if ($orig_post) {
        $private = 0;
        // webpages are allowed to change ACLs after the fact. Normal conversation items aren't.
        if ($webpage) {
            $str_group_allow = perms2str($_REQUEST['group_allow']);
            $str_contact_allow = perms2str($_REQUEST['contact_allow']);
            $str_group_deny = perms2str($_REQUEST['group_deny']);
            $str_contact_deny = perms2str($_REQUEST['contact_deny']);
        } else {
            $str_group_allow = $orig_post['allow_gid'];
            $str_contact_allow = $orig_post['allow_cid'];
            $str_group_deny = $orig_post['deny_gid'];
            $str_contact_deny = $orig_post['deny_cid'];
            $public_policy = $orig_post['public_policy'];
            $private = $orig_post['item_private'];
        }
        if (strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny) || strlen($public_policy) || $private) {
            $private = 1;
        }
        $location = $orig_post['location'];
        $coord = $orig_post['coord'];
        $verb = $orig_post['verb'];
        $app = $orig_post['app'];
        $title = escape_tags(trim($_REQUEST['title']));
        $body = trim($_REQUEST['body']);
        $item_flags = $orig_post['item_flags'];
        // force us to recalculate if we need to obscure this post
        if ($item_flags & ITEM_OBSCURED) {
            $item_flags = $item_flags ^ ITEM_OBSCURED;
        }
        $item_restrict = $orig_post['item_restrict'];
        $postopts = $orig_post['postopts'];
        $created = $orig_post['created'];
        $mid = $orig_post['mid'];
        $parent_mid = $orig_post['parent_mid'];
        $plink = $orig_post['plink'];
    } else {
        // if coming from the API and no privacy settings are set,
        // use the user default permissions - as they won't have
        // been supplied via a form.
        if ($api_source && !array_key_exists('contact_allow', $_REQUEST) && !array_key_exists('group_allow', $_REQUEST) && !array_key_exists('contact_deny', $_REQUEST) && !array_key_exists('group_deny', $_REQUEST)) {
            $str_group_allow = $channel['channel_allow_gid'];
            $str_contact_allow = $channel['channel_allow_cid'];
            $str_group_deny = $channel['channel_deny_gid'];
            $str_contact_deny = $channel['channel_deny_cid'];
        } elseif ($walltowall) {
            // use the channel owner's default permissions
            $str_group_allow = $channel['channel_allow_gid'];
            $str_contact_allow = $channel['channel_allow_cid'];
            $str_group_deny = $channel['channel_deny_gid'];
            $str_contact_deny = $channel['channel_deny_cid'];
        } else {
            // use the posted permissions
            $str_group_allow = perms2str($_REQUEST['group_allow']);
            $str_contact_allow = perms2str($_REQUEST['contact_allow']);
            $str_group_deny = perms2str($_REQUEST['group_deny']);
            $str_contact_deny = perms2str($_REQUEST['contact_deny']);
        }
        $location = notags(trim($_REQUEST['location']));
        $coord = notags(trim($_REQUEST['coord']));
        $verb = notags(trim($_REQUEST['verb']));
        $title = escape_tags(trim($_REQUEST['title']));
        $body = trim($_REQUEST['body']);
        $body .= trim($_REQUEST['attachment']);
        $postopts = '';
        $private = strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny) || strlen($public_policy) ? 1 : 0;
        // If this is a comment, set the permissions from the parent.
        if ($parent_item) {
            $private = 0;
            if ($parent_item['item_private'] || strlen($parent_item['allow_cid']) || strlen($parent_item['allow_gid']) || strlen($parent_item['deny_cid']) || strlen($parent_item['deny_gid']) || strlen($parent_item['public_policy'])) {
                $private = $parent_item['item_private'] ? $parent_item['item_private'] : 1;
            }
            $public_policy = $parent_item['public_policy'];
            $str_contact_allow = $parent_item['allow_cid'];
            $str_group_allow = $parent_item['allow_gid'];
            $str_contact_deny = $parent_item['deny_cid'];
            $str_group_deny = $parent_item['deny_gid'];
            $owner_hash = $parent_item['owner_xchan'];
        }
        if (!strlen($body)) {
            if ($preview) {
                killme();
            }
            info(t('Empty post discarded.') . EOL);
            if (x($_REQUEST, 'return')) {
                goaway($a->get_baseurl() . "/" . $return_path);
            }
            killme();
        }
    }
    $expires = NULL_DATE;
    if (feature_enabled($profile_uid, 'content_expire')) {
        if (x($_REQUEST, 'expire')) {
            $expires = datetime_convert(date_default_timezone_get(), 'UTC', $_REQUEST['expire']);
            if ($expires <= datetime_convert()) {
                $expires = NULL_DATE;
            }
        }
    }
    $mimetype = notags(trim($_REQUEST['mimetype']));
    if (!$mimetype) {
        $mimetype = 'text/bbcode';
    }
    if ($preview) {
        $body = z_input_filter($profile_uid, $body, $mimetype);
    }
    // Verify ability to use html or php!!!
    $execflag = false;
    if ($mimetype === 'application/x-php') {
        $z = q("select account_id, account_roles, channel_pageflags from account left join channel on channel_account_id = account_id where channel_id = %d limit 1", intval($profile_uid));
        if ($z && ($z[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE || $z[0]['channel_pageflags'] & PAGE_ALLOWCODE)) {
            if ($uid && get_account_id() == $z[0]['account_id']) {
                $execflag = true;
            } else {
                notice(t('Executable content type not permitted to this channel.') . EOL);
                if (x($_REQUEST, 'return')) {
                    goaway($a->get_baseurl() . "/" . $return_path);
                }
                killme();
            }
        }
    }
    if ($mimetype === 'text/bbcode') {
        require_once 'include/text.php';
        if ($uid && $uid == $profile_uid && feature_enabled($uid, 'markdown')) {
            require_once 'include/bb2diaspora.php';
            $body = escape_tags($body);
            $body = preg_replace_callback('/\\[share(.*?)\\]/ism', 'share_shield', $body);
            $body = diaspora2bb($body, true);
            $body = preg_replace_callback('/\\[share(.*?)\\]/ism', 'share_unshield', $body);
        }
        // BBCODE alert: the following functions assume bbcode input
        // and will require alternatives for alternative content-types (text/html, text/markdown, text/plain, etc.)
        // we may need virtual or template classes to implement the possible alternatives
        // Work around doubled linefeeds in Tinymce 3.5b2
        // First figure out if it's a status post that would've been
        // created using tinymce. Otherwise leave it alone.
        $plaintext = true;
        //		$plaintext = ((feature_enabled($profile_uid,'richtext')) ? false : true);
        //		if((! $parent) && (! $api_source) && (! $plaintext)) {
        //			$body = fix_mce_lf($body);
        //		}
        // If we're sending a private top-level message with a single @-taggable channel as a recipient, @-tag it, if our pconfig is set.
        if (!$parent && get_pconfig($profile_uid, 'system', 'tagifonlyrecip') && substr_count($str_contact_allow, '<') == 1 && $str_group_allow == '' && $str_contact_deny == '' && $str_group_deny == '') {
            $x = q("select abook_id, abook_their_perms from abook where abook_xchan = '%s' and abook_channel = %d limit 1", dbesc(str_replace(array('<', '>'), array('', ''), $str_contact_allow)), intval($profile_uid));
            if ($x && $x[0]['abook_their_perms'] & PERMS_W_TAGWALL) {
                $body .= "\n\n@group+" . $x[0]['abook_id'] . "\n";
            }
        }
        /**
         * fix naked links by passing through a callback to see if this is a red site
         * (already known to us) which will get a zrl, otherwise link with url, add bookmark tag to both.
         * First protect any url inside certain bbcode tags so we don't double link it.
         */
        $body = preg_replace_callback('/\\[code(.*?)\\[\\/(code)\\]/ism', 'red_escape_codeblock', $body);
        $body = preg_replace_callback('/\\[url(.*?)\\[\\/(url)\\]/ism', 'red_escape_codeblock', $body);
        $body = preg_replace_callback('/\\[zrl(.*?)\\[\\/(zrl)\\]/ism', 'red_escape_codeblock', $body);
        $body = preg_replace_callback("/([^\\]\\='" . '"' . "\\/]|^|\\#\\^)(https?\\:\\/\\/[a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\@\\_\\~\\#\\%\$\\!\\+\\,]+)/ism", 'red_zrl_callback', $body);
        $body = preg_replace_callback('/\\[\\$b64zrl(.*?)\\[\\/(zrl)\\]/ism', 'red_unescape_codeblock', $body);
        $body = preg_replace_callback('/\\[\\$b64url(.*?)\\[\\/(url)\\]/ism', 'red_unescape_codeblock', $body);
        $body = preg_replace_callback('/\\[\\$b64code(.*?)\\[\\/(code)\\]/ism', 'red_unescape_codeblock', $body);
        // fix any img tags that should be zmg
        $body = preg_replace_callback('/\\[img(.*?)\\](.*?)\\[\\/img\\]/ism', 'red_zrlify_img_callback', $body);
        $body = bb_translate_video($body);
        /**
         * Fold multi-line [code] sequences
         */
        $body = preg_replace('/\\[\\/code\\]\\s*\\[code\\]/ism', "\n", $body);
        $body = scale_external_images($body, false);
        // Look for tags and linkify them
        $results = linkify_tags($a, $body, $uid ? $uid : $profile_uid);
        if ($results) {
            // Set permissions based on tag replacements
            set_linkified_perms($results, $str_contact_allow, $str_group_allow, $profile_uid, $parent_item, $private);
            $post_tags = array();
            foreach ($results as $result) {
                $success = $result['success'];
                if ($success['replaced']) {
                    $post_tags[] = array('uid' => $profile_uid, 'type' => $success['termtype'], 'otype' => TERM_OBJ_POST, 'term' => $success['term'], 'url' => $success['url']);
                }
            }
        }
        /**
         *
         * When a photo was uploaded into the message using the (profile wall) ajax 
         * uploader, The permissions are initially set to disallow anybody but the
         * owner from seeing it. This is because the permissions may not yet have been
         * set for the post. If it's private, the photo permissions should be set
         * appropriately. But we didn't know the final permissions on the post until
         * now. So now we'll look for links of uploaded photos and attachments that are in the
         * post and set them to the same permissions as the post itself.
         *
         * If the post was end-to-end encrypted we can't find images and attachments in the body,
         * use our media_str input instead which only contains these elements - but only do this
         * when encrypted content exists because the photo/attachment may have been removed from 
         * the post and we should keep it private. If it's encrypted we have no way of knowing
         * so we'll set the permissions regardless and realise that the media may not be 
         * referenced in the post. 
         *
         * What is preventing us from being able to upload photos into comments is dealing with
         * the photo and attachment permissions, since we don't always know who was in the 
         * distribution for the top level post.
         * 
         * We might be able to provide this functionality with a lot of fiddling:
         * - if the top level post is public (make the photo public)
         * - if the top level post was written by us or a wall post that belongs to us (match the top level post)
         * - if the top level post has privacy mentions, add those to the permissions.
         * - otherwise disallow the photo *or* make the photo public. This is the part that gets messy. 
         */
        if (!$preview) {
            fix_attached_photo_permissions($profile_uid, $owner_xchan['xchan_hash'], strpos($body, '[/crypt]') ? $_POST['media_str'] : $body, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny);
            fix_attached_file_permissions($channel, $observer['xchan_hash'], strpos($body, '[/crypt]') ? $_POST['media_str'] : $body, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny);
        }
        $attachments = '';
        $match = false;
        if (preg_match_all('/(\\[attachment\\](.*?)\\[\\/attachment\\])/', $body, $match)) {
            $attachments = array();
            foreach ($match[2] as $mtch) {
                $hash = substr($mtch, 0, strpos($mtch, ','));
                $rev = intval(substr($mtch, strpos($mtch, ',')));
                $r = attach_by_hash_nodata($hash, $rev);
                if ($r['success']) {
                    $attachments[] = array('href' => $a->get_baseurl() . '/attach/' . $r['data']['hash'], 'length' => $r['data']['filesize'], 'type' => $r['data']['filetype'], 'title' => urlencode($r['data']['filename']), 'revision' => $r['data']['revision']);
                }
                $body = str_replace($match[1], '', $body);
            }
        }
    }
    // BBCODE end alert
    if (strlen($categories)) {
        $cats = explode(',', $categories);
        foreach ($cats as $cat) {
            $post_tags[] = array('uid' => $profile_uid, 'type' => TERM_CATEGORY, 'otype' => TERM_OBJ_POST, 'term' => trim($cat), 'url' => $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat)));
        }
    }
    $item_unseen = 1;
    // determine if this is a wall post
    if ($parent) {
        if ($parent_item['item_flags'] & ITEM_WALL) {
            $item_flags = $item_flags | ITEM_WALL;
        }
    } else {
        if (!$webpage) {
            $item_flags = $item_flags | ITEM_WALL;
        }
    }
    if ($origin) {
        $item_flags = $item_flags | ITEM_ORIGIN;
    }
    if ($moderated) {
        $item_restrict = $item_restrict | ITEM_MODERATED;
    }
    if ($webpage) {
        $item_restrict = $item_restrict | $webpage;
    }
    if (!strlen($verb)) {
        $verb = ACTIVITY_POST;
    }
    $notify_type = $parent ? 'comment-new' : 'wall-new';
    if (!$mid) {
        $mid = $message_id ? $message_id : item_message_id();
    }
    if (!$parent_mid) {
        $parent_mid = $mid;
    }
    if ($parent_item) {
        $parent_mid = $parent_item['mid'];
    }
    // Fallback so that we alway have a thr_parent
    if (!$thr_parent) {
        $thr_parent = $mid;
    }
    $datarray = array();
    if (!$parent) {
        $item_flags = $item_flags | ITEM_THREAD_TOP;
    }
    if ($consensus) {
        $item_flags |= ITEM_CONSENSUS;
    }
    if (!$plink && $item_flags & ITEM_THREAD_TOP) {
        $plink = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $mid;
    }
    $datarray['aid'] = $channel['channel_account_id'];
    $datarray['uid'] = $profile_uid;
    $datarray['owner_xchan'] = $owner_hash ? $owner_hash : $owner_xchan['xchan_hash'];
    $datarray['author_xchan'] = $observer['xchan_hash'];
    $datarray['created'] = $created;
    $datarray['edited'] = $orig_post ? datetime_convert() : $created;
    $datarray['expires'] = $expires;
    $datarray['commented'] = $orig_post ? datetime_convert() : $created;
    $datarray['received'] = $orig_post ? datetime_convert() : $created;
    $datarray['changed'] = $orig_post ? datetime_convert() : $created;
    $datarray['mid'] = $mid;
    $datarray['parent_mid'] = $parent_mid;
    $datarray['mimetype'] = $mimetype;
    $datarray['title'] = $title;
    $datarray['body'] = $body;
    $datarray['app'] = $app;
    $datarray['location'] = $location;
    $datarray['coord'] = $coord;
    $datarray['verb'] = $verb;
    $datarray['obj_type'] = $obj_type;
    $datarray['allow_cid'] = $str_contact_allow;
    $datarray['allow_gid'] = $str_group_allow;
    $datarray['deny_cid'] = $str_contact_deny;
    $datarray['deny_gid'] = $str_group_deny;
    $datarray['item_private'] = $private;
    $datarray['attach'] = $attachments;
    $datarray['thr_parent'] = $thr_parent;
    $datarray['postopts'] = $postopts;
    $datarray['item_restrict'] = $item_restrict;
    $datarray['item_flags'] = $item_flags;
    $datarray['layout_mid'] = $layout_mid;
    $datarray['public_policy'] = $public_policy;
    $datarray['comment_policy'] = map_scope($channel['channel_w_comment']);
    $datarray['term'] = $post_tags;
    $datarray['plink'] = $plink;
    $datarray['route'] = $route;
    $datarray['item_unseen'] = $item_unseen;
    // preview mode - prepare the body for display and send it via json
    if ($preview) {
        require_once 'include/conversation.php';
        $datarray['owner'] = $owner_xchan;
        $datarray['author'] = $observer;
        $datarray['attach'] = json_encode($datarray['attach']);
        $o = conversation($a, array($datarray), 'search', false, 'preview');
        //		logger('preview: ' . $o, LOGGER_DEBUG);
        echo json_encode(array('preview' => $o));
        killme();
    }
    if ($orig_post) {
        $datarray['edit'] = true;
    }
    call_hooks('post_local', $datarray);
    if (x($datarray, 'cancel')) {
        logger('mod_item: post cancelled by plugin.');
        if ($return_path) {
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        $json = array('cancel' => 1);
        if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload'])) {
            $json['reload'] = $a->get_baseurl() . '/' . $_REQUEST['jsreload'];
        }
        echo json_encode($json);
        killme();
    }
    if (mb_strlen($datarray['title']) > 255) {
        $datarray['title'] = mb_substr($datarray['title'], 0, 255);
    }
    if (array_key_exists('item_private', $datarray) && $datarray['item_private']) {
        $datarray['body'] = trim(z_input_filter($datarray['uid'], $datarray['body'], $datarray['mimetype']));
        if ($uid) {
            if ($channel['channel_hash'] === $datarray['author_xchan']) {
                $datarray['sig'] = base64url_encode(rsa_sign($datarray['body'], $channel['channel_prvkey']));
                $datarray['item_flags'] = $datarray['item_flags'] | ITEM_VERIFIED;
            }
        }
        logger('Encrypting local storage');
        $key = get_config('system', 'pubkey');
        $datarray['item_flags'] = $datarray['item_flags'] | ITEM_OBSCURED;
        if ($datarray['title']) {
            $datarray['title'] = json_encode(crypto_encapsulate($datarray['title'], $key));
        }
        if ($datarray['body']) {
            $datarray['body'] = json_encode(crypto_encapsulate($datarray['body'], $key));
        }
    }
    if ($orig_post) {
        $datarray['id'] = $post_id;
        item_store_update($datarray, $execflag);
        update_remote_id($channel, $post_id, $webpage, $pagetitle, $namespace, $remote_id, $mid);
        if (!$nopush) {
            proc_run('php', "include/notifier.php", 'edit_post', $post_id);
        }
        if (x($_REQUEST, 'return') && strlen($return_path)) {
            logger('return: ' . $return_path);
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        killme();
    } else {
        $post_id = 0;
    }
    $post = item_store($datarray, $execflag);
    $post_id = $post['item_id'];
    if ($post_id) {
        logger('mod_item: saved item ' . $post_id);
        if ($parent) {
            // only send comment notification if this is a wall-to-wall comment,
            // otherwise it will happen during delivery
            if ($datarray['owner_xchan'] != $datarray['author_xchan'] && $parent_item['item_flags'] & ITEM_WALL) {
                notification(array('type' => NOTIFY_COMMENT, 'from_xchan' => $datarray['author_xchan'], 'to_xchan' => $datarray['owner_xchan'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . $datarray['mid'], 'verb' => ACTIVITY_POST, 'otype' => 'item', 'parent' => $parent, 'parent_mid' => $parent_item['mid']));
            }
        } else {
            $parent = $post_id;
            if ($datarray['owner_xchan'] != $datarray['author_xchan']) {
                notification(array('type' => NOTIFY_WALL, 'from_xchan' => $datarray['author_xchan'], 'to_xchan' => $datarray['owner_xchan'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . $datarray['mid'], 'verb' => ACTIVITY_POST, 'otype' => 'item'));
            }
            if ($uid && $uid == $profile_uid && !$datarray['item_restrict']) {
                q("update channel set channel_lastpost = '%s' where channel_id = %d", dbesc(datetime_convert()), intval($uid));
            }
        }
        // photo comments turn the corresponding item visible to the profile wall
        // This way we don't see every picture in your new photo album posted to your wall at once.
        // They will show up as people comment on them.
        if ($parent_item['item_restrict'] & ITEM_HIDDEN) {
            $r = q("UPDATE `item` SET `item_restrict` = %d WHERE `id` = %d", intval($parent_item['item_restrict'] - ITEM_HIDDEN), intval($parent_item['id']));
        }
    } else {
        logger('mod_item: unable to retrieve post that was just stored.');
        notice(t('System error. Post not saved.') . EOL);
        goaway($a->get_baseurl() . "/" . $return_path);
        // NOTREACHED
    }
    if ($parent) {
        // Store the comment signature information in case we need to relay to Diaspora
        $ditem = $datarray;
        $ditem['author'] = $observer;
        store_diaspora_comment_sig($ditem, $channel, $parent_item, $post_id, $walltowall_comment ? 1 : 0);
    }
    update_remote_id($channel, $post_id, $webpage, $pagetitle, $namespace, $remote_id, $mid);
    $datarray['id'] = $post_id;
    $datarray['llink'] = $a->get_baseurl() . '/display/' . $channel['channel_address'] . '/' . $post_id;
    call_hooks('post_local_end', $datarray);
    if (!$nopush) {
        proc_run('php', 'include/notifier.php', $notify_type, $post_id);
    }
    logger('post_complete');
    // figure out how to return, depending on from whence we came
    if ($api_source) {
        return $post;
    }
    if ($return_path) {
        goaway($a->get_baseurl() . "/" . $return_path);
    }
    $json = array('success' => 1);
    if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload'])) {
        $json['reload'] = $a->get_baseurl() . '/' . $_REQUEST['jsreload'];
    }
    logger('post_json: ' . print_r($json, true), LOGGER_DEBUG);
    echo json_encode($json);
    killme();
    // NOTREACHED
}
예제 #20
0
파일: items.php 프로젝트: phellmes/hubzilla
/**
 * @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
 * or other processing is performed.
 *
 * @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);
    $is_comment = false;
    if ($arr['parent'] && $arr['parent'] != $arr['id'] || $arr['parent_mid'] && $arr['parent_mid'] != $arr['mid']) {
        $is_comment = true;
    }
    if (!array_key_exists('item_origin', $arr)) {
        $arr['item_origin'] = 1;
    }
    if (!array_key_exists('item_wall', $arr) && !$is_comment) {
        $arr['item_wall'] = 1;
    }
    if (!array_key_exists('item_thread_top', $arr) && !$is_comment) {
        $arr['item_thread_top'] = 1;
    }
    $channel = App::get_channel();
    $observer = App::get_observer();
    $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');
        return $ret;
    }
    $arr['public_policy'] = x($_REQUEST, 'public_policy') ? escape_tags($_REQUEST['public_policy']) : map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'], 'view_stream'), true);
    if ($arr['public_policy']) {
        $arr['item_private'] = 1;
    }
    if (!array_key_exists('mimetype', $arr)) {
        $arr['mimetype'] = 'text/bbcode';
    }
    if (array_key_exists('item_private', $arr) && $arr['item_private']) {
        $arr['body'] = trim(z_input_filter($arr['uid'], $arr['body'], $arr['mimetype']));
        if ($channel) {
            if ($channel['channel_hash'] === $arr['author_xchan']) {
                $arr['sig'] = base64url_encode(rsa_sign($arr['body'], $channel['channel_prvkey']));
                $arr['item_verified'] = 1;
            }
        }
    }
    $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['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(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'], 'post_comments'));
    if (!$arr['plink'] && intval($arr['item_thread_top'])) {
        $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid'];
    }
    // for the benefit of plugins, we will behave as if this is an API call rather than a normal online post
    $_REQUEST['api_source'] = 1;
    call_hooks('post_local', $arr);
    if (x($arr, 'cancel')) {
        logger('post_activity_item: post cancelled by plugin.');
        return $ret;
    }
    $post = item_store($arr);
    if ($post['success']) {
        $post_id = $post['item_id'];
    }
    if ($post_id) {
        $arr['id'] = $post_id;
        call_hooks('post_local_end', $arr);
        Zotlabs\Daemon\Master::Summon(array('Notifier', 'activity', $post_id));
        $ret['success'] = true;
        $ret['activity'] = $post['item'];
    }
    return $ret;
}
예제 #21
0
파일: like.php 프로젝트: vinzv/friendica
function like_content(&$a)
{
    if (!local_user() && !remote_user()) {
        return;
    }
    $verb = notags(trim($_GET['verb']));
    if (!$verb) {
        $verb = 'like';
    }
    switch ($verb) {
        case 'like':
        case 'unlike':
            $activity = ACTIVITY_LIKE;
            break;
        case 'dislike':
        case 'undislike':
            $activity = ACTIVITY_DISLIKE;
            break;
        case 'attendyes':
        case 'unattendyes':
            $activity = ACTIVITY_ATTEND;
            break;
        case 'attendno':
        case 'unattendno':
            $activity = ACTIVITY_ATTENDNO;
            break;
        case 'attendmaybe':
        case 'unattendmaybe':
            $activity = ACTIVITY_ATTENDMAYBE;
            break;
        default:
            return;
            break;
    }
    $item_id = $a->argc > 1 ? notags(trim($a->argv[1])) : 0;
    logger('like: verb ' . $verb . ' item ' . $item_id);
    $r = q("SELECT * FROM `item` WHERE `id` = '%s' OR `uri` = '%s' LIMIT 1", dbesc($item_id), dbesc($item_id));
    if (!$item_id || !count($r)) {
        logger('like: no item ' . $item_id);
        return;
    }
    $item = $r[0];
    $owner_uid = $item['uid'];
    if (!can_write_wall($a, $owner_uid)) {
        return;
    }
    $remote_owner = null;
    if (!$item['wall']) {
        // The top level post may have been written by somebody on another system
        $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($item['contact-id']), intval($item['uid']));
        if (!count($r)) {
            return;
        }
        if (!$r[0]['self']) {
            $remote_owner = $r[0];
        }
    }
    // this represents the post owner on this system.
    $r = q("SELECT `contact`.*, `user`.`nickname` FROM `contact` LEFT JOIN `user` ON `contact`.`uid` = `user`.`uid`\n\t\tWHERE `contact`.`self` = 1 AND `contact`.`uid` = %d LIMIT 1", intval($owner_uid));
    if (count($r)) {
        $owner = $r[0];
    }
    if (!$owner) {
        logger('like: no owner');
        return;
    }
    if (!$remote_owner) {
        $remote_owner = $owner;
    }
    // This represents the person posting
    if (local_user() && local_user() == $owner_uid) {
        $contact = $owner;
    } else {
        $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($_SESSION['visitor_id']), intval($owner_uid));
        if (count($r)) {
            $contact = $r[0];
        }
    }
    if (!$contact) {
        return;
    }
    // See if we've been passed a return path to redirect to
    $return_path = x($_REQUEST, 'return') ? $_REQUEST['return'] : '';
    $verbs = " '" . dbesc($activity) . "' ";
    // event participation are essentially radio toggles. If you make a subsequent choice,
    // we need to eradicate your first choice.
    if ($activity === ACTIVITY_ATTEND || $activity === ACTIVITY_ATTENDNO || $activity === ACTIVITY_ATTENDMAYBE) {
        $verbs = " '" . dbesc(ACTIVITY_ATTEND) . "','" . dbesc(ACTIVITY_ATTENDNO) . "','" . dbesc(ACTIVITY_ATTENDMAYBE) . "' ";
    }
    $r = q("SELECT `id`, `guid` FROM `item` WHERE `verb` IN ( {$verbs} ) AND `deleted` = 0\n\t\tAND `contact-id` = %d AND `uid` = %d\n\t\tAND (`parent` = '%s' OR `parent-uri` = '%s' OR `thr-parent` = '%s') LIMIT 1", intval($contact['id']), intval($owner_uid), dbesc($item_id), dbesc($item_id), dbesc($item['uri']));
    if (count($r)) {
        $like_item = $r[0];
        // Already voted, undo it
        $r = q("UPDATE `item` SET `deleted` = 1, `unseen` = 1, `changed` = '%s' WHERE `id` = %d", dbesc(datetime_convert()), intval($like_item['id']));
        // Clean up the Diaspora signatures for this like
        // Go ahead and do it even if Diaspora support is disabled. We still want to clean up
        // if it had been enabled in the past
        $r = q("DELETE FROM `sign` WHERE `iid` = %d", intval($like_item['id']));
        // Save the author information for the unlike in case we need to relay to Diaspora
        store_diaspora_like_retract_sig($activity, $item, $like_item, $contact);
        //		proc_run('php',"include/notifier.php","like","$post_id"); // $post_id isn't defined here!
        $like_item_id = $like_item['id'];
        proc_run('php', "include/notifier.php", "like", "{$like_item_id}");
        like_content_return($a->get_baseurl(), $return_path);
        return;
        // NOTREACHED
    }
    $uri = item_new_uri($a->get_hostname(), $owner_uid);
    $post_type = $item['resource-id'] ? t('photo') : t('status');
    if ($item['obj_type'] === ACTIVITY_OBJ_EVENT) {
        $post_type = t('event');
    }
    $objtype = $item['resource-id'] ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE;
    $link = xmlify('<link rel="alternate" type="text/html" href="' . $a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . '" />' . "\n");
    $body = $item['body'];
    $obj = <<<EOT

\t<object>
\t\t<type>{$objtype}</type>
\t\t<local>1</local>
\t\t<id>{$item['uri']}</id>
\t\t<link>{$link}</link>
\t\t<title></title>
\t\t<content>{$body}</content>
\t</object>
EOT;
    if ($verb === 'like') {
        $bodyverb = t('%1$s likes %2$s\'s %3$s');
    }
    if ($verb === 'dislike') {
        $bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s');
    }
    if ($verb === 'attendyes') {
        $bodyverb = t('%1$s is attending %2$s\'s %3$s');
    }
    if ($verb === 'attendno') {
        $bodyverb = t('%1$s is not attending %2$s\'s %3$s');
    }
    if ($verb === 'attendmaybe') {
        $bodyverb = t('%1$s may attend %2$s\'s %3$s');
    }
    if (!isset($bodyverb)) {
        return;
    }
    $arr = array();
    $arr['uri'] = $uri;
    $arr['uid'] = $owner_uid;
    $arr['contact-id'] = $contact['id'];
    $arr['type'] = 'activity';
    $arr['wall'] = $item['wall'];
    $arr['origin'] = 1;
    $arr['gravity'] = GRAVITY_LIKE;
    $arr['parent'] = $item['id'];
    $arr['parent-uri'] = $item['uri'];
    $arr['thr-parent'] = $item['uri'];
    $arr['owner-name'] = $remote_owner['name'];
    $arr['owner-link'] = $remote_owner['url'];
    $arr['owner-avatar'] = $remote_owner['thumb'];
    $arr['author-name'] = $contact['name'];
    $arr['author-link'] = $contact['url'];
    $arr['author-avatar'] = $contact['thumb'];
    $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
    $alink = '[url=' . $item['author-link'] . ']' . $item['author-name'] . '[/url]';
    $plink = '[url=' . $a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . ']' . $post_type . '[/url]';
    $arr['body'] = sprintf($bodyverb, $ulink, $alink, $plink);
    $arr['verb'] = $activity;
    $arr['object-type'] = $objtype;
    $arr['object'] = $obj;
    $arr['allow_cid'] = $item['allow_cid'];
    $arr['allow_gid'] = $item['allow_gid'];
    $arr['deny_cid'] = $item['deny_cid'];
    $arr['deny_gid'] = $item['deny_gid'];
    $arr['visible'] = 1;
    $arr['unseen'] = 1;
    $arr['last-child'] = 0;
    $post_id = item_store($arr);
    if (!$item['visible']) {
        $r = q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d AND `uid` = %d", intval($item['id']), intval($owner_uid));
    }
    // Save the author information for the like in case we need to relay to Diaspora
    store_diaspora_like_sig($activity, $post_type, $contact, $post_id);
    $arr['id'] = $post_id;
    call_hooks('post_local_end', $arr);
    proc_run('php', "include/notifier.php", "like", "{$post_id}");
    like_content_return($a->get_baseurl(), $return_path);
    killme();
    // NOTREACHED
    //	return; // NOTREACHED
}
예제 #22
0
파일: mood.php 프로젝트: Mauru/red
function mood_init(&$a)
{
    if (!local_user()) {
        return;
    }
    $uid = local_user();
    $channel = $a->get_channel();
    $verb = notags(trim($_GET['verb']));
    if (!$verb) {
        return;
    }
    $verbs = get_mood_verbs();
    if (!array_key_exists($verb, $verbs)) {
        return;
    }
    $activity = ACTIVITY_MOOD . '#' . urlencode($verb);
    $parent = x($_GET, 'parent') ? intval($_GET['parent']) : 0;
    logger('mood: verb ' . $verb, LOGGER_DEBUG);
    if ($parent) {
        $r = q("select mid, owner_xchan, private, allow_cid, allow_gid, deny_cid, deny_gid \n\t\t\tfrom item where id = %d and parent = %d and uid = %d limit 1", intval($parent), intval($parent), intval($uid));
        if (count($r)) {
            $parent_mid = $r[0]['mid'];
            $private = $r[0]['item_private'];
            $allow_cid = $r[0]['allow_cid'];
            $allow_gid = $r[0]['allow_gid'];
            $deny_cid = $r[0]['deny_cid'];
            $deny_gid = $r[0]['deny_gid'];
        }
    } else {
        $private = 0;
        $allow_cid = $channel['channel_allow_cid'];
        $allow_gid = $channel['channel_allow_gid'];
        $deny_cid = $channel['channel_deny_cid'];
        $deny_gid = $channel['channel_deny_gid'];
    }
    $poster = $a->get_observer();
    $mid = item_message_id();
    $action = sprintf(t('%1$s is %2$s', 'mood'), '[zrl=' . $poster['xchan_url'] . ']' . $poster['xchan_name'] . '[/zrl]', $verbs[$verb]);
    $item_flags = ITEM_WALL | ITEM_ORIGIN | ITEM_UNSEEN;
    if (!$parent_mid) {
        $item_flags |= ITEM_THREAD_TOP;
    }
    $arr = array();
    $arr['aid'] = get_account_id();
    $arr['uid'] = $uid;
    $arr['mid'] = $mid;
    $arr['parent_mid'] = $parent_mid ? $parent_mid : $mid;
    $arr['item_flags'] = $item_flags;
    $arr['author_xchan'] = $poster['xchan_hash'];
    $arr['owner_xchan'] = $parent_mid ? $r[0]['owner_xchan'] : $poster['xchan_hash'];
    $arr['title'] = '';
    $arr['allow_cid'] = $allow_cid;
    $arr['allow_gid'] = $allow_gid;
    $arr['deny_cid'] = $deny_cid;
    $arr['deny_gid'] = $deny_gid;
    $arr['item_private'] = $private;
    $arr['verb'] = $activity;
    $arr['body'] = $action;
    if (!$arr['plink'] && $arr['item_flags'] & ITEM_THREAD_TOP) {
        $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid'];
    }
    $post = item_store($arr);
    $item_id = $post['item_id'];
    if ($item_id) {
        proc_run('php', "include/notifier.php", "activity", $item_id);
    }
    call_hooks('post_local_end', $arr);
    if ($_SESSION['return_url']) {
        goaway(z_root() . '/' . $_SESSION['return_url']);
    }
    return;
}
예제 #23
0
function tagger_content(&$a)
{
    if (!local_user() && !remote_user()) {
        return;
    }
    $term = notags(trim($_GET['term']));
    // no commas allowed
    $term = str_replace(array(',', ' '), array('', '_'), $term);
    if (!$term) {
        return;
    }
    $item_id = $a->argc > 1 ? notags(trim($a->argv[1])) : 0;
    logger('tagger: tag ' . $term . ' item ' . $item_id);
    $r = q("SELECT * FROM `item` WHERE `id` = '%s' LIMIT 1", dbesc($item_id));
    if (!$item_id || !count($r)) {
        logger('tagger: no item ' . $item_id);
        return;
    }
    $item = $r[0];
    $owner_uid = $item['uid'];
    $r = q("select `nickname`,`blocktags` from user where uid = %d limit 1", intval($owner_uid));
    if (count($r)) {
        $owner_nick = $r[0]['nickname'];
        $blocktags = $r[0]['blocktags'];
    }
    if (local_user() != $owner_uid) {
        return;
    }
    if (remote_user()) {
        $r = q("select * from contact where id = %d AND `uid` = %d limit 1", intval(remote_user()), intval($item['uid']));
    } else {
        $r = q("select * from contact where self = 1 and uid = %d limit 1", intval(local_user()));
    }
    if (count($r)) {
        $contact = $r[0];
    } else {
        logger('tagger: no contact_id');
        return;
    }
    $uri = item_new_uri($a->get_hostname(), $owner_uid);
    $post_type = $item['resource-id'] ? t('photo') : t('status');
    $targettype = $item['resource-id'] ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE;
    $link = xmlify('<link rel="alternate" type="text/html" href="' . $a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . '" />' . "\n");
    $body = $item['body'];
    $target = <<<EOT
\t<target>
\t\t<type>{$targettype}</type>
\t\t<local>1</local>
\t\t<id>{$item['uri']}</id>
\t\t<link>{$link}</link>
\t\t<title></title>
\t\t<content>{$body}</content>
\t</target>
EOT;
    $tagid = $a->get_baseurl() . '/search?search=' . $term;
    $objtype = ACTIVITY_OBJ_TAGTERM;
    $obj = <<<EOT
\t<object>
\t\t<type>{$objtype}</type>
\t\t<local>1</local>
\t\t<id>{$tagid}</id>
\t\t<link>{$tagid}</link>
\t\t<title>{$term}</title>
\t\t<content>{$term}</content>
\t</object>
EOT;
    $bodyverb = t('%1$s tagged %2$s\'s %3$s with %4$s');
    if (!isset($bodyverb)) {
        return;
    }
    $termlink = html_entity_decode('&#x2317;') . '[url=' . $a->get_baseurl() . '/search?search=' . urlencode($term) . ']' . $term . '[/url]';
    $arr = array();
    $arr['uri'] = $uri;
    $arr['uid'] = $owner_uid;
    $arr['contact-id'] = $contact['id'];
    $arr['type'] = 'activity';
    $arr['wall'] = $item['wall'];
    $arr['gravity'] = GRAVITY_COMMENT;
    $arr['parent'] = $item['id'];
    $arr['parent-uri'] = $item['uri'];
    $arr['owner-name'] = $item['author-name'];
    $arr['owner-link'] = $item['author-link'];
    $arr['owner-avatar'] = $item['author-avatar'];
    $arr['author-name'] = $contact['name'];
    $arr['author-link'] = $contact['url'];
    $arr['author-avatar'] = $contact['thumb'];
    $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
    $alink = '[url=' . $item['author-link'] . ']' . $item['author-name'] . '[/url]';
    $plink = '[url=' . $item['plink'] . ']' . $post_type . '[/url]';
    $arr['body'] = sprintf($bodyverb, $ulink, $alink, $plink, $termlink);
    $arr['verb'] = ACTIVITY_TAG;
    $arr['target-type'] = $targettype;
    $arr['target'] = $target;
    $arr['object-type'] = $objtype;
    $arr['object'] = $obj;
    $arr['allow_cid'] = $item['allow_cid'];
    $arr['allow_gid'] = $item['allow_gid'];
    $arr['deny_cid'] = $item['deny_cid'];
    $arr['deny_gid'] = $item['deny_gid'];
    $arr['visible'] = 1;
    $arr['unseen'] = 1;
    $arr['last-child'] = 1;
    $arr['origin'] = 1;
    $post_id = item_store($arr);
    q("UPDATE `item` set plink = '%s' where id = %d limit 1", dbesc($a->get_baseurl() . '/display/' . $owner_nick . '/' . $post_id), intval($post_id));
    if (!$item['visible']) {
        $r = q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($item['id']), intval($owner_uid));
    }
    if (!$blocktags && !stristr($item['tag'], ']' . $term . '[')) {
        q("update item set tag = '%s' where id = %d limit 1", dbesc($item['tag'] . (strlen($item['tag']) ? ',' : '') . '#[url=' . $a->get_baseurl() . '/search?search=' . $term . ']' . $term . '[/url]'), intval($item['id']));
    }
    // if the original post is on this site, update it.
    $r = q("select `tag`,`id`,`uid` from item where `origin` = 1 AND `uri` = '%s' LIMIT 1", dbesc($item['uri']));
    if (count($r)) {
        $x = q("SELECT `blocktags` FROM `user` WHERE `uid` = %d limit 1", intval($r[0]['uid']));
        if (count($x) && !$x[0]['blocktags'] && !stristr($r[0]['tag'], ']' . $term . '[')) {
            q("update item set tag = '%s' where id = %d limit 1", dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . '#[url=' . $a->get_baseurl() . '/search?search=' . $term . ']' . $term . '[/url]'), intval($r[0]['id']));
        }
    }
    $arr['id'] = $post_id;
    call_hooks('post_local_end', $arr);
    proc_run('php', "include/notifier.php", "tag", "{$post_id}");
    killme();
    return;
    // NOTREACHED
}
예제 #24
0
/**
 * @brief Process atom feed and update anything/everything we might need to update.
 *
 * @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.
 */
function consume_feed($xml, $importer, &$contact, $pass = 0)
{
    require_once 'library/simplepie/simplepie.inc';
    if (!strlen($xml)) {
        logger('consume_feed: empty input');
        return;
    }
    $sys_expire = intval(get_config('system', 'default_expire_days'));
    $chn_expire = intval($importer['channel_expire_days']);
    $expire_days = $sys_expire;
    if ($chn_expire != 0 && $chn_expire < $sys_expire) {
        $expire_days = $chn_expire;
    }
    // logger('expire_days: ' . $expire_days);
    $feed = new SimplePie();
    $feed->set_raw_data($xml);
    $feed->init();
    if ($feed->error()) {
        logger('consume_feed: Error parsing XML: ' . $feed->error());
    }
    $permalink = $feed->get_permalink();
    // Check at the feed level for updated contact name and/or photo
    // process any deleted entries
    $del_entries = $feed->get_feed_tags(NAMESPACE_TOMB, 'deleted-entry');
    if (is_array($del_entries) && count($del_entries) && $pass != 2) {
        foreach ($del_entries as $dentry) {
            $deleted = false;
            if (isset($dentry['attribs']['']['ref'])) {
                $mid = $dentry['attribs']['']['ref'];
                $deleted = true;
                if (isset($dentry['attribs']['']['when'])) {
                    $when = $dentry['attribs']['']['when'];
                    $when = datetime_convert('UTC', 'UTC', $when, 'Y-m-d H:i:s');
                } else {
                    $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)), dbesc($contact['xchan_hash']), intval($importer['channel_id']));
                if ($r) {
                    $item = $r[0];
                    if (!intval($item['item_deleted'])) {
                        logger('consume_feed: deleting item ' . $item['id'] . ' mid=' . base64url_decode($item['mid']), LOGGER_DEBUG);
                        drop_item($item['id'], false);
                    }
                }
            }
        }
    }
    // Now process the feed
    if ($feed->get_item_quantity()) {
        logger('consume_feed: feed item count = ' . $feed->get_item_quantity(), LOGGER_DEBUG);
        $items = $feed->get_items();
        foreach ($items as $item) {
            $is_reply = false;
            $item_id = base64url_encode($item->get_id());
            logger('consume_feed: processing ' . $item_id, LOGGER_DEBUG);
            $rawthread = $item->get_item_tags(NAMESPACE_THREAD, 'in-reply-to');
            if (isset($rawthread[0]['attribs']['']['ref'])) {
                $is_reply = true;
                $parent_mid = base64url_encode($rawthread[0]['attribs']['']['ref']);
            }
            if ($is_reply) {
                if ($pass == 1) {
                    continue;
                }
                // Have we seen it? If not, import it.
                $item_id = base64url_encode($item->get_id());
                $author = array();
                $datarray = get_atom_elements($feed, $item, $author);
                if ($contact['xchan_network'] === 'rss') {
                    $datarray['public_policy'] = 'specific';
                    $datarray['comment_policy'] = 'none';
                }
                if (!x($author, 'author_name') || $author['author_is_feed']) {
                    $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']) {
                    $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) {
                        $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']));
                // Update content if 'updated' changes
                if ($r) {
                    if (x($datarray, 'edited') !== false && datetime_convert('UTC', 'UTC', $datarray['edited']) !== $r[0]['edited']) {
                        // do not accept (ignore) an earlier edit than one we currently have.
                        if (datetime_convert('UTC', 'UTC', $datarray['edited']) < $r[0]['edited']) {
                            continue;
                        }
                        update_feed_item($importer['channel_id'], $datarray);
                    }
                    continue;
                }
                $datarray['parent_mid'] = $parent_mid;
                $datarray['aid'] = $importer['channel_account_id'];
                $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.
                $item_id = base64url_encode($item->get_id());
                $author = array();
                $datarray = get_atom_elements($feed, $item, $author);
                if ($contact['xchan_network'] === 'rss') {
                    $datarray['public_policy'] = 'specific';
                    $datarray['comment_policy'] = 'none';
                }
                if (is_array($contact)) {
                    if (!x($author, 'author_name') || $author['author_is_feed']) {
                        $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']) {
                        $author['author_photo'] = $contact['xchan_photo_m'];
                    }
                }
                if (!x($author, 'author_name') || !x($author, 'author_link')) {
                    logger('consume_feed: no author information! ' . print_r($author, true));
                    continue;
                }
                $datarray['author_xchan'] = '';
                if (activity_match($datarray['verb'], ACTIVITY_FOLLOW) && $datarray['obj_type'] === ACTIVITY_OBJ_PERSON) {
                    $cb = array('item' => $datarray, 'channel' => $importer, 'xchan' => null, 'author' => $author, 'caught' => false);
                    call_hooks('follow_from_feed', $cb);
                    if ($cb['caught']) {
                        if ($cb['return_code']) {
                            http_status_exit($cb['return_code']);
                        }
                        continue;
                    }
                }
                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) {
                        $datarray['author_xchan'] = $x;
                    }
                }
                if (!$datarray['author_xchan']) {
                    $datarray['author_xchan'] = $contact['xchan_hash'];
                }
                $datarray['owner_xchan'] = $contact['xchan_hash'];
                if (array_key_exists('created', $datarray) && $datarray['created'] != NULL_DATE && $expire_days) {
                    $t1 = $datarray['created'];
                    $t2 = datetime_convert('UTC', 'UTC', 'now - ' . $expire_days . 'days');
                    if ($t1 < $t2) {
                        logger('feed content older than expiration. Ignoring.', LOGGER_DEBUG, LOG_INFO);
                        continue;
                    }
                }
                $r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1", dbesc($item_id), intval($importer['channel_id']));
                // Update content if 'updated' changes
                if ($r) {
                    if (x($datarray, 'edited') !== false && datetime_convert('UTC', 'UTC', $datarray['edited']) !== $r[0]['edited']) {
                        // do not accept (ignore) an earlier edit than one we currently have.
                        if (datetime_convert('UTC', 'UTC', $datarray['edited']) < $r[0]['edited']) {
                            continue;
                        }
                        update_feed_item($importer['channel_id'], $datarray);
                    }
                    continue;
                }
                $datarray['parent_mid'] = $item_id;
                $datarray['uid'] = $importer['channel_id'];
                $datarray['aid'] = $importer['channel_account_id'];
                if (!link_compare($author['owner_link'], $contact['xchan_url'])) {
                    logger('consume_feed: Correcting item owner.', LOGGER_DEBUG);
                    $author['owner_name'] = $contact['name'];
                    $author['owner_link'] = $contact['url'];
                    $author['owner_avatar'] = $contact['thumb'];
                }
                if (!post_is_importable($datarray, $contact)) {
                    continue;
                }
                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;
            }
        }
    }
}
예제 #25
0
function store_doc_file($s)
{
    if (is_dir($s)) {
        return;
    }
    $item = array();
    $sys = get_sys_channel();
    $item['aid'] = 0;
    $item['uid'] = $sys['channel_id'];
    if (strpos($s, '.md')) {
        $mimetype = 'text/markdown';
    } elseif (strpos($s, '.html')) {
        $mimetype = 'text/html';
    } else {
        $mimetype = 'text/bbcode';
    }
    require_once 'include/html2plain.php';
    $item['body'] = html2plain(prepare_text(file_get_contents($s), $mimetype, true));
    $item['mimetype'] = 'text/plain';
    $item['plink'] = z_root() . '/' . str_replace('doc', 'help', $s);
    $item['owner_xchan'] = $item['author_xchan'] = $sys['channel_hash'];
    $item['item_type'] = ITEM_TYPE_DOC;
    $r = q("select item.* from item left join item_id on item.id = item_id.iid where service = 'docfile' and\n\t\tsid = '%s' and item_type = %d limit 1", dbesc($s), intval(ITEM_TYPE_DOC));
    if ($r) {
        $item['id'] = $r[0]['id'];
        $item['mid'] = $item['parent_mid'] = $r[0]['mid'];
        $x = item_store_update($item);
    } else {
        $item['mid'] = $item['parent_mid'] = item_message_id();
        $x = item_store($item);
    }
    if ($x['success']) {
        update_remote_id($sys, $x['item_id'], ITEM_TYPE_DOC, $s, 'docfile', 0, $item['mid']);
    }
}
예제 #26
0
파일: like.php 프로젝트: redmatrix/red
function like_content(&$a)
{
    $o = '';
    $observer = $a->get_observer();
    $interactive = $_REQUEST['interactive'];
    if ($interactive) {
        $o .= '<h1>' . t('Like/Dislike') . '</h1>';
        $o .= EOL . EOL;
        if (!$observer) {
            $_SESSION['return_url'] = $a->query_string;
            $o .= t('This action is restricted to members.') . EOL;
            $o .= t('Please <a href="rmagic">login with your RedMatrix ID</a> or <a href="register">register as a new RedMatrix member</a> to continue.') . EOL;
            return $o;
        }
    }
    $verb = notags(trim($_GET['verb']));
    if (!$verb) {
        $verb = 'like';
    }
    switch ($verb) {
        case 'like':
        case 'unlike':
            $activity = ACTIVITY_LIKE;
            break;
        case 'dislike':
        case 'undislike':
            $activity = ACTIVITY_DISLIKE;
            break;
        case 'agree':
        case 'unagree':
            $activity = ACTIVITY_AGREE;
            break;
        case 'disagree':
        case 'undisagree':
            $activity = ACTIVITY_DISAGREE;
            break;
        case 'abstain':
        case 'unabstain':
            $activity = ACTIVITY_ABSTAIN;
            break;
        case 'attendyes':
        case 'unattendyes':
            $activity = ACTIVITY_ATTEND;
            break;
        case 'attendno':
        case 'unattendno':
            $activity = ACTIVITY_ATTENDNO;
            break;
        case 'attendmaybe':
        case 'unattendmaybe':
            $activity = ACTIVITY_ATTENDMAYBE;
            break;
        default:
            return;
            break;
    }
    $extended_like = false;
    $object = $target = null;
    $post_type = '';
    $objtype = '';
    if (argc() == 3) {
        if (!$observer) {
            killme();
        }
        $extended_like = true;
        $obj_type = argv(1);
        $obj_id = argv(2);
        $public = true;
        if ($obj_type == 'profile') {
            $r = q("select * from profile where profile_guid = '%s' limit 1", dbesc(argv(2)));
            if (!$r) {
                killme();
            }
            $owner_uid = $r[0]['uid'];
            if ($r[0]['is_default']) {
                $public = true;
            }
            if (!$public) {
                $d = q("select abook_xchan from abook where abook_profile = '%s' and abook_channel = %d", dbesc($r[0]['profile_guid']), intval($owner_uid));
                if (!$d) {
                    // forgery - illegal
                    if ($interactive) {
                        notice(t('Invalid request.') . EOL);
                        return $o;
                    }
                    killme();
                }
                // $d now contains a list of those who can see this profile - only send the status notification
                // to them.
                $allow_cid = $allow_gid = $deny_cid = $deny_gid = '';
                foreach ($d as $dd) {
                    $allow_gid .= '<' . $dd['abook_xchan'] . '>';
                }
            }
            $post_type = t('channel');
            $objtype = ACTIVITY_OBJ_PROFILE;
        } elseif ($obj_type == 'thing') {
            $r = q("select * from obj left join term on obj_obj = term_hash where term_hash != '' \n\t\t\t\tand obj_type = %d and term_hash = '%s' limit 1", intval(TERM_OBJ_THING), dbesc(argv(2)));
            if (!$r) {
                if ($interactive) {
                    notice(t('Invalid request.') . EOL);
                    return $o;
                }
                killme();
            }
            $owner_uid = $r[0]['obj_channel'];
            $allow_cid = $r[0]['allow_cid'];
            $allow_gid = $r[0]['allow_gid'];
            $deny_cid = $r[0]['deny_cid'];
            $deny_gid = $r[0]['deny_gid'];
            if ($allow_cid || $allow_gid || $deny_cid || $deny_gid) {
                $public = false;
            }
            $post_type = t('thing');
            $objtype = ACTIVITY_OBJ_PROFILE;
            $tgttype = ACTIVITY_OBJ_THING;
            $links = array();
            $links[] = array('rel' => 'alternate', 'type' => 'text/html', 'href' => z_root() . '/thing/' . $r[0]['term_hash']);
            if ($r[0]['imgurl']) {
                $links[] = array('rel' => 'photo', 'href' => $r[0]['imgurl']);
            }
            $target = json_encode(array('type' => $tgttype, 'title' => $r[0]['term'], 'id' => z_root() . '/thing/' . $r[0]['term_hash'], 'link' => $links));
            $plink = '[zrl=' . z_root() . '/thing/' . $r[0]['term_hash'] . ']' . $r[0]['term'] . '[/zrl]';
        }
        if (!($owner_uid && $r)) {
            if ($interactive) {
                notice(t('Invalid request.') . EOL);
                return $o;
            }
            killme();
        }
        // The resultant activity is going to be a wall-to-wall post, so make sure this is allowed
        $perms = get_all_perms($owner_uid, $observer['xchan_hash']);
        if (!($perms['post_like'] && $perms['view_profile'])) {
            if ($interactive) {
                notice(t('Permission denied.') . EOL);
                return $o;
            }
            killme();
        }
        $ch = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1", intval($owner_uid));
        if (!$ch) {
            if ($interactive) {
                notice(t('Channel unavailable.') . EOL);
                return $o;
            }
            killme();
        }
        if (!$plink) {
            $plink = '[zrl=' . z_root() . '/profile/' . $ch[0]['channel_address'] . ']' . $post_type . '[/zrl]';
        }
        $links = array();
        $links[] = array('rel' => 'alternate', 'type' => 'text/html', 'href' => z_root() . '/profile/' . $ch[0]['channel_address']);
        $links[] = array('rel' => 'photo', 'type' => $ch[0]['xchan_photo_mimetype'], 'href' => $ch[0]['xchan_photo_l']);
        $object = json_encode(array('type' => ACTIVITY_OBJ_PROFILE, 'title' => $ch[0]['channel_name'], 'id' => $ch[0]['xchan_url'] . '/' . $ch[0]['xchan_hash'], 'link' => $links));
        // second like of the same thing is "undo" for the first like
        $z = q("select * from likes where channel_id = %d and liker = '%s' and verb = '%s' and target_type = '%s' and target_id = '%s' limit 1", intval($ch[0]['channel_id']), dbesc($observer['xchan_hash']), dbesc($activity), dbesc($tgttype ? $tgttype : $objtype), dbesc($obj_id));
        if ($z) {
            q("delete from likes where id = %d limit 1", intval($z[0]['id']));
            drop_item($z[0]['iid'], false);
            if ($interactive) {
                notice(t('Previous action reversed.') . EOL);
                return $o;
            }
            killme();
        }
    } else {
        // this is used to like an item or comment
        $item_id = argc() == 2 ? notags(trim(argv(1))) : 0;
        logger('like: verb ' . $verb . ' item ' . $item_id, LOGGER_DEBUG);
        // get the item. Allow linked photos (which are normally hidden) to be liked
        $r = q("SELECT * FROM item WHERE id = %d and (item_restrict = 0 or item_restrict = %d) LIMIT 1", intval($item_id), intval(ITEM_HIDDEN));
        if (!$item_id || !$r) {
            logger('like: no item ' . $item_id);
            killme();
        }
        $item = $r[0];
        $owner_uid = $item['uid'];
        $owner_aid = $item['aid'];
        $sys = get_sys_channel();
        // if this is a "discover" item, (item['uid'] is the sys channel),
        // fallback to the item comment policy, which should've been
        // respected when generating the conversation thread.
        // Even if the activity is rejected by the item owner, it should still get attached
        // to the local discover conversation on this site.
        if ($owner_uid != $sys['channel_id'] && !perm_is_allowed($owner_uid, $observer['xchan_hash'], 'post_comments')) {
            notice(t('Permission denied') . EOL);
            killme();
        }
        $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($item['owner_xchan']));
        if ($r) {
            $thread_owner = $r[0];
        } else {
            killme();
        }
        $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($item['author_xchan']));
        if ($r) {
            $item_author = $r[0];
        } else {
            killme();
        }
        $verbs = " '" . dbesc($activity) . "' ";
        $multi_undo = 0;
        // event participation and consensus items are essentially radio toggles. If you make a subsequent choice,
        // we need to eradicate your first choice.
        if ($activity === ACTIVITY_ATTEND || $activity === ACTIVITY_ATTENDNO || $activity === ACTIVITY_ATTENDMAYBE) {
            $verbs = " '" . dbesc(ACTIVITY_ATTEND) . "','" . dbesc(ACTIVITY_ATTENDNO) . "','" . dbesc(ACTIVITY_ATTENDMAYBE) . "' ";
            $multi_undo = 1;
        }
        if ($activity === ACTIVITY_AGREE || $activity === ACTIVITY_DISAGREE || $activity === ACTIVITY_ABSTAIN) {
            $verbs = " '" . dbesc(ACTIVITY_AGREE) . "','" . dbesc(ACTIVITY_DISAGREE) . "','" . dbesc(ACTIVITY_ABSTAIN) . "' ";
            $multi_undo = 1;
        }
        $r = q("SELECT id, parent, uid, verb FROM item WHERE verb in ( {$verbs} ) AND item_restrict = 0 \n\t\t\tAND author_xchan = '%s' AND ( parent = %d OR thr_parent = '%s') and uid = %d ", dbesc($observer['xchan_hash']), intval($item_id), dbesc($item['mid']), intval($owner_uid));
        if ($r) {
            // already liked it. Drop that item.
            require_once 'include/items.php';
            foreach ($r as $rr) {
                drop_item($rr['id'], false, DROPITEM_PHASE1);
                // set the changed timestamp on the parent so we'll see the update without a page reload
                $z = q("update item set changed = '%s' where id = %d and uid = %d", dbesc(datetime_convert()), intval($rr['parent']), intval($rr['uid']));
                // Prior activity was a duplicate of the one we're submitting, just undo it;
                // don't fall through and create another
                if (activity_match($rr['verb'], $activity)) {
                    $multi_undo = false;
                }
            }
            if ($interactive) {
                return;
            }
            if (!$multi_undo) {
                killme();
            }
        }
    }
    $mid = item_message_id();
    if ($extended_like) {
        $item_flags = ITEM_THREAD_TOP | ITEM_ORIGIN | ITEM_WALL;
    } else {
        $post_type = $item['resource_type'] === 'photo' ? t('photo') : t('status');
        if ($item['obj_type'] === ACTIVITY_OBJ_EVENT) {
            $post_type = t('event');
        }
        $links = array(array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item['plink']));
        $objtype = $item['resource_type'] === 'photo' ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE;
        $body = $item['body'];
        $object = json_encode(array('type' => $objtype, 'id' => $item['mid'], 'parent' => $item['thr_parent'] ? $item['thr_parent'] : $item['parent_mid'], 'link' => $links, 'title' => $item['title'], 'content' => $item['body'], 'created' => $item['created'], 'edited' => $item['edited'], 'author' => array('name' => $item_author['xchan_name'], 'address' => $item_author['xchan_addr'], 'guid' => $item_author['xchan_guid'], 'guid_sig' => $item_author['xchan_guid_sig'], 'link' => array(array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item_author['xchan_url']), array('rel' => 'photo', 'type' => $item_author['xchan_photo_mimetype'], 'href' => $item_author['xchan_photo_m'])))));
        if (!($item['item_flags'] & ITEM_THREAD_TOP)) {
            $post_type = 'comment';
        }
        $item_flags = ITEM_ORIGIN | ITEM_NOTSHOWN;
        if ($item['item_flags'] & ITEM_WALL) {
            $item_flags |= ITEM_WALL;
        }
        // if this was a linked photo and was hidden, unhide it.
        if ($item['item_restrict'] & ITEM_HIDDEN) {
            $r = q("update item set item_restrict = (item_restrict ^ %d) where id = %d", intval(ITEM_HIDDEN), intval($item['id']));
        }
    }
    if ($verb === 'like') {
        $bodyverb = t('%1$s likes %2$s\'s %3$s');
    }
    if ($verb === 'dislike') {
        $bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s');
    }
    if ($verb === 'agree') {
        $bodyverb = t('%1$s agrees with %2$s\'s %3$s');
    }
    if ($verb === 'disagree') {
        $bodyverb = t('%1$s doesn\'t agree with %2$s\'s %3$s');
    }
    if ($verb === 'abstain') {
        $bodyverb = t('%1$s abstains from a decision on %2$s\'s %3$s');
    }
    if ($verb === 'attendyes') {
        $bodyverb = t('%1$s is attending %2$s\'s %3$s');
    }
    if ($verb === 'attendno') {
        $bodyverb = t('%1$s is not attending %2$s\'s %3$s');
    }
    if ($verb === 'attendmaybe') {
        $bodyverb = t('%1$s may attend %2$s\'s %3$s');
    }
    if (!isset($bodyverb)) {
        killme();
    }
    $arr = array();
    if ($extended_like) {
        $ulink = '[zrl=' . $ch[0]['xchan_url'] . ']' . $ch[0]['xchan_name'] . '[/zrl]';
        $alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]';
        $private = $public ? 0 : 1;
    } else {
        $arr['parent'] = $item['id'];
        $arr['thr_parent'] = $item['mid'];
        $ulink = '[zrl=' . $item_author['xchan_url'] . ']' . $item_author['xchan_name'] . '[/zrl]';
        $alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]';
        $plink = '[zrl=' . $a->get_baseurl() . '/display/' . $item['mid'] . ']' . $post_type . '[/zrl]';
        $allow_cid = $item['allow_cid'];
        $allow_gid = $item['allow_gid'];
        $deny_cid = $item['deny_cid'];
        $deny_gid = $item['deny_gid'];
        $private = $item['private'];
    }
    $arr['mid'] = $mid;
    $arr['aid'] = $extended_like ? $ch[0]['channel_account_id'] : $owner_aid;
    $arr['uid'] = $owner_uid;
    $arr['item_flags'] = $item_flags;
    $arr['parent_mid'] = $extended_like ? $mid : $item['mid'];
    $arr['owner_xchan'] = $extended_like ? $ch[0]['xchan_hash'] : $thread_owner['xchan_hash'];
    $arr['author_xchan'] = $observer['xchan_hash'];
    $arr['body'] = sprintf($bodyverb, $alink, $ulink, $plink);
    if ($obj_type === 'thing' && $r[0]['imgurl']) {
        $arr['body'] .= "\n\n[zmg=80x80]" . $r[0]['imgurl'] . '[/zmg]';
    }
    $arr['verb'] = $activity;
    $arr['obj_type'] = $objtype;
    $arr['object'] = $object;
    if ($target) {
        $arr['tgt_type'] = $tgttype;
        $arr['target'] = $target;
    }
    $arr['allow_cid'] = $allow_cid;
    $arr['allow_gid'] = $allow_gid;
    $arr['deny_cid'] = $deny_cid;
    $arr['deny_gid'] = $deny_gid;
    $arr['item_private'] = $private;
    $post = item_store($arr);
    $post_id = $post['item_id'];
    $arr['id'] = $post_id;
    call_hooks('post_local_end', $arr);
    if ($extended_like) {
        $r = q("insert into likes (channel_id,liker,likee,iid,verb,target_type,target_id,target) values (%d,'%s','%s',%d,'%s','%s','%s','%s')", intval($ch[0]['channel_id']), dbesc($observer['xchan_hash']), dbesc($ch[0]['channel_hash']), intval($post_id), dbesc($activity), dbesc($tgttype ? $tgttype : $objtype), dbesc($obj_id), dbesc(json_encode($target ? $target : $object)));
    }
    proc_run('php', "include/notifier.php", "like", "{$post_id}");
    if ($interactive) {
        notice(t('Action completed.') . EOL);
        $o .= t('Thank you.');
        return $o;
    }
    killme();
}
예제 #27
0
function diaspora_like($importer, $xml, $msg)
{
    $a = get_app();
    $guid = notags(unxmlify($xml->guid));
    $parent_guid = notags(unxmlify($xml->parent_guid));
    $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
    $target_type = notags(unxmlify($xml->target_type));
    $positive = notags(unxmlify($xml->positive));
    $author_signature = notags(unxmlify($xml->author_signature));
    $parent_author_signature = $xml->parent_author_signature ? notags(unxmlify($xml->parent_author_signature)) : '';
    // likes on comments not supported here and likes on photos not supported by Diaspora
    //	if($target_type !== 'Post')
    //		return;
    $contact = diaspora_get_contact_by_handle($importer['uid'], $msg['author']);
    if (!$contact) {
        logger('diaspora_like: cannot find contact: ' . $msg['author']);
        return;
    }
    if (!diaspora_post_allow($importer, $contact, false)) {
        logger('diaspora_like: Ignoring this author.');
        return 202;
    }
    $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1", intval($importer['uid']), dbesc($parent_guid));
    if (!count($r)) {
        $result = diaspora_store_by_guid($parent_guid, $contact['url'], $importer['uid']);
        if (!$result) {
            $person = find_diaspora_person_by_handle($diaspora_handle);
            $result = diaspora_store_by_guid($parent_guid, $person['url'], $importer['uid']);
        }
        if ($result) {
            logger("Fetched missing item " . $parent_guid . " - result: " . $result, LOGGER_DEBUG);
            $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1", intval($importer['uid']), dbesc($parent_guid));
        }
    }
    if (!count($r)) {
        logger('diaspora_like: parent item not found: ' . $guid);
        return;
    }
    $parent_item = $r[0];
    $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1", intval($importer['uid']), dbesc($guid));
    if (count($r)) {
        if ($positive === 'true') {
            logger('diaspora_like: duplicate like: ' . $guid);
            return;
        }
        // Note: I don't think "Like" objects with positive = "false" are ever actually used
        // It looks like "RelayableRetractions" are used for "unlike" instead
        if ($positive === 'false') {
            logger('diaspora_like: received a like with positive set to "false"...ignoring');
            /*			q("UPDATE `item` SET `deleted` = 1 WHERE `id` = %d AND `uid` = %d",
            				intval($r[0]['id']),
            				intval($importer['uid'])
            			);*/
            // FIXME--actually don't unless it turns out that Diaspora does indeed send out "false" likes
            //  send notification via proc_run()
            return;
        }
    }
    // Note: I don't think "Like" objects with positive = "false" are ever actually used
    // It looks like "RelayableRetractions" are used for "unlike" instead
    if ($positive === 'false') {
        logger('diaspora_like: received a like with positive set to "false"');
        logger('diaspora_like: unlike received with no corresponding like...ignoring');
        return;
    }
    /* How Diaspora performs "like" signature checking:
    
    	   - If an item has been sent by the like author to the top-level post owner to relay on
    	     to the rest of the contacts on the top-level post, the top-level post owner should check
    	     the author_signature, then create a parent_author_signature before relaying the like on
    	   - If an item has been relayed on by the top-level post owner, the contacts who receive it
    	     check only the parent_author_signature. Basically, they trust that the top-level post
    	     owner has already verified the authenticity of anything he/she sends out
    	   - In either case, the signature that get checked is the signature created by the person
    	     who sent the salmon
    	*/
    // Diaspora has changed the way they are signing the likes.
    // Just to make sure that we don't miss any likes we will check the old and the current way.
    $old_signed_data = $guid . ';' . $target_type . ';' . $parent_guid . ';' . $positive . ';' . $diaspora_handle;
    $signed_data = $positive . ';' . $guid . ';' . $target_type . ';' . $parent_guid . ';' . $diaspora_handle;
    $key = $msg['key'];
    if ($parent_author_signature) {
        // If a parent_author_signature exists, then we've received the like
        // relayed from the top-level post owner. There's no need to check the
        // author_signature if the parent_author_signature is valid
        $parent_author_signature = base64_decode($parent_author_signature);
        if (!rsa_verify($signed_data, $parent_author_signature, $key, 'sha256') and !rsa_verify($old_signed_data, $parent_author_signature, $key, 'sha256')) {
            logger('diaspora_like: top-level owner verification failed.');
            return;
        }
    } else {
        // If there's no parent_author_signature, then we've received the like
        // from the like creator. In that case, the person is "like"ing
        // our post, so he/she must be a contact of ours and his/her public key
        // should be in $msg['key']
        $author_signature = base64_decode($author_signature);
        if (!rsa_verify($signed_data, $author_signature, $key, 'sha256') and !rsa_verify($old_signed_data, $author_signature, $key, 'sha256')) {
            logger('diaspora_like: like creator verification failed.');
            return;
        }
    }
    // Phew! Everything checks out. Now create an item.
    // Find the original comment author information.
    // We need this to make sure we display the comment author
    // information (name and avatar) correctly.
    if (strcasecmp($diaspora_handle, $msg['author']) == 0) {
        $person = $contact;
    } else {
        $person = find_diaspora_person_by_handle($diaspora_handle);
        if (!is_array($person)) {
            logger('diaspora_like: unable to find author details');
            return;
        }
    }
    $uri = $diaspora_handle . ':' . $guid;
    $activity = ACTIVITY_LIKE;
    $post_type = $parent_item['resource-id'] ? t('photo') : t('status');
    $objtype = $parent_item['resource-id'] ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE;
    $link = xmlify('<link rel="alternate" type="text/html" href="' . $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $parent_item['id'] . '" />' . "\n");
    $body = $parent_item['body'];
    $obj = <<<EOT

\t<object>
\t\t<type>{$objtype}</type>
\t\t<local>1</local>
\t\t<id>{$parent_item['uri']}</id>
\t\t<link>{$link}</link>
\t\t<title></title>
\t\t<content>{$body}</content>
\t</object>
EOT;
    $bodyverb = t('%1$s likes %2$s\'s %3$s');
    $arr = array();
    $arr['uri'] = $uri;
    $arr['uid'] = $importer['uid'];
    $arr['guid'] = $guid;
    $arr['network'] = NETWORK_DIASPORA;
    $arr['contact-id'] = $contact['id'];
    $arr['type'] = 'activity';
    $arr['wall'] = $parent_item['wall'];
    $arr['gravity'] = GRAVITY_LIKE;
    $arr['parent'] = $parent_item['id'];
    $arr['parent-uri'] = $parent_item['uri'];
    $arr['owner-name'] = $parent_item['name'];
    $arr['owner-link'] = $parent_item['url'];
    //$arr['owner-avatar'] = $parent_item['thumb'];
    $arr['owner-avatar'] = x($parent_item, 'thumb') ? $parent_item['thumb'] : $parent_item['photo'];
    $arr['author-name'] = $person['name'];
    $arr['author-link'] = $person['url'];
    $arr['author-avatar'] = x($person, 'thumb') ? $person['thumb'] : $person['photo'];
    $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
    $alink = '[url=' . $parent_item['author-link'] . ']' . $parent_item['author-name'] . '[/url]';
    //$plink = '[url=' . $a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $parent_item['id'] . ']' . $post_type . '[/url]';
    $plink = '[url=' . $a->get_baseurl() . '/display/' . urlencode($guid) . ']' . $post_type . '[/url]';
    $arr['body'] = sprintf($bodyverb, $ulink, $alink, $plink);
    $arr['app'] = 'Diaspora';
    $arr['private'] = $parent_item['private'];
    $arr['verb'] = $activity;
    $arr['object-type'] = $objtype;
    $arr['object'] = $obj;
    $arr['visible'] = 1;
    $arr['unseen'] = 1;
    $arr['last-child'] = 0;
    $message_id = item_store($arr);
    //if($message_id) {
    //	q("update item set plink = '%s' where id = %d",
    //		//dbesc($a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id),
    //		dbesc($a->get_baseurl().'/display/'.$guid),
    //		intval($message_id)
    //	);
    //}
    if (!$parent_author_signature) {
        q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($message_id), dbesc($signed_data), dbesc(base64_encode($author_signature)), dbesc($diaspora_handle));
    }
    // if the message isn't already being relayed, notify others
    // the existence of parent_author_signature means the parent_author or owner
    // is already relaying. The parent_item['origin'] indicates the message was created on our system
    if ($parent_item['origin'] && !$parent_author_signature) {
        proc_run('php', 'include/notifier.php', 'comment-import', $message_id);
    }
    return;
}
예제 #28
0
파일: help.php 프로젝트: BlaBlaNet/hubzilla
function store_doc_file($s)
{
    if (is_dir($s)) {
        return;
    }
    $item = array();
    $sys = get_sys_channel();
    $item['aid'] = 0;
    $item['uid'] = $sys['channel_id'];
    if (strpos($s, '.md')) {
        $mimetype = 'text/markdown';
    } elseif (strpos($s, '.html')) {
        $mimetype = 'text/html';
    } else {
        $mimetype = 'text/bbcode';
    }
    require_once 'include/html2plain.php';
    $item['body'] = html2plain(prepare_text(file_get_contents($s), $mimetype, true));
    $item['mimetype'] = 'text/plain';
    $item['plink'] = z_root() . '/' . str_replace('doc', 'help', $s);
    $item['owner_xchan'] = $item['author_xchan'] = $sys['channel_hash'];
    $item['item_type'] = ITEM_TYPE_DOC;
    $r = q("select item.* from item left join iconfig on item.id = iconfig.iid \n\t\twhere iconfig.cat = 'system' and iconfig.k = 'docfile' and\n\t\ticonfig.v = '%s' and item_type = %d limit 1", dbesc($s), intval(ITEM_TYPE_DOC));
    \Zotlabs\Lib\IConfig::Set($item, 'system', 'docfile', $s);
    if ($r) {
        $item['id'] = $r[0]['id'];
        $item['mid'] = $item['parent_mid'] = $r[0]['mid'];
        $x = item_store_update($item);
    } else {
        $item['mid'] = $item['parent_mid'] = item_message_id();
        $x = item_store($item);
    }
    return $x;
}
예제 #29
0
function event_store_item($arr, $event)
{
    require_once 'include/datetime.php';
    require_once 'include/items.php';
    require_once 'include/bbcode.php';
    $item = null;
    if ($arr['mid'] && $arr['uid']) {
        $i = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc($arr['mid']), intval($arr['uid']));
        if ($i) {
            xchan_query($i);
            $item = fetch_post_tags($i, true);
        }
    }
    $item_arr = array();
    $prefix = '';
    //	$birthday = false;
    if ($event['type'] === 'birthday') {
        $prefix = t('This event has been added to your calendar.');
        //		$birthday = true;
        // The event is created on your own site by the system, but appears to belong
        // to the birthday person. It also isn't propagated - so we need to prevent
        // folks from trying to comment on it. If you're looking at this and trying to
        // fix it, you'll need to completely change the way birthday events are created
        // and send them out from the source. This has its own issues.
        $item_arr['comment_policy'] = 'none';
    }
    $r = q("SELECT * FROM item left join xchan on author_xchan = xchan_hash WHERE resource_id = '%s' AND resource_type = 'event' and uid = %d LIMIT 1", dbesc($event['event_hash']), intval($arr['uid']));
    if ($r) {
        $object = json_encode(array('type' => ACTIVITY_OBJ_EVENT, 'id' => z_root() . '/event/' . $r[0]['resource_id'], 'title' => $arr['summary'], 'content' => format_event_bbcode($arr), 'author' => array('name' => $r[0]['xchan_name'], 'address' => $r[0]['xchan_addr'], 'guid' => $r[0]['xchan_guid'], 'guid_sig' => $r[0]['xchan_guid_sig'], 'link' => array(array('rel' => 'alternate', 'type' => 'text/html', 'href' => $r[0]['xchan_url']), array('rel' => 'photo', 'type' => $r[0]['xchan_photo_mimetype'], 'href' => $r[0]['xchan_photo_m'])))));
        $private = $arr['allow_cid'] || $arr['allow_gid'] || $arr['deny_cid'] || $arr['deny_gid'] ? 1 : 0;
        q("UPDATE item SET title = '%s', body = '%s', object = '%s', allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', edited = '%s', item_flags = %d, item_private = %d, obj_type = '%s'  WHERE id = %d AND uid = %d", dbesc($arr['summary']), dbesc($prefix . format_event_bbcode($arr)), dbesc($object), dbesc($arr['allow_cid']), dbesc($arr['allow_gid']), dbesc($arr['deny_cid']), dbesc($arr['deny_gid']), dbesc($arr['edited']), intval($r[0]['item_flags']), intval($private), dbesc(ACTIVITY_OBJ_EVENT), intval($r[0]['id']), intval($arr['uid']));
        q("delete from term where oid = %d and otype = %d", intval($r[0]['id']), intval(TERM_OBJ_POST));
        if ($arr['term'] && is_array($arr['term'])) {
            foreach ($arr['term'] as $t) {
                q("insert into term (uid,oid,otype,type,term,url)\n\t\t\t\t\tvalues(%d,%d,%d,%d,'%s','%s') ", intval($arr['uid']), intval($r[0]['id']), intval(TERM_OBJ_POST), intval($t['type']), dbesc($t['term']), dbesc($t['url']));
            }
        }
        $item_id = $r[0]['id'];
        call_hooks('event_updated', $event['id']);
        return $item_id;
    } else {
        $z = q("select * from channel where channel_id = %d limit 1", intval($arr['uid']));
        $private = $arr['allow_cid'] || $arr['allow_gid'] || $arr['deny_cid'] || $arr['deny_gid'] ? 1 : 0;
        if ($item) {
            $item_arr['id'] = $item['id'];
        } else {
            $wall = $z[0]['channel_hash'] == $event['event_xchan'] ? true : false;
            $item_flags = ITEM_THREAD_TOP;
            if ($wall) {
                $item_flags |= ITEM_WALL;
                $item_flags |= ITEM_ORIGIN;
            }
            $item_arr['item_flags'] = $item_flags;
        }
        if (!$arr['mid']) {
            $arr['mid'] = item_message_id();
        }
        $item_arr['aid'] = $z[0]['channel_account_id'];
        $item_arr['uid'] = $arr['uid'];
        $item_arr['author_xchan'] = $arr['event_xchan'];
        $item_arr['mid'] = $arr['mid'];
        $item_arr['parent_mid'] = $arr['mid'];
        $item_arr['owner_xchan'] = $wall ? $z[0]['channel_hash'] : $arr['event_xchan'];
        $item_arr['author_xchan'] = $arr['event_xchan'];
        $item_arr['title'] = $arr['summary'];
        $item_arr['allow_cid'] = $arr['allow_cid'];
        $item_arr['allow_gid'] = $arr['allow_gid'];
        $item_arr['deny_cid'] = $arr['deny_cid'];
        $item_arr['deny_gid'] = $arr['deny_gid'];
        $item_arr['item_private'] = $private;
        $item_arr['verb'] = ACTIVITY_POST;
        if (array_key_exists('term', $arr)) {
            $item_arr['term'] = $arr['term'];
        }
        $item_arr['resource_type'] = 'event';
        $item_arr['resource_id'] = $event['event_hash'];
        $item_arr['obj_type'] = ACTIVITY_OBJ_EVENT;
        $item_arr['body'] = $prefix . format_event_bbcode($arr);
        // if it's local send the permalink to the channel page.
        // otherwise we'll fallback to /display/$message_id
        if ($wall) {
            $item_arr['plink'] = z_root() . '/channel/' . $z[0]['channel_address'] . '/?f=&mid=' . $item_arr['mid'];
        } else {
            $item_arr['plink'] = z_root() . '/display/' . $item_arr['mid'];
        }
        $x = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($arr['event_xchan']));
        if ($x) {
            $item_arr['object'] = json_encode(array('type' => ACTIVITY_OBJ_EVENT, 'id' => z_root() . '/event/' . $event['event_hash'], 'title' => $arr['summary'], 'content' => format_event_bbcode($arr), 'author' => array('name' => $x[0]['xchan_name'], 'address' => $x[0]['xchan_addr'], 'guid' => $x[0]['xchan_guid'], 'guid_sig' => $x[0]['xchan_guid_sig'], 'link' => array(array('rel' => 'alternate', 'type' => 'text/html', 'href' => $x[0]['xchan_url']), array('rel' => 'photo', 'type' => $x[0]['xchan_photo_mimetype'], 'href' => $x[0]['xchan_photo_m'])))));
        }
        $res = item_store($item_arr);
        $item_id = $res['item_id'];
        call_hooks('event_created', $event['id']);
        return $item_id;
    }
}
예제 #30
0
function local_delivery($importer, $data)
{
    $a = get_app();
    logger(__FUNCTION__, LOGGER_TRACE);
    if ($importer['readonly']) {
        // We aren't receiving stuff from this person. But we will quietly ignore them
        // rather than a blatant "go away" message.
        logger('local_delivery: ignoring');
        return 0;
        //NOTREACHED
    }
    // Consume notification feed. This may differ from consuming a public feed in several ways
    // - might contain email or friend suggestions
    // - might contain remote followup to our message
    //		- in which case we need to accept it and then notify other conversants
    // - we may need to send various email notifications
    $feed = new SimplePie();
    $feed->set_raw_data($data);
    $feed->enable_order_by_date(false);
    $feed->init();
    if ($feed->error()) {
        logger('local_delivery: Error parsing XML: ' . $feed->error());
    }
    // Check at the feed level for updated contact name and/or photo
    $name_updated = '';
    $new_name = '';
    $photo_timestamp = '';
    $photo_url = '';
    $contact_updated = '';
    $rawtags = $feed->get_feed_tags(NAMESPACE_DFRN, 'owner');
    // Fallback should not be needed here. If it isn't DFRN it won't have DFRN updated tags
    //	if(! $rawtags)
    //		$rawtags = $feed->get_feed_tags( SIMPLEPIE_NAMESPACE_ATOM_10, 'author');
    if ($rawtags) {
        $elems = $rawtags[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10];
        if ($elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated']) {
            $name_updated = $elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated'];
            $new_name = $elems['name'][0]['data'];
            // Manually checking for changed contact names
            if ($new_name != $importer['name'] and $new_name != "" and $name_updated <= $importer['name-date']) {
                $name_updated = date("c");
                $photo_timestamp = date("c");
            }
        }
        if (x($elems, 'link') && $elems['link'][0]['attribs']['']['rel'] === 'photo' && $elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated']) {
            if ($photo_timestamp == "") {
                $photo_timestamp = datetime_convert('UTC', 'UTC', $elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated']);
            }
            $photo_url = $elems['link'][0]['attribs']['']['href'];
        }
    }
    if ($photo_timestamp && strlen($photo_url) && $photo_timestamp > $importer['avatar-date']) {
        $contact_updated = $photo_timestamp;
        logger('local_delivery: Updating photo for ' . $importer['name']);
        require_once "include/Photo.php";
        $photos = import_profile_photo($photo_url, $importer['importer_uid'], $importer['id']);
        q("UPDATE `contact` SET `avatar-date` = '%s', `photo` = '%s', `thumb` = '%s', `micro` = '%s'\n\t\t\tWHERE `uid` = %d AND `id` = %d AND NOT `self`", dbesc(datetime_convert()), dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), intval($importer['importer_uid']), intval($importer['id']));
    }
    if ($name_updated && strlen($new_name) && $name_updated > $importer['name-date']) {
        if ($name_updated > $contact_updated) {
            $contact_updated = $name_updated;
        }
        $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($importer['importer_uid']), intval($importer['id']));
        $x = q("UPDATE `contact` SET `name` = '%s', `name-date` = '%s' WHERE `uid` = %d AND `id` = %d AND `name` != '%s' AND NOT `self`", dbesc(notags(trim($new_name))), dbesc(datetime_convert()), intval($importer['importer_uid']), intval($importer['id']), dbesc(notags(trim($new_name))));
        // do our best to update the name on content items
        if (count($r) and notags(trim($new_name)) != $r[0]['name']) {
            q("UPDATE `item` SET `author-name` = '%s' WHERE `author-name` = '%s' AND `author-link` = '%s' AND `uid` = %d AND `author-name` != '%s'", dbesc(notags(trim($new_name))), dbesc($r[0]['name']), dbesc($r[0]['url']), intval($importer['importer_uid']), dbesc(notags(trim($new_name))));
        }
    }
    if ($contact_updated and $new_name and $photo_url) {
        poco_check($importer['url'], $new_name, NETWORK_DFRN, $photo_url, "", "", "", "", "", $contact_updated, 2, $importer['id'], $importer['importer_uid']);
    }
    // Currently unsupported - needs a lot of work
    $reloc = $feed->get_feed_tags(NAMESPACE_DFRN, 'relocate');
    if (isset($reloc[0]['child'][NAMESPACE_DFRN])) {
        $base = $reloc[0]['child'][NAMESPACE_DFRN];
        $newloc = array();
        $newloc['uid'] = $importer['importer_uid'];
        $newloc['cid'] = $importer['id'];
        $newloc['name'] = notags(unxmlify($base['name'][0]['data']));
        $newloc['photo'] = notags(unxmlify($base['photo'][0]['data']));
        $newloc['thumb'] = notags(unxmlify($base['thumb'][0]['data']));
        $newloc['micro'] = notags(unxmlify($base['micro'][0]['data']));
        $newloc['url'] = notags(unxmlify($base['url'][0]['data']));
        $newloc['request'] = notags(unxmlify($base['request'][0]['data']));
        $newloc['confirm'] = notags(unxmlify($base['confirm'][0]['data']));
        $newloc['notify'] = notags(unxmlify($base['notify'][0]['data']));
        $newloc['poll'] = notags(unxmlify($base['poll'][0]['data']));
        $newloc['sitepubkey'] = notags(unxmlify($base['sitepubkey'][0]['data']));
        /** relocated user must have original key pair */
        /*$newloc['pubkey'] = notags(unxmlify($base['pubkey'][0]['data']));
        		$newloc['prvkey'] = notags(unxmlify($base['prvkey'][0]['data']));*/
        logger("items:relocate contact " . print_r($newloc, true) . print_r($importer, true), LOGGER_DEBUG);
        // update contact
        $r = q("SELECT photo, url FROM contact WHERE id=%d AND uid=%d;", intval($importer['id']), intval($importer['importer_uid']));
        if ($r === false) {
            return 1;
        }
        $old = $r[0];
        $x = q("UPDATE contact SET\n\t\t\t\t\tname = '%s',\n\t\t\t\t\tphoto = '%s',\n\t\t\t\t\tthumb = '%s',\n\t\t\t\t\tmicro = '%s',\n\t\t\t\t\turl = '%s',\n\t\t\t\t\tnurl = '%s',\n\t\t\t\t\trequest = '%s',\n\t\t\t\t\tconfirm = '%s',\n\t\t\t\t\tnotify = '%s',\n\t\t\t\t\tpoll = '%s',\n\t\t\t\t\t`site-pubkey` = '%s'\n\t\t\tWHERE id=%d AND uid=%d;", dbesc($newloc['name']), dbesc($newloc['photo']), dbesc($newloc['thumb']), dbesc($newloc['micro']), dbesc($newloc['url']), dbesc(normalise_link($newloc['url'])), dbesc($newloc['request']), dbesc($newloc['confirm']), dbesc($newloc['notify']), dbesc($newloc['poll']), dbesc($newloc['sitepubkey']), intval($importer['id']), intval($importer['importer_uid']));
        if ($x === false) {
            return 1;
        }
        // update items
        $fields = array('owner-link' => array($old['url'], $newloc['url']), 'author-link' => array($old['url'], $newloc['url']), 'owner-avatar' => array($old['photo'], $newloc['photo']), 'author-avatar' => array($old['photo'], $newloc['photo']));
        foreach ($fields as $n => $f) {
            $x = q("UPDATE `item` SET `%s`='%s' WHERE `%s`='%s' AND uid=%d", $n, dbesc($f[1]), $n, dbesc($f[0]), intval($importer['importer_uid']));
            if ($x === false) {
                return 1;
            }
        }
        // TODO
        // merge with current record, current contents have priority
        // update record, set url-updated
        // update profile photos
        // schedule a scan?
        return 0;
    }
    // handle friend suggestion notification
    $sugg = $feed->get_feed_tags(NAMESPACE_DFRN, 'suggest');
    if (isset($sugg[0]['child'][NAMESPACE_DFRN])) {
        $base = $sugg[0]['child'][NAMESPACE_DFRN];
        $fsugg = array();
        $fsugg['uid'] = $importer['importer_uid'];
        $fsugg['cid'] = $importer['id'];
        $fsugg['name'] = notags(unxmlify($base['name'][0]['data']));
        $fsugg['photo'] = notags(unxmlify($base['photo'][0]['data']));
        $fsugg['url'] = notags(unxmlify($base['url'][0]['data']));
        $fsugg['request'] = notags(unxmlify($base['request'][0]['data']));
        $fsugg['body'] = escape_tags(unxmlify($base['note'][0]['data']));
        // Does our member already have a friend matching this description?
        $r = q("SELECT * FROM `contact` WHERE `name` = '%s' AND `nurl` = '%s' AND `uid` = %d LIMIT 1", dbesc($fsugg['name']), dbesc(normalise_link($fsugg['url'])), intval($fsugg['uid']));
        if (count($r)) {
            return 0;
        }
        // Do we already have an fcontact record for this person?
        $fid = 0;
        $r = q("SELECT * FROM `fcontact` WHERE `url` = '%s' AND `name` = '%s' AND `request` = '%s' LIMIT 1", dbesc($fsugg['url']), dbesc($fsugg['name']), dbesc($fsugg['request']));
        if (count($r)) {
            $fid = $r[0]['id'];
            // OK, we do. Do we already have an introduction for this person ?
            $r = q("select id from intro where uid = %d and fid = %d limit 1", intval($fsugg['uid']), intval($fid));
            if (count($r)) {
                return 0;
            }
        }
        if (!$fid) {
            $r = q("INSERT INTO `fcontact` ( `name`,`url`,`photo`,`request` ) VALUES ( '%s', '%s', '%s', '%s' ) ", dbesc($fsugg['name']), dbesc($fsugg['url']), dbesc($fsugg['photo']), dbesc($fsugg['request']));
        }
        $r = q("SELECT * FROM `fcontact` WHERE `url` = '%s' AND `name` = '%s' AND `request` = '%s' LIMIT 1", dbesc($fsugg['url']), dbesc($fsugg['name']), dbesc($fsugg['request']));
        if (count($r)) {
            $fid = $r[0]['id'];
        } else {
            return 0;
        }
        $hash = random_string();
        $r = q("INSERT INTO `intro` ( `uid`, `fid`, `contact-id`, `note`, `hash`, `datetime`, `blocked` )\n\t\t\tVALUES( %d, %d, %d, '%s', '%s', '%s', %d )", intval($fsugg['uid']), intval($fid), intval($fsugg['cid']), dbesc($fsugg['body']), dbesc($hash), dbesc(datetime_convert()), intval(0));
        notification(array('type' => NOTIFY_SUGGEST, 'notify_flags' => $importer['notify-flags'], 'language' => $importer['language'], 'to_name' => $importer['username'], 'to_email' => $importer['email'], 'uid' => $importer['importer_uid'], 'item' => $fsugg, 'link' => $a->get_baseurl() . '/notifications/intros', 'source_name' => $importer['name'], 'source_link' => $importer['url'], 'source_photo' => $importer['photo'], 'verb' => ACTIVITY_REQ_FRIEND, 'otype' => 'intro'));
        return 0;
    }
    $ismail = false;
    $rawmail = $feed->get_feed_tags(NAMESPACE_DFRN, 'mail');
    if (isset($rawmail[0]['child'][NAMESPACE_DFRN])) {
        logger('local_delivery: private message received');
        $ismail = true;
        $base = $rawmail[0]['child'][NAMESPACE_DFRN];
        $msg = array();
        $msg['uid'] = $importer['importer_uid'];
        $msg['from-name'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['name'][0]['data']));
        $msg['from-photo'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['avatar'][0]['data']));
        $msg['from-url'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['uri'][0]['data']));
        $msg['contact-id'] = $importer['id'];
        $msg['title'] = notags(unxmlify($base['subject'][0]['data']));
        $msg['body'] = escape_tags(unxmlify($base['content'][0]['data']));
        $msg['seen'] = 0;
        $msg['replied'] = 0;
        $msg['uri'] = notags(unxmlify($base['id'][0]['data']));
        $msg['parent-uri'] = notags(unxmlify($base['in-reply-to'][0]['data']));
        $msg['created'] = datetime_convert(notags(unxmlify('UTC', 'UTC', $base['sentdate'][0]['data'])));
        dbesc_array($msg);
        $r = dbq("INSERT INTO `mail` (`" . implode("`, `", array_keys($msg)) . "`) VALUES ('" . implode("', '", array_values($msg)) . "')");
        // send notifications.
        require_once 'include/enotify.php';
        $notif_params = array('type' => NOTIFY_MAIL, 'notify_flags' => $importer['notify-flags'], 'language' => $importer['language'], 'to_name' => $importer['username'], 'to_email' => $importer['email'], 'uid' => $importer['importer_uid'], 'item' => $msg, 'source_name' => $msg['from-name'], 'source_link' => $importer['url'], 'source_photo' => $importer['thumb'], 'verb' => ACTIVITY_POST, 'otype' => 'mail');
        notification($notif_params);
        return 0;
        // NOTREACHED
    }
    $community_page = 0;
    $rawtags = $feed->get_feed_tags(NAMESPACE_DFRN, 'community');
    if ($rawtags) {
        $community_page = intval($rawtags[0]['data']);
    }
    if (intval($importer['forum']) != $community_page) {
        q("update contact set forum = %d where id = %d", intval($community_page), intval($importer['id']));
        $importer['forum'] = (string) $community_page;
    }
    logger('local_delivery: feed item count = ' . $feed->get_item_quantity());
    // process any deleted entries
    $del_entries = $feed->get_feed_tags(NAMESPACE_TOMB, 'deleted-entry');
    if (is_array($del_entries) && count($del_entries)) {
        foreach ($del_entries as $dentry) {
            $deleted = false;
            if (isset($dentry['attribs']['']['ref'])) {
                $uri = $dentry['attribs']['']['ref'];
                $deleted = true;
                if (isset($dentry['attribs']['']['when'])) {
                    $when = $dentry['attribs']['']['when'];
                    $when = datetime_convert('UTC', 'UTC', $when, 'Y-m-d H:i:s');
                } else {
                    $when = datetime_convert('UTC', 'UTC', 'now', 'Y-m-d H:i:s');
                }
            }
            if ($deleted) {
                // check for relayed deletes to our conversation
                $is_reply = false;
                $r = q("select * from item where uri = '%s' and uid = %d limit 1", dbesc($uri), intval($importer['importer_uid']));
                if (count($r)) {
                    $parent_uri = $r[0]['parent-uri'];
                    if ($r[0]['id'] != $r[0]['parent']) {
                        $is_reply = true;
                    }
                }
                if ($is_reply) {
                    $community = false;
                    if ($importer['page-flags'] == PAGE_COMMUNITY || $importer['page-flags'] == PAGE_PRVGROUP) {
                        $sql_extra = '';
                        $community = true;
                        logger('local_delivery: possible community delete');
                    } else {
                        $sql_extra = " and contact.self = 1 and item.wall = 1 ";
                    }
                    // was the top-level post for this reply written by somebody on this site?
                    // Specifically, the recipient?
                    $is_a_remote_delete = false;
                    // POSSIBLE CLEANUP --> Why select so many fields when only forum_mode and wall are used?
                    $r = q("select `item`.`id`, `item`.`uri`, `item`.`tag`, `item`.`forum_mode`,`item`.`origin`,`item`.`wall`,\n\t\t\t\t\t\t`contact`.`name`, `contact`.`url`, `contact`.`thumb` from `item`\n\t\t\t\t\t\tINNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`\n\t\t\t\t\t\tWHERE `item`.`uri` = '%s' AND (`item`.`parent-uri` = '%s' or `item`.`thr-parent` = '%s')\n\t\t\t\t\t\tAND `item`.`uid` = %d\n\t\t\t\t\t\t{$sql_extra}\n\t\t\t\t\t\tLIMIT 1", dbesc($parent_uri), dbesc($parent_uri), dbesc($parent_uri), intval($importer['importer_uid']));
                    if ($r && count($r)) {
                        $is_a_remote_delete = true;
                    }
                    // Does this have the characteristics of a community or private group comment?
                    // If it's a reply to a wall post on a community/prvgroup page it's a
                    // valid community comment. Also forum_mode makes it valid for sure.
                    // If neither, it's not.
                    if ($is_a_remote_delete && $community) {
                        if (!$r[0]['forum_mode'] && !$r[0]['wall']) {
                            $is_a_remote_delete = false;
                            logger('local_delivery: not a community delete');
                        }
                    }
                    if ($is_a_remote_delete) {
                        logger('local_delivery: received remote delete');
                    }
                }
                $r = q("SELECT `item`.*, `contact`.`self` FROM `item` INNER JOIN contact on `item`.`contact-id` = `contact`.`id`\n\t\t\t\t\tWHERE `uri` = '%s' AND `item`.`uid` = %d AND `contact-id` = %d AND NOT `item`.`file` LIKE '%%[%%' LIMIT 1", dbesc($uri), intval($importer['importer_uid']), intval($importer['id']));
                if (count($r)) {
                    $item = $r[0];
                    if ($item['deleted']) {
                        continue;
                    }
                    logger('local_delivery: deleting item ' . $item['id'] . ' uri=' . $item['uri'], LOGGER_DEBUG);
                    if ($item['object-type'] === ACTIVITY_OBJ_EVENT) {
                        logger("Deleting event " . $item['event-id'], LOGGER_DEBUG);
                        event_delete($item['event-id']);
                    }
                    if ($item['verb'] === ACTIVITY_TAG && $item['object-type'] === ACTIVITY_OBJ_TAGTERM) {
                        $xo = parse_xml_string($item['object'], false);
                        $xt = parse_xml_string($item['target'], false);
                        if ($xt->type === ACTIVITY_OBJ_NOTE) {
                            $i = q("select * from `item` where uri = '%s' and uid = %d limit 1", dbesc($xt->id), intval($importer['importer_uid']));
                            if (count($i)) {
                                // For tags, the owner cannot remove the tag on the author's copy of the post.
                                $owner_remove = $item['contact-id'] == $i[0]['contact-id'] ? true : false;
                                $author_remove = $item['origin'] && $item['self'] ? true : false;
                                $author_copy = $item['origin'] ? true : false;
                                if ($owner_remove && $author_copy) {
                                    continue;
                                }
                                if ($author_remove || $owner_remove) {
                                    $tags = explode(',', $i[0]['tag']);
                                    $newtags = array();
                                    if (count($tags)) {
                                        foreach ($tags as $tag) {
                                            if (trim($tag) !== trim($xo->body)) {
                                                $newtags[] = trim($tag);
                                            }
                                        }
                                    }
                                    q("update item set tag = '%s' where id = %d", dbesc(implode(',', $newtags)), intval($i[0]['id']));
                                    create_tags_from_item($i[0]['id']);
                                }
                            }
                        }
                    }
                    if ($item['uri'] == $item['parent-uri']) {
                        $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',\n\t\t\t\t\t\t\t`body` = '', `title` = ''\n\t\t\t\t\t\t\tWHERE `parent-uri` = '%s' AND `uid` = %d", dbesc($when), dbesc(datetime_convert()), dbesc($item['uri']), intval($importer['importer_uid']));
                        create_tags_from_itemuri($item['uri'], $importer['importer_uid']);
                        create_files_from_itemuri($item['uri'], $importer['importer_uid']);
                        update_thread_uri($item['uri'], $importer['importer_uid']);
                    } else {
                        $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',\n\t\t\t\t\t\t\t`body` = '', `title` = ''\n\t\t\t\t\t\t\tWHERE `uri` = '%s' AND `uid` = %d", dbesc($when), dbesc(datetime_convert()), dbesc($uri), intval($importer['importer_uid']));
                        create_tags_from_itemuri($uri, $importer['importer_uid']);
                        create_files_from_itemuri($uri, $importer['importer_uid']);
                        update_thread_uri($uri, $importer['importer_uid']);
                        if ($item['last-child']) {
                            // ensure that last-child is set in case the comment that had it just got wiped.
                            q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ", dbesc(datetime_convert()), dbesc($item['parent-uri']), intval($item['uid']));
                            // who is the last child now?
                            $r = q("SELECT `id` FROM `item` WHERE `parent-uri` = '%s' AND `type` != 'activity' AND `deleted` = 0 AND `uid` = %d\n\t\t\t\t\t\t\t\tORDER BY `created` DESC LIMIT 1", dbesc($item['parent-uri']), intval($importer['importer_uid']));
                            if (count($r)) {
                                q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d", intval($r[0]['id']));
                            }
                        }
                        // if this is a relayed delete, propagate it to other recipients
                        if ($is_a_remote_delete) {
                            proc_run('php', "include/notifier.php", "drop", $item['id']);
                        }
                    }
                }
            }
        }
    }
    foreach ($feed->get_items() as $item) {
        $is_reply = false;
        $item_id = $item->get_id();
        $rawthread = $item->get_item_tags(NAMESPACE_THREAD, 'in-reply-to');
        if (isset($rawthread[0]['attribs']['']['ref'])) {
            $is_reply = true;
            $parent_uri = $rawthread[0]['attribs']['']['ref'];
        }
        if ($is_reply) {
            $community = false;
            if ($importer['page-flags'] == PAGE_COMMUNITY || $importer['page-flags'] == PAGE_PRVGROUP) {
                $sql_extra = '';
                $community = true;
                logger('local_delivery: possible community reply');
            } else {
                $sql_extra = " and contact.self = 1 and item.wall = 1 ";
            }
            // was the top-level post for this reply written by somebody on this site?
            // Specifically, the recipient?
            $is_a_remote_comment = false;
            $top_uri = $parent_uri;
            $r = q("select `item`.`parent-uri` from `item`\n\t\t\t\tWHERE `item`.`uri` = '%s'\n\t\t\t\tLIMIT 1", dbesc($parent_uri));
            if ($r && count($r)) {
                $top_uri = $r[0]['parent-uri'];
                // POSSIBLE CLEANUP --> Why select so many fields when only forum_mode and wall are used?
                $r = q("select `item`.`id`, `item`.`uri`, `item`.`tag`, `item`.`forum_mode`,`item`.`origin`,`item`.`wall`,\n\t\t\t\t\t`contact`.`name`, `contact`.`url`, `contact`.`thumb` from `item`\n\t\t\t\t\tINNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`\n\t\t\t\t\tWHERE `item`.`uri` = '%s' AND (`item`.`parent-uri` = '%s' or `item`.`thr-parent` = '%s')\n\t\t\t\t\tAND `item`.`uid` = %d\n\t\t\t\t\t{$sql_extra}\n\t\t\t\t\tLIMIT 1", dbesc($top_uri), dbesc($top_uri), dbesc($top_uri), intval($importer['importer_uid']));
                if ($r && count($r)) {
                    $is_a_remote_comment = true;
                }
            }
            // Does this have the characteristics of a community or private group comment?
            // If it's a reply to a wall post on a community/prvgroup page it's a
            // valid community comment. Also forum_mode makes it valid for sure.
            // If neither, it's not.
            if ($is_a_remote_comment && $community) {
                if (!$r[0]['forum_mode'] && !$r[0]['wall']) {
                    $is_a_remote_comment = false;
                    logger('local_delivery: not a community reply');
                }
            }
            if ($is_a_remote_comment) {
                logger('local_delivery: received remote comment');
                $is_like = false;
                // remote reply to our post. Import and then notify everybody else.
                $datarray = get_atom_elements($feed, $item);
                $r = q("SELECT `id`, `uid`, `last-child`, `edited`, `body`  FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['importer_uid']));
                // Update content if 'updated' changes
                if (count($r)) {
                    $iid = $r[0]['id'];
                    if (edited_timestamp_is_newer($r[0], $datarray)) {
                        // do not accept (ignore) an earlier edit than one we currently have.
                        if (datetime_convert('UTC', 'UTC', $datarray['edited']) < $r[0]['edited']) {
                            continue;
                        }
                        logger('received updated comment', LOGGER_DEBUG);
                        $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['tag']), dbesc(datetime_convert('UTC', 'UTC', $datarray['edited'])), dbesc(datetime_convert()), dbesc($item_id), intval($importer['importer_uid']));
                        create_tags_from_itemuri($item_id, $importer['importer_uid']);
                        proc_run('php', "include/notifier.php", "comment-import", $iid);
                    }
                    continue;
                }
                $own = q("select name,url,thumb from contact where uid = %d and self = 1 limit 1", intval($importer['importer_uid']));
                $datarray['type'] = 'remote-comment';
                $datarray['wall'] = 1;
                $datarray['parent-uri'] = $parent_uri;
                $datarray['uid'] = $importer['importer_uid'];
                $datarray['owner-name'] = $own[0]['name'];
                $datarray['owner-link'] = $own[0]['url'];
                $datarray['owner-avatar'] = $own[0]['thumb'];
                $datarray['contact-id'] = $importer['id'];
                if ($datarray['verb'] === ACTIVITY_LIKE || $datarray['verb'] === ACTIVITY_DISLIKE || $datarray['verb'] === ACTIVITY_ATTEND || $datarray['verb'] === ACTIVITY_ATTENDNO || $datarray['verb'] === ACTIVITY_ATTENDMAYBE) {
                    $is_like = true;
                    $datarray['type'] = 'activity';
                    $datarray['gravity'] = GRAVITY_LIKE;
                    $datarray['last-child'] = 0;
                    // only one like or dislike per person
                    // splitted into two queries for performance issues
                    $r = q("select id from item where uid = %d and `contact-id` = %d and verb = '%s' and (`parent-uri` = '%s') and deleted = 0 limit 1", intval($datarray['uid']), intval($datarray['contact-id']), dbesc($datarray['verb']), dbesc($datarray['parent-uri']));
                    if ($r && count($r)) {
                        continue;
                    }
                    $r = q("select id from item where uid = %d and `contact-id` = %d and verb = '%s' and (`thr-parent` = '%s') and deleted = 0 limit 1", intval($datarray['uid']), intval($datarray['contact-id']), dbesc($datarray['verb']), dbesc($datarray['parent-uri']));
                    if ($r && count($r)) {
                        continue;
                    }
                }
                if ($datarray['verb'] === ACTIVITY_TAG && $datarray['object-type'] === ACTIVITY_OBJ_TAGTERM) {
                    $xo = parse_xml_string($datarray['object'], false);
                    $xt = parse_xml_string($datarray['target'], false);
                    if ($xt->type == ACTIVITY_OBJ_NOTE && $xt->id) {
                        // fetch the parent item
                        $tagp = q("select * from item where uri = '%s' and uid = %d limit 1", dbesc($xt->id), intval($importer['importer_uid']));
                        if (!count($tagp)) {
                            continue;
                        }
                        // extract tag, if not duplicate, and this user allows tags, add to parent item
                        if ($xo->id && $xo->content) {
                            $newtag = '#[url=' . $xo->id . ']' . $xo->content . '[/url]';
                            if (!stristr($tagp[0]['tag'], $newtag)) {
                                $i = q("SELECT `blocktags` FROM `user` where `uid` = %d LIMIT 1", intval($importer['importer_uid']));
                                if (count($i) && !intval($i[0]['blocktags'])) {
                                    q("UPDATE item SET tag = '%s', `edited` = '%s', `changed` = '%s' WHERE id = %d", dbesc($tagp[0]['tag'] . (strlen($tagp[0]['tag']) ? ',' : '') . $newtag), intval($tagp[0]['id']), dbesc(datetime_convert()), dbesc(datetime_convert()));
                                    create_tags_from_item($tagp[0]['id']);
                                }
                            }
                        }
                    }
                }
                $posted_id = item_store($datarray);
                $parent = 0;
                if ($posted_id) {
                    $datarray["id"] = $posted_id;
                    $r = q("SELECT `parent`, `parent-uri` FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($posted_id), intval($importer['importer_uid']));
                    if (count($r)) {
                        $parent = $r[0]['parent'];
                        $parent_uri = $r[0]['parent-uri'];
                    }
                    if (!$is_like) {
                        $r1 = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `uid` = %d AND `parent` = %d", dbesc(datetime_convert()), intval($importer['importer_uid']), intval($r[0]['parent']));
                        $r2 = q("UPDATE `item` SET `last-child` = 1, `changed` = '%s' WHERE `uid` = %d AND `id` = %d", dbesc(datetime_convert()), intval($importer['importer_uid']), intval($posted_id));
                    }
                    if ($posted_id && $parent) {
                        proc_run('php', "include/notifier.php", "comment-import", "{$posted_id}");
                        if (!$is_like && !$importer['self']) {
                            require_once 'include/enotify.php';
                            notification(array('type' => NOTIFY_COMMENT, 'notify_flags' => $importer['notify-flags'], 'language' => $importer['language'], 'to_name' => $importer['username'], 'to_email' => $importer['email'], 'uid' => $importer['importer_uid'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . urlencode(get_item_guid($posted_id)), 'source_name' => stripslashes($datarray['author-name']), 'source_link' => $datarray['author-link'], 'source_photo' => link_compare($datarray['author-link'], $importer['url']) ? $importer['thumb'] : $datarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item', 'parent' => $parent, 'parent_uri' => $parent_uri));
                        }
                    }
                    return 0;
                    // NOTREACHED
                }
            } else {
                // regular comment that is part of this total conversation. Have we seen it? If not, import it.
                $item_id = $item->get_id();
                $datarray = get_atom_elements($feed, $item);
                if ($importer['rel'] == CONTACT_IS_FOLLOWER) {
                    continue;
                }
                $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['importer_uid']));
                // Update content if 'updated' changes
                if (count($r)) {
                    if (edited_timestamp_is_newer($r[0], $datarray)) {
                        // do not accept (ignore) an earlier edit than one we currently have.
                        if (datetime_convert('UTC', 'UTC', $datarray['edited']) < $r[0]['edited']) {
                            continue;
                        }
                        $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['tag']), dbesc(datetime_convert('UTC', 'UTC', $datarray['edited'])), dbesc(datetime_convert()), dbesc($item_id), intval($importer['importer_uid']));
                        create_tags_from_itemuri($item_id, $importer['importer_uid']);
                    }
                    // update last-child if it changes
                    $allow = $item->get_item_tags(NAMESPACE_DFRN, 'comment-allow');
                    if ($allow && $allow[0]['data'] != $r[0]['last-child']) {
                        $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", dbesc(datetime_convert()), dbesc($parent_uri), intval($importer['importer_uid']));
                        $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s'  WHERE `uri` = '%s' AND `uid` = %d", intval($allow[0]['data']), dbesc(datetime_convert()), dbesc($item_id), intval($importer['importer_uid']));
                    }
                    continue;
                }
                $datarray['parent-uri'] = $parent_uri;
                $datarray['uid'] = $importer['importer_uid'];
                $datarray['contact-id'] = $importer['id'];
                if ($datarray['verb'] === ACTIVITY_LIKE || $datarray['verb'] === ACTIVITY_DISLIKE || $datarray['verb'] === ACTIVITY_ATTEND || $datarray['verb'] === ACTIVITY_ATTENDNO || $datarray['verb'] === ACTIVITY_ATTENDMAYBE) {
                    $datarray['type'] = 'activity';
                    $datarray['gravity'] = GRAVITY_LIKE;
                    // only one like or dislike per person
                    // splitted into two queries for performance issues
                    $r = q("select id from item where uid = %d and `contact-id` = %d and verb ='%s' and deleted = 0 and (`parent-uri` = '%s') limit 1", intval($datarray['uid']), intval($datarray['contact-id']), dbesc($datarray['verb']), dbesc($parent_uri));
                    if ($r && count($r)) {
                        continue;
                    }
                    $r = q("select id from item where uid = %d and `contact-id` = %d and verb ='%s' and deleted = 0 and (`thr-parent` = '%s') limit 1", intval($datarray['uid']), intval($datarray['contact-id']), dbesc($datarray['verb']), dbesc($parent_uri));
                    if ($r && count($r)) {
                        continue;
                    }
                }
                if ($datarray['verb'] === ACTIVITY_TAG && $datarray['object-type'] === ACTIVITY_OBJ_TAGTERM) {
                    $xo = parse_xml_string($datarray['object'], false);
                    $xt = parse_xml_string($datarray['target'], false);
                    if ($xt->type == ACTIVITY_OBJ_NOTE) {
                        $r = q("select * from item where `uri` = '%s' AND `uid` = %d limit 1", dbesc($xt->id), intval($importer['importer_uid']));
                        if (!count($r)) {
                            continue;
                        }
                        // extract tag, if not duplicate, add to parent item
                        if ($xo->content) {
                            if (!stristr($r[0]['tag'], trim($xo->content))) {
                                q("UPDATE item SET tag = '%s' WHERE id = %d", dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . '#[url=' . $xo->id . ']' . $xo->content . '[/url]'), intval($r[0]['id']));
                                create_tags_from_item($r[0]['id']);
                            }
                        }
                    }
                }
                $posted_id = item_store($datarray);
                // find out if our user is involved in this conversation and wants to be notified.
                if (!x($datarray['type']) || $datarray['type'] != 'activity') {
                    $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 AND `deleted` = 0", dbesc($top_uri), intval($importer['importer_uid']));
                    if (count($myconv)) {
                        $importer_url = $a->get_baseurl() . '/profile/' . $importer['nickname'];
                        // first make sure this isn't our own post coming back to us from a wall-to-wall event
                        if (!link_compare($datarray['author-link'], $importer_url)) {
                            foreach ($myconv as $conv) {
                                // now if we find a match, it means we're in this conversation
                                if (!link_compare($conv['author-link'], $importer_url)) {
                                    continue;
                                }
                                require_once 'include/enotify.php';
                                $conv_parent = $conv['parent'];
                                notification(array('type' => NOTIFY_COMMENT, 'notify_flags' => $importer['notify-flags'], 'language' => $importer['language'], 'to_name' => $importer['username'], 'to_email' => $importer['email'], 'uid' => $importer['importer_uid'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . urlencode(get_item_guid($posted_id)), 'source_name' => stripslashes($datarray['author-name']), 'source_link' => $datarray['author-link'], 'source_photo' => link_compare($datarray['author-link'], $importer['url']) ? $importer['thumb'] : $datarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item', 'parent' => $conv_parent, 'parent_uri' => $parent_uri));
                                // only send one notification
                                break;
                            }
                        }
                    }
                }
                continue;
            }
        } else {
            // Head post of a conversation. Have we seen it? If not, import it.
            $item_id = $item->get_id();
            $datarray = get_atom_elements($feed, $item);
            if (x($datarray, 'object-type') && $datarray['object-type'] === ACTIVITY_OBJ_EVENT) {
                $ev = bbtoevent($datarray['body']);
                if ((x($ev, 'desc') || x($ev, 'summary')) && x($ev, 'start')) {
                    $ev['cid'] = $importer['id'];
                    $ev['uid'] = $importer['uid'];
                    $ev['uri'] = $item_id;
                    $ev['edited'] = $datarray['edited'];
                    $ev['private'] = $datarray['private'];
                    $ev['guid'] = $datarray['guid'];
                    $r = q("SELECT * FROM `event` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['uid']));
                    if (count($r)) {
                        $ev['id'] = $r[0]['id'];
                    }
                    $xyz = event_store($ev);
                    continue;
                }
            }
            $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['importer_uid']));
            // Update content if 'updated' changes
            if (count($r)) {
                if (edited_timestamp_is_newer($r[0], $datarray)) {
                    // do not accept (ignore) an earlier edit than one we currently have.
                    if (datetime_convert('UTC', 'UTC', $datarray['edited']) < $r[0]['edited']) {
                        continue;
                    }
                    $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['tag']), dbesc(datetime_convert('UTC', 'UTC', $datarray['edited'])), dbesc(datetime_convert()), dbesc($item_id), intval($importer['importer_uid']));
                    create_tags_from_itemuri($item_id, $importer['importer_uid']);
                    update_thread_uri($item_id, $importer['importer_uid']);
                }
                // update last-child if it changes
                $allow = $item->get_item_tags(NAMESPACE_DFRN, 'comment-allow');
                if ($allow && $allow[0]['data'] != $r[0]['last-child']) {
                    $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", intval($allow[0]['data']), dbesc(datetime_convert()), dbesc($item_id), intval($importer['importer_uid']));
                }
                continue;
            }
            $datarray['parent-uri'] = $item_id;
            $datarray['uid'] = $importer['importer_uid'];
            $datarray['contact-id'] = $importer['id'];
            if (!link_compare($datarray['owner-link'], $importer['url'])) {
                // The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery,
                // but otherwise there's a possible data mixup on the sender's system.
                // the tgroup delivery code called from item_store will correct it if it's a forum,
                // but we're going to unconditionally correct it here so that the post will always be owned by our contact.
                logger('local_delivery: Correcting item owner.', LOGGER_DEBUG);
                $datarray['owner-name'] = $importer['senderName'];
                $datarray['owner-link'] = $importer['url'];
                $datarray['owner-avatar'] = $importer['thumb'];
            }
            if ($importer['rel'] == CONTACT_IS_FOLLOWER && !tgroup_check($importer['importer_uid'], $datarray)) {
                continue;
            }
            // This is my contact on another system, but it's really me.
            // Turn this into a wall post.
            $notify = item_is_remote_self($importer, $datarray);
            $posted_id = item_store($datarray, false, $notify);
            if (stristr($datarray['verb'], ACTIVITY_POKE)) {
                $verb = urldecode(substr($datarray['verb'], strpos($datarray['verb'], '#') + 1));
                if (!$verb) {
                    continue;
                }
                $xo = parse_xml_string($datarray['object'], false);
                if ($xo->type == ACTIVITY_OBJ_PERSON && $xo->id) {
                    // somebody was poked/prodded. Was it me?
                    $links = parse_xml_string("<links>" . unxmlify($xo->link) . "</links>", false);
                    foreach ($links->link as $l) {
                        $atts = $l->attributes();
                        switch ($atts['rel']) {
                            case "alternate":
                                $Blink = $atts['href'];
                                break;
                            default:
                                break;
                        }
                    }
                    if ($Blink && link_compare($Blink, $a->get_baseurl() . '/profile/' . $importer['nickname'])) {
                        // send a notification
                        require_once 'include/enotify.php';
                        notification(array('type' => NOTIFY_POKE, 'notify_flags' => $importer['notify-flags'], 'language' => $importer['language'], 'to_name' => $importer['username'], 'to_email' => $importer['email'], 'uid' => $importer['importer_uid'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . urlencode(get_item_guid($posted_id)), 'source_name' => stripslashes($datarray['author-name']), 'source_link' => $datarray['author-link'], 'source_photo' => link_compare($datarray['author-link'], $importer['url']) ? $importer['thumb'] : $datarray['author-avatar'], 'verb' => $datarray['verb'], 'otype' => 'person', 'activity' => $verb, 'parent' => $datarray['parent']));
                    }
                }
            }
            continue;
        }
    }
    return 0;
    // NOTREACHED
}