Beispiel #1
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));
         }
     }
 }
Beispiel #2
0
/**
 * @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;
}
 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();
 }
Beispiel #4
0
 function post()
 {
     // 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/channel.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']);
     $nocomment = intval($_REQUEST['nocomment']);
     // '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 iconfig 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(date_default_timezone_get(), '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 = $this->item_check_service_class($uid, $_REQUEST['webpage'] == ITEM_TYPE_WEBPAGE ? true : false);
         if (!$ret['success']) {
             notice(t($ret['message']) . EOL);
             if (x($_REQUEST, 'return')) {
                 goaway(z_root() . "/" . $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(z_root() . "/" . $return_path);
             }
             killme();
         }
         // can_comment_on_post() needs info from the following xchan_query
         // This may be from the discover tab which means we need to correct the effective uid
         xchan_query($r, true, $r[0]['uid'] == local_channel() ? 0 : local_channel());
         $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 = \App::get_observer();
     }
     if ($parent) {
         logger('mod_item: item_post parent=' . $parent);
         $can_comment = false;
         if (array_key_exists('owner', $parent_item) && intval($parent_item['owner']['abook_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(z_root() . "/" . $return_path);
             }
             killme();
         }
     } else {
         if (!perm_is_allowed($profile_uid, $observer['xchan_hash'], $webpage ? 'write_pages' : 'post_wall')) {
             notice(t('Permission denied.') . EOL);
             if (x($_REQUEST, 'return')) {
                 goaway(z_root() . "/" . $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 iconfig where cat = 'system' and k = '%s' and v = '%s' limit 1", dbesc($namespace), dbesc($remote_id));
         if ($i) {
             $post_id = $i[0]['iid'];
         }
     }
     $iconfig = null;
     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];
         $iconfig = q("select * from iconfig where iid = %d", intval($post_id));
     }
     if (!$channel) {
         if ($uid && $uid == $profile_uid) {
             $channel = \App::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(z_root() . "/" . $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(z_root() . "/" . $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_wall'] && $parent_item['item_origin'])) {
                 $walltowall_comment = true;
                 $walltowall = true;
             }
             if (!$parent) {
                 $walltowall = true;
             }
         }
     }
     $acl = new \Zotlabs\Access\AccessList($channel);
     $view_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'], 'view_stream');
     $comment_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'], 'post_comments');
     $public_policy = x($_REQUEST, 'public_policy') ? escape_tags($_REQUEST['public_policy']) : map_scope($view_policy, 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) {
             $acl->set_from_array($_REQUEST);
         } else {
             $acl->set($orig_post);
             $public_policy = $orig_post['public_policy'];
             $private = $orig_post['item_private'];
         }
         if ($private || $public_policy || $acl->is_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'];
         $item_origin = $orig_post['item_origin'];
         $item_unseen = $orig_post['item_unseen'];
         $item_starred = $orig_post['item_starred'];
         $item_uplink = $orig_post['item_uplink'];
         $item_consensus = $orig_post['item_consensus'];
         $item_wall = $orig_post['item_wall'];
         $item_thread_top = $orig_post['item_thread_top'];
         $item_notshown = $orig_post['item_notshown'];
         $item_nsfw = $orig_post['item_nsfw'];
         $item_relay = $orig_post['item_relay'];
         $item_mentionsme = $orig_post['item_mentionsme'];
         $item_nocomment = $orig_post['item_nocomment'];
         $item_obscured = $orig_post['item_obscured'];
         $item_verified = $orig_post['item_verified'];
         $item_retained = $orig_post['item_retained'];
         $item_rss = $orig_post['item_rss'];
         $item_deleted = $orig_post['item_deleted'];
         $item_type = $orig_post['item_type'];
         $item_hidden = $orig_post['item_hidden'];
         $item_unpublished = $orig_post['item_unpublished'];
         $item_delayed = $orig_post['item_delayed'];
         $item_pending_remove = $orig_post['item_pending_remove'];
         $item_blocked = $orig_post['item_blocked'];
         $postopts = $orig_post['postopts'];
         $created = $orig_post['created'];
         $mid = $orig_post['mid'];
         $parent_mid = $orig_post['parent_mid'];
         $plink = $orig_post['plink'];
     } else {
         if (!$walltowall) {
             if (array_key_exists('contact_allow', $_REQUEST) || array_key_exists('group_allow', $_REQUEST) || array_key_exists('contact_deny', $_REQUEST) || array_key_exists('group_deny', $_REQUEST)) {
                 $acl->set_from_array($_REQUEST);
             } elseif (!$api_source) {
                 // if no ACL has been defined and we aren't using the API, the form
                 // didn't send us any parameters. This means there's no ACL or it has
                 // been reset to the default audience.
                 // If $api_source is set and there are no ACL parameters, we default
                 // to the channel permissions which were set in the ACL contructor.
                 $acl->set(array('allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => ''));
             }
         }
         $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 = intval($acl->is_private() || $public_policy);
         // If this is a comment, set the permissions from the parent.
         if ($parent_item) {
             $private = 0;
             $acl->set($parent_item);
             $private = intval($acl->is_private() || $parent_item['item_private']);
             $public_policy = $parent_item['public_policy'];
             $owner_hash = $parent_item['owner_xchan'];
         }
         if (!strlen($body)) {
             if ($preview) {
                 killme();
             }
             info(t('Empty post discarded.') . EOL);
             if (x($_REQUEST, 'return')) {
                 goaway(z_root() . "/" . $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 !== 'text/bbcode') {
         $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(z_root() . "/" . $return_path);
                 }
                 killme();
             }
         }
     }
     $gacl = $acl->get();
     $str_contact_allow = $gacl['allow_cid'];
     $str_group_allow = $gacl['allow_gid'];
     $str_contact_deny = $gacl['deny_cid'];
     $str_group_deny = $gacl['deny_gid'];
     if ($mimetype === 'text/bbcode') {
         require_once 'include/text.php';
         // Markdown doesn't work correctly. Do not re-enable unless you're willing to fix it and support it.
         // Sample that will probably give you grief - you must preserve the linebreaks
         // and provide the correct markdown interpretation and you cannot allow unfiltered HTML
         // Markdown
         // ========
         //
         // **bold** abcde
         // fghijkl
         // *italic*
         // <img src="javascript:alert('hacked');" />
         //		if($uid && $uid == $profile_uid && feature_enabled($uid,'markdown')) {
         //			require_once('include/bb2diaspora.php');
         //			$body = escape_tags(trim($body));
         //			$body = str_replace("\n",'<br />', $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, abconfig.v from abook left join abconfig on abook_xchan = abconfig.xchan and abook_channel = abconfig.chan and cat= 'their_perms' and abconfig.k = 'tag_deliver' and abconfig.v = 1 and abook_xchan = '%s' and abook_channel = %d limit 1", dbesc(str_replace(array('<', '>'), array('', ''), $str_contact_allow)), intval($profile_uid));
             if ($x) {
                 $body .= "\n\n@group+" . $x[0]['abook_id'] . "\n";
             }
         }
         /**
          * fix naked links by passing through a callback to see if this is a hubzilla 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", 'nakedoembed', $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, 'ttype' => $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();
             $i = 0;
             foreach ($match[2] as $mtch) {
                 $attach_link = '';
                 $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' => z_root() . '/attach/' . $r['data']['hash'], 'length' => $r['data']['filesize'], 'type' => $r['data']['filetype'], 'title' => urlencode($r['data']['filename']), 'revision' => $r['data']['revision']);
                 }
                 $ext = substr($r['data']['filename'], strrpos($r['data']['filename'], '.'));
                 if (strpos($r['data']['filetype'], 'audio/') !== false) {
                     $attach_link = '[audio]' . z_root() . '/attach/' . $r['data']['hash'] . '/' . $r['data']['revision'] . ($ext ? $ext : '') . '[/audio]';
                 } elseif (strpos($r['data']['filetype'], 'video/') !== false) {
                     $attach_link = '[video]' . z_root() . '/attach/' . $r['data']['hash'] . '/' . $r['data']['revision'] . ($ext ? $ext : '') . '[/video]';
                 }
                 $body = str_replace($match[1][$i], $attach_link, $body);
                 $i++;
             }
         }
     }
     // BBCODE end alert
     if (strlen($categories)) {
         $cats = explode(',', $categories);
         foreach ($cats as $cat) {
             $post_tags[] = array('uid' => $profile_uid, 'ttype' => TERM_CATEGORY, 'otype' => TERM_OBJ_POST, 'term' => trim($cat), 'url' => $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat)));
         }
     }
     if ($orig_post) {
         // preserve original tags
         $t = q("select * from term where oid = %d and otype = %d and uid = %d and ttype in ( %d, %d, %d )", intval($orig_post['id']), intval(TERM_OBJ_POST), intval($profile_uid), intval(TERM_UNKNOWN), intval(TERM_FILE), intval(TERM_COMMUNITYTAG));
         if ($t) {
             foreach ($t as $t1) {
                 $post_tags[] = array('uid' => $profile_uid, 'ttype' => $t1['type'], 'otype' => TERM_OBJ_POST, 'term' => $t1['term'], 'url' => $t1['url']);
             }
         }
     }
     $item_unseen = local_channel() != $profile_uid ? 1 : 0;
     $item_wall = $post_type === 'wall' || $post_type === 'wall-comment' ? 1 : 0;
     $item_origin = $origin ? 1 : 0;
     $item_consensus = $consensus ? 1 : 0;
     $item_nocomment = $nocomment ? 1 : 0;
     // determine if this is a wall post
     if ($parent) {
         $item_wall = $parent_item['item_wall'];
     } else {
         if (!$webpage) {
             $item_wall = 1;
         }
     }
     if ($moderated) {
         $item_blocked = ITEM_MODERATED;
     }
     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();
     $item_thread_top = !$parent ? 1 : 0;
     if (!$plink && $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['attach'] = $attachments;
     $datarray['thr_parent'] = $thr_parent;
     $datarray['postopts'] = $postopts;
     $datarray['item_unseen'] = intval($item_unseen);
     $datarray['item_wall'] = intval($item_wall);
     $datarray['item_origin'] = intval($item_origin);
     $datarray['item_type'] = $webpage;
     $datarray['item_private'] = intval($private);
     $datarray['item_thread_top'] = intval($item_thread_top);
     $datarray['item_unseen'] = intval($item_unseen);
     $datarray['item_starred'] = intval($item_starred);
     $datarray['item_uplink'] = intval($item_uplink);
     $datarray['item_consensus'] = intval($item_consensus);
     $datarray['item_notshown'] = intval($item_notshown);
     $datarray['item_nsfw'] = intval($item_nsfw);
     $datarray['item_relay'] = intval($item_relay);
     $datarray['item_mentionsme'] = intval($item_mentionsme);
     $datarray['item_nocomment'] = intval($item_nocomment);
     $datarray['item_obscured'] = intval($item_obscured);
     $datarray['item_verified'] = intval($item_verified);
     $datarray['item_retained'] = intval($item_retained);
     $datarray['item_rss'] = intval($item_rss);
     $datarray['item_deleted'] = intval($item_deleted);
     $datarray['item_hidden'] = intval($item_hidden);
     $datarray['item_unpublished'] = intval($item_unpublished);
     $datarray['item_delayed'] = intval($item_delayed);
     $datarray['item_pending_remove'] = intval($item_pending_remove);
     $datarray['item_blocked'] = intval($item_blocked);
     $datarray['layout_mid'] = $layout_mid;
     $datarray['public_policy'] = $public_policy;
     $datarray['comment_policy'] = map_scope($comment_policy);
     $datarray['term'] = $post_tags;
     $datarray['plink'] = $plink;
     $datarray['route'] = $route;
     if ($iconfig) {
         $datarray['iconfig'] = $iconfig;
     }
     // 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;
     }
     // suppress duplicates, *unless* you're editing an existing post. This could get picked up
     // as a duplicate if you're editing it very soon after posting it initially and you edited
     // some attribute besides the content, such as title or categories.
     if (feature_enabled($profile_uid, 'suppress_duplicates') && !$orig_post) {
         $z = q("select created from item where uid = %d and created > %s - INTERVAL %s and body = '%s' limit 1", intval($profile_uid), db_utcnow(), db_quoteinterval('2 MINUTE'), dbesc($body));
         if ($z) {
             $datarray['cancel'] = 1;
             notice(t('Duplicate post suppressed.') . EOL);
             logger('Duplicate post. Faking plugin cancel.');
         }
     }
     call_hooks('post_local', $datarray);
     if (x($datarray, 'cancel')) {
         logger('mod_item: post cancelled by plugin or duplicate suppressed.');
         if ($return_path) {
             goaway(z_root() . "/" . $return_path);
         }
         $json = array('cancel' => 1);
         $json['reload'] = z_root() . '/' . $_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_verified'] = 1;
             }
         }
     }
     if ($webpage) {
         Zlib\IConfig::Set($datarray, 'system', webpage_to_namespace($webpage), $pagetitle ? $pagetitle : substr($datarray['mid'], 0, 16), true);
     } elseif ($namespace) {
         Zlib\IConfig::Set($datarray, 'system', $namespace, $remote_id ? $remote_id : substr($datarray['mid'], 0, 16), true);
     }
     if ($orig_post) {
         $datarray['id'] = $post_id;
         $x = item_store_update($datarray, $execflag);
         if (!$parent) {
             $r = q("select * from item where id = %d", intval($post_id));
             if ($r) {
                 xchan_query($r);
                 $sync_item = fetch_post_tags($r);
                 build_sync_packet($profile_uid, array('item' => array(encode_item($sync_item[0], true))));
             }
         }
         if (!$nopush) {
             \Zotlabs\Daemon\Master::Summon(array('Notifier', 'edit_post', $post_id));
         }
         if (x($_REQUEST, 'return') && strlen($return_path)) {
             logger('return: ' . $return_path);
             goaway(z_root() . "/" . $return_path);
         }
         killme();
     } else {
         $post_id = 0;
     }
     $post = item_store($datarray, $execflag);
     $post_id = $post['item_id'];
     $datarray = $post['item'];
     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'] && intval($parent_item['item_wall'])) {
                 Zlib\Enotify::submit(array('type' => NOTIFY_COMMENT, 'from_xchan' => $datarray['author_xchan'], 'to_xchan' => $datarray['owner_xchan'], 'item' => $datarray, 'link' => z_root() . '/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'] && $datarray['item_type'] == ITEM_TYPE_POST) {
                 Zlib\Enotify::submit(array('type' => NOTIFY_WALL, 'from_xchan' => $datarray['author_xchan'], 'to_xchan' => $datarray['owner_xchan'], 'item' => $datarray, 'link' => z_root() . '/display/' . $datarray['mid'], 'verb' => ACTIVITY_POST, 'otype' => 'item'));
             }
             if ($uid && $uid == $profile_uid && is_item_normal($datarray)) {
                 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 (intval($parent_item['item_hidden'])) {
             $r = q("UPDATE item SET item_hidden = 0 WHERE id = %d", 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(z_root() . "/" . $return_path);
         // NOTREACHED
     }
     if ($parent && $parent != $post_id) {
         // 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));
     } else {
         $r = q("select * from item where id = %d", intval($post_id));
         if ($r) {
             xchan_query($r);
             $sync_item = fetch_post_tags($r);
             build_sync_packet($profile_uid, array('item' => array(encode_item($sync_item[0], true))));
         }
     }
     $datarray['id'] = $post_id;
     $datarray['llink'] = z_root() . '/display/' . $channel['channel_address'] . '/' . $post_id;
     call_hooks('post_local_end', $datarray);
     if (!$nopush) {
         \Zotlabs\Daemon\Master::Summon(array('Notifier', $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(z_root() . "/" . $return_path);
     }
     $json = array('success' => 1);
     if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload'])) {
         $json['reload'] = z_root() . '/' . $_REQUEST['jsreload'];
     }
     logger('post_json: ' . print_r($json, true), LOGGER_DEBUG);
     echo json_encode($json);
     killme();
     // NOTREACHED
 }
Beispiel #5
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));
            }
        }
    }
}
Beispiel #6
0
/**
 * @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 (!x($arr, 'item_flags')) {
        if ($is_comment) {
            $arr['item_flags'] = ITEM_ORIGIN;
        } else {
            $arr['item_flags'] = ITEM_ORIGIN | ITEM_WALL | ITEM_THREAD_TOP;
        }
    }
    $channel = get_app()->get_channel();
    $observer = get_app()->get_observer();
    $arr['aid'] = x($arr, 'aid') ? $arr['aid'] : $channel['channel_account_id'];
    $arr['uid'] = x($arr, 'uid') ? $arr['uid'] : $channel['channel_id'];
    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($channel['channel_r_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_flags'] = $arr['item_flags'] | ITEM_VERIFIED;
            }
        }
        logger('Encrypting local storage');
        $key = get_config('system', 'pubkey');
        $arr['item_flags'] = $arr['item_flags'] | ITEM_OBSCURED;
        if ($arr['title']) {
            $arr['title'] = json_encode(crypto_encapsulate($arr['title'], $key));
        }
        if ($arr['body']) {
            $arr['body'] = json_encode(crypto_encapsulate($arr['body'], $key));
        }
    }
    $arr['mid'] = x($arr, 'mid') ? $arr['mid'] : item_message_id();
    $arr['parent_mid'] = x($arr, 'parent_mid') ? $arr['parent_mid'] : $arr['mid'];
    $arr['thr_parent'] = x($arr, 'thr_parent') ? $arr['thr_parent'] : $arr['mid'];
    $arr['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($channel['channel_w_comment']);
    if (!$arr['plink'] && $arr['item_flags'] & 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);
        proc_run('php', 'include/notifier.php', 'activity', $post_id);
        $ret['success'] = true;
        $r = q("select * from item where id = %d limit 1", intval($post_id));
        if ($r) {
            $ret['activity'] = $r[0];
        }
    }
    return $ret;
}
Beispiel #7
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;
}
Beispiel #8
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 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;
}
Beispiel #9
0
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();
    $is_menu = false;
    // a portable menu has its links rewritten with the local baseurl
    $portable_menu = false;
    switch ($j['type']) {
        case 'webpage':
            $arr['item_type'] = ITEM_TYPE_WEBPAGE;
            $namespace = 'WEBPAGE';
            $installed_type = t('webpage');
            break;
        case 'block':
            $arr['item_type'] = ITEM_TYPE_BLOCK;
            $namespace = 'BUILDBLOCK';
            $installed_type = t('block');
            break;
        case 'layout':
            $arr['item_type'] = ITEM_TYPE_PDL;
            $namespace = 'PDL';
            $installed_type = t('layout');
            break;
        case 'portable-menu':
            $portable_menu = true;
            // fall through
        // fall through
        case 'menu':
            $is_menu = true;
            $installed_type = t('menu');
            break;
        default:
            logger('mod_impel: unrecognised element type' . print_r($j, true));
            break;
    }
    if ($is_menu) {
        $m = array();
        $m['menu_channel_id'] = local_channel();
        $m['menu_name'] = $j['pagetitle'];
        $m['menu_desc'] = $j['desc'];
        if ($j['created']) {
            $m['menu_created'] = datetime_convert($j['created']);
        }
        if ($j['edited']) {
            $m['menu_edited'] = datetime_convert($j['edited']);
        }
        $m['menu_flags'] = 0;
        if ($j['flags']) {
            if (in_array('bookmark', $j['flags'])) {
                $m['menu_flags'] |= MENU_BOOKMARK;
            }
            if (in_array('system', $j['flags'])) {
                $m['menu_flags'] |= MENU_SYSTEM;
            }
        }
        $menu_id = menu_create($m);
        if ($menu_id) {
            if (is_array($j['items'])) {
                foreach ($j['items'] as $it) {
                    $mitem = array();
                    $mitem['mitem_link'] = str_replace('[baseurl]', z_root(), $it['link']);
                    $mitem['mitem_desc'] = escape_tags($it['desc']);
                    $mitem['mitem_order'] = intval($it['order']);
                    if (is_array($it['flags'])) {
                        $mitem['mitem_flags'] = 0;
                        if (in_array('zid', $it['flags'])) {
                            $mitem['mitem_flags'] |= MENU_ITEM_ZID;
                        }
                        if (in_array('new-window', $it['flags'])) {
                            $mitem['mitem_flags'] |= MENU_ITEM_NEWWIN;
                        }
                        if (in_array('chatroom', $it['flags'])) {
                            $mitem['mitem_flags'] |= MENU_ITEM_CHATROOM;
                        }
                    }
                    menu_add_item($menu_id, local_channel(), $mitem);
                }
                if ($j['edited']) {
                    $x = q("update menu set menu_edited = '%s' where menu_id = %d and menu_channel_id = %d", dbesc(datetime_convert('UTC', 'UTC', $j['edited'])), intval($menu_id), intval(local_channel()));
                }
            }
            $ret['success'] = true;
        }
        $x = $ret;
    } else {
        $arr['uid'] = local_channel();
        $arr['aid'] = $channel['channel_account_id'];
        $arr['title'] = $j['title'];
        $arr['body'] = $j['body'];
        $arr['term'] = $j['term'];
        $arr['layout_mid'] = $j['layout_mid'];
        $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, edited, item_deleted 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 {
            if ($i && intval($i[0]['item_deleted'])) {
                // was partially deleted already, finish it off
                q("delete from item where mid = '%s' and uid = %d", dbesc($arr['mid']), intval(local_channel()));
            }
            $x = item_store($arr, $execflag);
        }
        if ($x['success']) {
            $item_id = $x['item_id'];
            update_remote_id($channel, $item_id, $arr['item_type'], $pagetitle, $namespace, $remote_id, $arr['mid']);
        }
    }
    if ($x['success']) {
        $ret['success'] = true;
        info(sprintf(t('%s element installed'), $installed_type));
    } else {
        notice(sprintf(t('%s element installation failed'), $installed_type));
    }
    //??? should perhaps return ret?
    json_return_and_die(true);
}
Beispiel #10
0
/** @file */
function profile_activity($changed, $value)
{
    $a = get_app();
    if (!local_user() || !is_array($changed) || !count($changed)) {
        return;
    }
    if (!get_pconfig(local_user(), '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_user();
    $arr['aid'] = $self['channel_account_id'];
    $arr['owner_xchan'] = $arr['author_xchan'] = $self['xchan_hash'];
    $arr['item_flags'] = ITEM_WALL | ITEM_ORIGIN | ITEM_THREAD_TOP;
    $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 = linkify($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');
    }
}
Beispiel #11
0
/**
 * @brief Creates a new photo item.
 *
 * @param array $channel
 * @param string $creator_hash
 * @param array $photo
 * @param boolean $visible default false
 * @return int item_id
 */
function photos_create_item($channel, $creator_hash, $photo, $visible = false)
{
    // Create item container
    $item_hidden = $visible ? 0 : 1;
    $mid = item_message_id();
    $arr = array();
    $arr['aid'] = $channel['channel_account_id'];
    $arr['uid'] = $channel['channel_id'];
    $arr['mid'] = $mid;
    $arr['parent_mid'] = $mid;
    $arr['item_wall'] = 1;
    $arr['item_origin'] = 1;
    $arr['item_thread_top'] = 1;
    $arr['item_hidden'] = $item_hidden;
    $arr['resource_type'] = 'photo';
    $arr['resource_id'] = $photo['resource_id'];
    $arr['owner_xchan'] = $channel['channel_hash'];
    $arr['author_xchan'] = $creator_hash;
    $arr['allow_cid'] = $photo['allow_cid'];
    $arr['allow_gid'] = $photo['allow_gid'];
    $arr['deny_cid'] = $photo['deny_cid'];
    $arr['deny_gid'] = $photo['deny_gid'];
    $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid'];
    $arr['body'] = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo['resource_id'] . ']' . '[zmg]' . z_root() . '/photo/' . $photo['resource_id'] . '-' . $photo['imgscale'] . '[/zmg]' . '[/zrl]';
    $result = item_store($arr);
    $item_id = $result['item_id'];
    return $item_id;
}
Beispiel #12
0
function import_webpage_element($element, $channel, $type)
{
    $arr = array();
    // construct information for the webpage element item table record
    switch ($type) {
        //
        //	PAGES
        //
        case 'page':
            $arr['item_type'] = ITEM_TYPE_WEBPAGE;
            $namespace = 'WEBPAGE';
            $name = $element['pagelink'];
            if ($name) {
                require_once 'library/urlify/URLify.php';
                $name = strtolower(\URLify::transliterate($name));
            }
            $arr['title'] = $element['title'];
            $arr['term'] = $element['term'];
            $arr['layout_mid'] = '';
            // by default there is no layout associated with the page
            // If a layout was specified, find it in the database and get its info. If
            // it does not exist, leave layout_mid empty
            if ($element['layout'] !== '') {
                $liid = q("select iid from iconfig where k = 'PDL' and v = '%s' and cat = 'system'", dbesc($element['layout']));
                if ($liid) {
                    $linfo = q("select mid from item where id = %d", intval($liid[0]['iid']));
                    $arr['layout_mid'] = $linfo[0]['mid'];
                }
            }
            break;
            //
            //	LAYOUTS
            //
        //
        //	LAYOUTS
        //
        case 'layout':
            $arr['item_type'] = ITEM_TYPE_PDL;
            $namespace = 'PDL';
            $name = $element['name'];
            $arr['title'] = $element['description'];
            $arr['term'] = $element['term'];
            break;
            //
            //	BLOCKS
            //
        //
        //	BLOCKS
        //
        case 'block':
            $arr['item_type'] = ITEM_TYPE_BLOCK;
            $namespace = 'BUILDBLOCK';
            $name = $element['name'];
            $arr['title'] = $element['title'];
            break;
        default:
            return null;
            // return null if invalid element type
    }
    $arr['uid'] = $channel['channel_id'];
    $arr['aid'] = $channel['channel_account_id'];
    // Check if an item already exists based on the name
    $iid = q("select iid from iconfig where k = '" . $namespace . "' and v = '%s' and cat = 'system'", dbesc($name));
    if ($iid) {
        // If the item does exist, get the item metadata
        $iteminfo = q("select mid,created,edited from item where id = %d", intval($iid[0]['iid']));
        $arr['mid'] = $arr['parent_mid'] = $iteminfo[0]['mid'];
        $arr['created'] = $iteminfo[0]['created'];
        $arr['edited'] = $element['edited'] ? datetime_convert('UTC', 'UTC', $element['edited']) : datetime_convert();
    } else {
        // otherwise, generate the creation times and unique id
        $arr['created'] = $element['created'] ? datetime_convert('UTC', 'UTC', $element['created']) : datetime_convert();
        $arr['edited'] = datetime_convert('UTC', 'UTC', '0000-00-00 00:00:00');
        $arr['mid'] = $arr['parent_mid'] = item_message_id();
    }
    // Import the actual element content
    $arr['body'] = file_get_contents($element['path']);
    // The element owner is the channel importing the elements
    $arr['owner_xchan'] = get_observer_hash();
    // The author is either the owner or whomever was specified
    $arr['author_xchan'] = $element['author_xchan'] ? $element['author_xchan'] : get_observer_hash();
    // Import mimetype if it is a valid mimetype for the element
    $mimetypes = ['text/bbcode', 'text/html', 'text/markdown', 'text/plain', 'application/x-pdl', 'application/x-php'];
    // Blocks and pages can have any mimetype, but layouts must be text/bbcode
    if (in_array($element['mimetype'], $mimetypes) && ($type === 'page' || $type === 'block')) {
        $arr['mimetype'] = $element['mimetype'];
    } else {
        $arr['mimetype'] = 'text/bbcode';
    }
    // 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;
        }
    }
    $z = q("select * from iconfig where v = '%s' and k = '%s' and cat = 'service' limit 1", dbesc($name), dbesc($namespace));
    $i = q("select id, edited, item_deleted from item where mid = '%s' and uid = %d limit 1", dbesc($arr['mid']), intval(local_channel()));
    $remote_id = 0;
    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 {
        if ($i && intval($i[0]['item_deleted'])) {
            // was partially deleted already, finish it off
            q("delete from item where mid = '%s' and uid = %d", dbesc($arr['mid']), intval(local_channel()));
        }
        $x = item_store($arr, $execflag);
    }
    if ($x['success']) {
        $item_id = $x['item_id'];
        update_remote_id($channel, $item_id, $arr['item_type'], $name, $namespace, $remote_id, $arr['mid']);
        $element['import_success'] = 1;
    } else {
        $element['import_success'] = 0;
    }
    return $element;
}
Beispiel #13
0
/**
 * @brief Creates a new photo item.
 *
 * @param array $channel
 * @param string $creator_hash
 * @param array $photo
 * @param boolean $visible default false
 * @return int item_id
 */
function photos_create_item($channel, $creator_hash, $photo, $visible = false)
{
    // Create item container
    $item_flags = ITEM_WALL | ITEM_ORIGIN | ITEM_THREAD_TOP;
    $item_restrict = $visible ? ITEM_VISIBLE : ITEM_HIDDEN;
    $mid = item_message_id();
    $arr = array();
    $arr['aid'] = $channel['channel_account_id'];
    $arr['uid'] = $channel['channel_id'];
    $arr['mid'] = $mid;
    $arr['parent_mid'] = $mid;
    $arr['item_flags'] = $item_flags;
    $arr['item_restrict'] = $item_restrict;
    $arr['resource_type'] = 'photo';
    $arr['resource_id'] = $photo['resource_id'];
    $arr['owner_xchan'] = $channel['channel_hash'];
    $arr['author_xchan'] = $creator_hash;
    $arr['allow_cid'] = $photo['allow_cid'];
    $arr['allow_gid'] = $photo['allow_gid'];
    $arr['deny_cid'] = $photo['deny_cid'];
    $arr['deny_gid'] = $photo['deny_gid'];
    $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid'];
    $arr['body'] = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo['resource_id'] . ']' . '[zmg]' . z_root() . '/photo/' . $photo['resource_id'] . '-' . $photo['scale'] . '[/zmg]' . '[/zrl]';
    $result = item_store($arr);
    $item_id = $result['item_id'];
    return $item_id;
}
Beispiel #14
0
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;
}
Beispiel #15
0
function wiki_create_wiki($channel, $observer_hash, $wiki, $acl)
{
    $wikiinit = wiki_init_wiki($channel, $wiki);
    if (!$wikiinit['path']) {
        notice('Error creating wiki');
        return array('item' => null, 'success' => false);
    }
    $path = $wikiinit['path'];
    // Generate unique resource_id using the same method as item_message_id()
    do {
        $dups = false;
        $resource_id = random_string();
        $r = q("SELECT mid FROM item WHERE resource_id = '%s' AND resource_type = '%s' AND uid = %d LIMIT 1", dbesc($resource_id), dbesc(WIKI_ITEM_RESOURCE_TYPE), intval($channel['channel_id']));
        if (count($r)) {
            $dups = true;
        }
    } while ($dups == true);
    $ac = $acl->get();
    $mid = item_message_id();
    $arr = array();
    // Initialize the array of parameters for the post
    $item_hidden = 0;
    // TODO: Allow form creator to send post to ACL about new game automatically
    $wiki_url = z_root() . '/wiki/' . $channel['channel_address'] . '/' . $wiki['urlName'];
    $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'] = WIKI_ITEM_RESOURCE_TYPE;
    $arr['resource_id'] = $resource_id;
    $arr['owner_xchan'] = $channel['channel_hash'];
    $arr['author_xchan'] = $observer_hash;
    $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid'];
    $arr['llink'] = $arr['plink'];
    $arr['title'] = $wiki['htmlName'];
    // name of new wiki;
    $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'] = 1;
    $arr['item_origin'] = 1;
    $arr['item_thread_top'] = 1;
    $arr['item_private'] = intval($acl->is_private());
    $arr['verb'] = ACTIVITY_CREATE;
    $arr['obj_type'] = ACTIVITY_OBJ_WIKI;
    $arr['body'] = '[table][tr][td][h1]New Wiki[/h1][/td][/tr][tr][td][zrl=' . $wiki_url . ']' . $wiki['htmlName'] . '[/zrl][/td][/tr][/table]';
    // Save the path using iconfig. The file path should not be shared with other hubs
    if (!set_iconfig($arr, 'wiki', 'path', $path, false)) {
        return array('item' => null, 'success' => false);
    }
    // Save the wiki name information using iconfig. This is shareable.
    if (!set_iconfig($arr, 'wiki', 'rawName', $wiki['rawName'], true)) {
        return array('item' => null, 'success' => false);
    }
    if (!set_iconfig($arr, 'wiki', 'htmlName', $wiki['htmlName'], true)) {
        return array('item' => null, 'success' => false);
    }
    if (!set_iconfig($arr, 'wiki', 'urlName', $wiki['urlName'], true)) {
        return array('item' => null, 'success' => false);
    }
    $post = item_store($arr);
    $item_id = $post['item_id'];
    if ($item_id) {
        proc_run('php', "include/notifier.php", "activity", $item_id);
        return array('item' => $arr, 'success' => true);
    } else {
        return array('item' => null, 'success' => false);
    }
}
Beispiel #16
0
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();
}
Beispiel #17
0
/**
 * @brief Create a new move in the game by generating a child item for the game post
 *
 * @param $observer Authenticated observer (remote or local channel) viewing the page
 * @param $newPosFEN New board position in FEN-format
 * @param $g Game post item table record with all the game information
 * @return array Success status and array of new post data
 */
function chess_make_move($observer, $newPosFEN, $g)
{
    $resource_type = 'chess';
    $resource_id = $g['resource_id'];
    $mid = item_message_id();
    $arr = array();
    // Initialize the array of parameters for the post
    $objtype = ACTIVITY_OBJ_CHESSGAME;
    $object = json_encode(array('id' => z_root() . '/chess/game/' . $resource_id, 'position' => $newPosFEN, 'version' => chess_get_version()));
    $item_hidden = 0;
    // TODO: Allow form creator to send post to ACL about new game automatically
    $r = q("select channel_address from channel where channel_id = %d limit 1", intval($g['uid']));
    $channel_address = '';
    if ($r) {
        $channel_address = $r[0]['channel_address'];
    }
    $arr['aid'] = $g['aid'];
    $arr['uid'] = $g['uid'];
    $arr['mid'] = $mid;
    $arr['parent_mid'] = $g['mid'];
    $arr['item_hidden'] = $item_hidden;
    $arr['resource_type'] = $resource_type;
    $arr['resource_id'] = $resource_id;
    // Game ID
    $arr['owner_xchan'] = $g['owner_xchan'];
    // Tracks the owner of the game
    $arr['author_xchan'] = $observer['xchan_hash'];
    // Denotes which player made this move
    // Store info about the type of chess item using the "title" field
    // Other types include 'move' for children items but may in the future include
    // additional types that will determine how the "object" field is interpreted
    $arr['title'] = 'move';
    $arr['item_wall'] = 1;
    $arr['item_origin'] = 1;
    $arr['item_thread_top'] = 0;
    $arr['item_private'] = 1;
    $arr['verb'] = ACTIVITY_POST;
    $arr['obj_type'] = $objtype;
    $arr['obj'] = $object;
    $arr['body'] = 'New position (FEN format): ' . $newPosFEN;
    $post = item_store($arr);
    $item_id = $post['item_id'];
    if ($item_id) {
        Zotlabs\Daemon\Master::Summon(['Notifier', 'activity', $item_id]);
        return array('item' => $arr, 'status' => true);
    } else {
        return array('item' => null, 'status' => false);
    }
}
Beispiel #18
0
/**
 * 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;
}
Beispiel #19
0
function subthread_content(&$a)
{
    if (!local_channel() && !remote_channel()) {
        return;
    }
    $activity = ACTIVITY_FOLLOW;
    $item_id = argc() > 1 ? notags(trim(argv(1))) : 0;
    $r = q("SELECT * FROM `item` WHERE `parent` = '%s' OR `parent_mid` = '%s' and parent = id LIMIT 1", dbesc($item_id), dbesc($item_id));
    if (!$item_id || !$r) {
        logger('subthread: no item ' . $item_id);
        return;
    }
    $item = $r[0];
    $owner_uid = $item['uid'];
    $observer = $a->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 (!($item['item_flags'] & ITEM_THREAD_TOP)) {
        $post_type = 'comment';
    }
    $bodyverb = t('%1$s is following %2$s\'s %3$s');
    $item_flags = ITEM_ORIGIN | ITEM_NOTSHOWN;
    if ($item['item_flags'] & ITEM_WALL) {
        $item_flags |= ITEM_WALL;
    }
    $arr = array();
    $arr['mid'] = $mid;
    $arr['aid'] = $owner_aid;
    $arr['uid'] = $owner_uid;
    $arr['item_flags'] = $item_flags;
    $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'];
    $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]';
    $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();
    $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['mid']}</id>
\t\t<link>{$link}</link>
\t\t<title></title>
\t\t<content>{$body}</content>
\t</object>
EOT;
    $arr = array();
    $arr['mid'] = $mid;
    $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-mid'] = $item['mid'];
    $arr['thr_parent'] = $item['mid'];
    $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 = '[zrl=' . $contact['url'] . ']' . $contact['name'] . '[/zrl]';
    $alink = '[zrl=' . $item['author-link'] . ']' . $item['author-name'] . '[/zrl]';
    $plink = '[zrl=' . $a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . ']' . $post_type . '[/zrl]';
    $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 = item_store($arr);
    $post_id = $post['item_id'];
    if (!$item['visible']) {
        $r = q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d AND `uid` = %d", intval($item['id']), intval($owner_uid));
    }
    $arr['id'] = $post_id;
    call_hooks('post_local_end', $arr);
    killme();
}
Beispiel #20
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
}
Beispiel #21
0
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);
}
Beispiel #22
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']);
    }
}
Beispiel #23
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');
    }
}
Beispiel #24
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;
    }
}
Beispiel #25
0
 function init()
 {
     if (!local_channel()) {
         return;
     }
     $uid = local_channel();
     $channel = \App::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\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 = \App::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]);
     $arr = array();
     $arr['aid'] = get_account_id();
     $arr['uid'] = $uid;
     $arr['mid'] = $mid;
     $arr['parent_mid'] = $parent_mid ? $parent_mid : $mid;
     $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;
     $arr['item_origin'] = 1;
     $arr['item_wall'] = 1;
     $arr['item_unseen'] = 1;
     if (!$parent_mid) {
         $item['item_thread_top'] = 1;
     }
     if (!$arr['plink'] && intval($arr['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) {
         \Zotlabs\Daemon\Master::Summon(array('Notifier', 'activity', $item_id));
     }
     call_hooks('post_local_end', $arr);
     if ($_SESSION['return_url']) {
         goaway(z_root() . '/' . $_SESSION['return_url']);
     }
     return;
 }