Example #1
0
function diaspora2bb($s)
{
    $s = html_entity_decode($s, ENT_COMPAT, 'UTF-8');
    // Remove CR to avoid problems with following code
    $s = str_replace("\r", "", $s);
    $s = str_replace("\n", " \n", $s);
    // The parser cannot handle paragraphs correctly
    $s = str_replace(array("</p>", "<p>", '<p dir="ltr">'), array("<br>", "<br>", "<br>"), $s);
    // Escaping the hash tags
    $s = preg_replace('/\\#([^\\s\\#])/', '&#35;$1', $s);
    $s = Markdown($s);
    $s = preg_replace('/\\@\\{(.+?)\\; (.+?)\\@(.+?)\\}/', '@[url=https://$3/u/$2]$1[/url]', $s);
    $s = str_replace('&#35;', '#', $s);
    $s = html2bbcode($s);
    // protect the recycle symbol from turning into a tag, but without unescaping angles and naked ampersands
    $s = str_replace('&#x2672;', html_entity_decode('&#x2672;', ENT_QUOTES, 'UTF-8'), $s);
    // Convert everything that looks like a link to a link
    $s = preg_replace("/([^\\]\\=]|^)(https?\\:\\/\\/)([a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\$\\!\\+\\,]+)/ism", '$1[url=$2$3]$2$3[/url]', $s);
    //$s = preg_replace("/([^\]\=]|^)(https?\:\/\/)(vimeo|youtu|www\.youtube|soundcloud)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2$3$4]$2$3$4[/url]',$s);
    $s = bb_tag_preg_replace("/\\[url\\=?(.*?)\\]https?:\\/\\/www.youtube.com\\/watch\\?v\\=(.*?)\\[\\/url\\]/ism", '[youtube]$2[/youtube]', 'url', $s);
    $s = bb_tag_preg_replace("/\\[url\\=https?:\\/\\/www.youtube.com\\/watch\\?v\\=(.*?)\\].*?\\[\\/url\\]/ism", '[youtube]$1[/youtube]', 'url', $s);
    $s = bb_tag_preg_replace("/\\[url\\=?(.*?)\\]https?:\\/\\/vimeo.com\\/([0-9]+)(.*?)\\[\\/url\\]/ism", '[vimeo]$2[/vimeo]', 'url', $s);
    $s = bb_tag_preg_replace("/\\[url\\=https?:\\/\\/vimeo.com\\/([0-9]+)\\](.*?)\\[\\/url\\]/ism", '[vimeo]$1[/vimeo]', 'url', $s);
    // remove duplicate adjacent code tags
    $s = preg_replace("/(\\[code\\])+(.*?)(\\[\\/code\\])+/ism", "[code]\$2[/code]", $s);
    // Don't show link to full picture (until it is fixed)
    $s = scale_external_images($s, false);
    return $s;
}
Example #2
0
function diaspora2bb($s)
{
    // for testing purposes: Collect raw markdown articles
    // $file = tempnam("/tmp/friendica/", "markdown");
    // file_put_contents($file, $s);
    $s = html_entity_decode($s, ENT_COMPAT, 'UTF-8');
    // Too many new lines. So deactivated the following line
    // $s = str_replace("\r","\n",$s);
    // Simply remove cr.
    $s = str_replace("\r", "", $s);
    // <br/> is invalid. Replace it with the valid expression
    $s = str_replace("<br/>", "<br />", $s);
    $s = preg_replace('/\\@\\{(.+?)\\; (.+?)\\@(.+?)\\}/', '@[url=https://$3/u/$2]$1[/url]', $s);
    // Escaping the hash tags - doesn't always seem to work
    // $s = preg_replace('/\#([^\s\#])/','\\#$1',$s);
    // This seems to work
    $s = preg_replace('/\\#([^\\s\\#])/', '&#35;$1', $s);
    $s = Markdown($s);
    $s = str_replace('&#35;', '#', $s);
    $s = str_replace("\n", '<br />', $s);
    $s = html2bbcode($s);
    //	$s = str_replace('&#42;','*',$s);
    // Convert everything that looks like a link to a link
    $s = preg_replace("/([^\\]\\=]|^)(https?\\:\\/\\/)([a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\$\\!\\+\\,]+)/ism", '$1[url=$2$3]$2$3[/url]', $s);
    //$s = preg_replace("/([^\]\=]|^)(https?\:\/\/)(vimeo|youtu|www\.youtube|soundcloud)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2$3$4]$2$3$4[/url]',$s);
    $s = preg_replace("/\\[url\\=?(.*?)\\]https?:\\/\\/www.youtube.com\\/watch\\?v\\=(.*?)\\[\\/url\\]/ism", '[youtube]$2[/youtube]', $s);
    $s = preg_replace("/\\[url\\=https?:\\/\\/www.youtube.com\\/watch\\?v\\=(.*?)\\].*?\\[\\/url\\]/ism", '[youtube]$1[/youtube]', $s);
    $s = preg_replace("/\\[url\\=?(.*?)\\]https?:\\/\\/vimeo.com\\/([0-9]+)(.*?)\\[\\/url\\]/ism", '[vimeo]$2[/vimeo]', $s);
    $s = preg_replace("/\\[url\\=https?:\\/\\/vimeo.com\\/([0-9]+)\\](.*?)\\[\\/url\\]/ism", '[vimeo]$1[/vimeo]', $s);
    // remove duplicate adjacent code tags
    $s = preg_replace("/(\\[code\\])+(.*?)(\\[\\/code\\])+/ism", "[code]\$2[/code]", $s);
    // Don't show link to full picture (until it is fixed)
    $s = scale_external_images($s, false);
    return $s;
}
Example #3
0
function diaspora_photo($importer, $xml, $msg, $attempt = 1)
{
    $a = get_app();
    logger('diaspora_photo: init', LOGGER_DEBUG);
    $remote_photo_path = notags(unxmlify($xml->remote_photo_path));
    $remote_photo_name = notags(unxmlify($xml->remote_photo_name));
    $status_message_guid = notags(unxmlify($xml->status_message_guid));
    $guid = notags(unxmlify($xml->guid));
    $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
    $public = notags(unxmlify($xml->public));
    $created_at = notags(unxmlify($xml_created_at));
    logger('diaspora_photo: status_message_guid: ' . $status_message_guid, LOGGER_DEBUG);
    $contact = diaspora_get_contact_by_handle($importer['uid'], $msg['author']);
    if (!$contact) {
        logger('diaspora_photo: contact record not found: ' . $msg['author'] . ' handle: ' . $diaspora_handle);
        return;
    }
    if (!diaspora_post_allow($importer, $contact, false)) {
        logger('diaspora_photo: Ignoring this author.');
        return 202;
    }
    $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1", intval($importer['uid']), dbesc($status_message_guid));
    /*	deactivated by now since it can lead to multiplicated pictures in posts.
    	if(!count($r)) {
    		$result = diaspora_store_by_guid($status_message_guid, $contact['url'], $importer['uid']);
    
    		if (!$result) {
    			$person = find_diaspora_person_by_handle($diaspora_handle);
    			$result = diaspora_store_by_guid($status_message_guid, $person['url'], $importer['uid']);
    		}
    
    		if ($result) {
    			logger("Fetched missing item ".$status_message_guid." - result: ".$result, LOGGER_DEBUG);
    
    			$r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1",
    				intval($importer['uid']),
    				dbesc($status_message_guid)
    			);
    		}
    	}
    */
    if (!count($r)) {
        if ($attempt <= 3) {
            q("INSERT INTO dsprphotoq (uid, msg, attempt) VALUES (%d, '%s', %d)", intval($importer['uid']), dbesc(serialize($msg)), intval($attempt + 1));
        }
        logger('diaspora_photo: attempt = ' . $attempt . '; status message not found: ' . $status_message_guid . ' for photo: ' . $guid);
        return;
    }
    $parent_item = $r[0];
    $link_text = '[img]' . $remote_photo_path . $remote_photo_name . '[/img]' . "\n";
    $link_text = scale_external_images($link_text, true, array($remote_photo_name, 'scaled_full_' . $remote_photo_name));
    if (strpos($parent_item['body'], $link_text) === false) {
        $r = q("UPDATE `item` SET `body` = '%s', `visible` = 1 WHERE `id` = %d AND `uid` = %d", dbesc($link_text . $parent_item['body']), intval($parent_item['id']), intval($parent_item['uid']));
        update_thread($parent_item['id']);
    }
    return;
}
Example #4
0
function diaspora_asphoto($importer, $xml, $msg)
{
    logger('diaspora_asphoto called');
    $a = get_app();
    $guid = notags(unxmlify($xml->guid));
    $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
    if ($diaspora_handle != $msg['author']) {
        logger('diaspora_post: Potential forgery. Message handle is not the same as envelope sender.');
        return 202;
    }
    $contact = diaspora_get_contact_by_handle($importer['channel_id'], $diaspora_handle);
    if (!$contact) {
        return;
    }
    if (!perm_is_allowed($importer['channel_id'], $contact['xchan_hash'], 'send_stream')) {
        logger('diaspora_asphoto: Ignoring this author.');
        return 202;
    }
    $message_id = $diaspora_handle . ':' . $guid;
    $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `guid` = '%s' LIMIT 1", intval($importer['channel_id']), dbesc($message_id), dbesc($guid));
    if (count($r)) {
        logger('diaspora_asphoto: message exists: ' . $guid);
        return;
    }
    // allocate a guid on our system - we aren't fixing any collisions.
    // we're ignoring them
    $g = q("select * from guid where guid = '%s' limit 1", dbesc($guid));
    if (!count($g)) {
        q("insert into guid ( guid ) values ( '%s' )", dbesc($guid));
    }
    $created = unxmlify($xml->created_at);
    $private = unxmlify($xml->public) == 'false' ? 1 : 0;
    if (strlen($xml->objectId) && $xml->objectId != 0 && $xml->image_url) {
        $body = '[url=' . notags(unxmlify($xml->image_url)) . '][img]' . notags(unxmlify($xml->objectId)) . '[/img][/url]' . "\n";
        $body = scale_external_images($body, false);
    } elseif ($xml->image_url) {
        $body = '[img]' . notags(unxmlify($xml->image_url)) . '[/img]' . "\n";
        $body = scale_external_images($body);
    } else {
        logger('diaspora_asphoto: no photo url found.');
        return;
    }
    $plink = 'https://' . substr($diaspora_handle, strpos($diaspora_handle, '@') + 1) . '/posts/' . $guid;
    $datarray = array();
    $datarray['uid'] = $importer['channel_id'];
    $datarray['contact-id'] = $contact['id'];
    $datarray['wall'] = 0;
    $datarray['network'] = NETWORK_DIASPORA;
    $datarray['guid'] = $guid;
    $datarray['uri'] = $datarray['parent-uri'] = $message_id;
    $datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert('UTC', 'UTC', $created);
    $datarray['private'] = $private;
    $datarray['parent'] = 0;
    $datarray['plink'] = $plink;
    $datarray['owner-name'] = $contact['name'];
    $datarray['owner-link'] = $contact['url'];
    //$datarray['owner-avatar'] = $contact['thumb'];
    $datarray['owner-avatar'] = x($contact, 'thumb') ? $contact['thumb'] : $contact['photo'];
    $datarray['author-name'] = $contact['name'];
    $datarray['author-link'] = $contact['url'];
    $datarray['author-avatar'] = $contact['thumb'];
    $datarray['body'] = $body;
    $datarray['app'] = 'Diaspora/Cubbi.es';
    $message_id = item_store($datarray);
    //if($message_id) {
    //	q("update item set plink = '%s' where id = %d",
    //		dbesc($a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id),
    //		intval($message_id)
    //	);
    //}
    return;
}
Example #5
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
}
Example #6
0
function item_post(&$a)
{
    if (!local_user() && !remote_user() && !x($_REQUEST, 'commenter')) {
        return;
    }
    require_once 'include/security.php';
    $uid = local_user();
    if (x($_REQUEST, 'dropitems')) {
        $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('postinput ' . file_get_contents('php://input'));
    logger('postvars ' . print_r($_REQUEST, true), LOGGER_DATA);
    $api_source = x($_REQUEST, 'api_source') && $_REQUEST['api_source'] ? true : false;
    $message_id = x($_REQUEST, 'message_id') && $api_source ? strip_tags($_REQUEST['message_id']) : '';
    $return_path = x($_REQUEST, 'return') ? $_REQUEST['return'] : '';
    $preview = x($_REQUEST, 'preview') ? intval($_REQUEST['preview']) : 0;
    // Check for doubly-submitted posts, and reject duplicates
    // Note that we have to ignore previews, otherwise nothing will post
    // after it's been previewed
    if (!$preview && x($_REQUEST['post_id_random'])) {
        if (x($_SESSION['post-random']) && $_SESSION['post-random'] == $_REQUEST['post_id_random']) {
            logger("item post: duplicate post", LOGGER_DEBUG);
            item_post_return($a->get_baseurl(), $api_source, $return_path);
        } else {
            $_SESSION['post-random'] = $_REQUEST['post_id_random'];
        }
    }
    /**
     * Is this a reply to something?
     */
    $parent = x($_REQUEST, 'parent') ? intval($_REQUEST['parent']) : 0;
    $parent_uri = x($_REQUEST, 'parent_uri') ? trim($_REQUEST['parent_uri']) : '';
    $parent_item = null;
    $parent_contact = null;
    $thr_parent = '';
    $parid = 0;
    $r = false;
    $objecttype = null;
    if ($parent || $parent_uri) {
        $objecttype = ACTIVITY_OBJ_COMMENT;
        if (!x($_REQUEST, 'type')) {
            $_REQUEST['type'] = 'net-comment';
        }
        if ($parent) {
            $r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1", intval($parent));
        } elseif ($parent_uri && local_user()) {
            // This is coming from an API source, and we are logged in
            $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($parent_uri), intval(local_user()));
        }
        // if this isn't the real parent of the conversation, find it
        if ($r !== false && count($r)) {
            $parid = $r[0]['parent'];
            $parent_uri = $r[0]['uri'];
            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();
        }
        $parent_item = $r[0];
        $parent = $r[0]['id'];
        // multi-level threading - preserve the info but re-parent to our single level threading
        //if(($parid) && ($parid != $parent))
        $thr_parent = $parent_uri;
        if ($parent_item['contact-id'] && $uid) {
            $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($parent_item['contact-id']), intval($uid));
            if (count($r)) {
                $parent_contact = $r[0];
                // If the contact id doesn't fit with the contact, then set the contact to null
                $thrparent = q("SELECT `author-link`, `network` FROM `item` WHERE `uri` = '%s' LIMIT 1", dbesc($thr_parent));
                if (count($thrparent) and $thrparent[0]["network"] === NETWORK_OSTATUS and normalise_link($parent_contact["url"]) != normalise_link($thrparent[0]["author-link"])) {
                    $parent_contact = null;
                    require_once "include/Scrape.php";
                    $probed_contact = probe_url($thrparent[0]["author-link"]);
                    if ($probed_contact["network"] != NETWORK_FEED) {
                        $parent_contact = $probed_contact;
                        $parent_contact["nurl"] = normalise_link($probed_contact["url"]);
                        $parent_contact["thumb"] = $probed_contact["photo"];
                        $parent_contact["micro"] = $probed_contact["photo"];
                    }
                    logger('parent contact: ' . print_r($parent_contact, true), LOGGER_DEBUG);
                } else {
                    logger('no contact found: ' . print_r($thrparent, true), LOGGER_DEBUG);
                }
            }
        }
    }
    if ($parent) {
        logger('mod_item: item_post parent=' . $parent);
    }
    $profile_uid = x($_REQUEST, 'profile_uid') ? intval($_REQUEST['profile_uid']) : 0;
    $post_id = x($_REQUEST, 'post_id') ? intval($_REQUEST['post_id']) : 0;
    $app = x($_REQUEST, 'source') ? strip_tags($_REQUEST['source']) : '';
    $extid = x($_REQUEST, 'extid') ? strip_tags($_REQUEST['extid']) : '';
    $allow_moderated = false;
    // here is where we are going to check for permission to post a moderated comment.
    // First check that the parent exists and it is a wall item.
    if (x($_REQUEST, 'commenter') && (!$parent || !$parent_item['wall'])) {
        notice(t('Permission denied.') . EOL);
        if (x($_REQUEST, 'return')) {
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        killme();
    }
    // Now check that it is a page_type of PAGE_BLOG, and that valid personal details
    // have been provided, and run any anti-spam plugins
    // TODO
    if (!can_write_wall($a, $profile_uid) && !$allow_moderated) {
        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 ($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];
    }
    $user = null;
    $r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($profile_uid));
    if (count($r)) {
        $user = $r[0];
    }
    if ($orig_post) {
        $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'];
        $location = $orig_post['location'];
        $coord = $orig_post['coord'];
        $verb = $orig_post['verb'];
        $objecttype = $orig_post['object-type'];
        $emailcc = $orig_post['emailcc'];
        $app = $orig_post['app'];
        $categories = $orig_post['file'];
        $title = notags(trim($_REQUEST['title']));
        $body = escape_tags(trim($_REQUEST['body']));
        $private = $orig_post['private'];
        $pubmail_enable = $orig_post['pubmail'];
        $network = $orig_post['network'];
        $guid = $orig_post['guid'];
        $extid = $orig_post['extid'];
    } 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 = $user['allow_gid'];
            $str_contact_allow = $user['allow_cid'];
            $str_group_deny = $user['deny_gid'];
            $str_contact_deny = $user['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']);
        }
        $title = notags(trim($_REQUEST['title']));
        $location = notags(trim($_REQUEST['location']));
        $coord = notags(trim($_REQUEST['coord']));
        $verb = notags(trim($_REQUEST['verb']));
        $emailcc = notags(trim($_REQUEST['emailcc']));
        $body = escape_tags(trim($_REQUEST['body']));
        $network = notags(trim($_REQUEST['network']));
        $guid = get_guid(32);
        $naked_body = preg_replace('/\\[(.+?)\\]/', '', $body);
        if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
            $l = new Text_LanguageDetect();
            //$lng = $l->detectConfidence($naked_body);
            //$postopts = (($lng['language']) ? 'lang=' . $lng['language'] . ';' . $lng['confidence'] : '');
            $lng = $l->detect($naked_body, 3);
            if (sizeof($lng) > 0) {
                $postopts = "";
                foreach ($lng as $language => $score) {
                    if ($postopts == "") {
                        $postopts = "lang=";
                    } else {
                        $postopts .= ":";
                    }
                    $postopts .= $language . ";" . $score;
                }
            }
            logger('mod_item: detect language' . print_r($lng, true) . $naked_body, LOGGER_DATA);
        } else {
            $postopts = '';
        }
        $private = strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny) ? 1 : 0;
        if ($user['hidewall']) {
            $private = 2;
        }
        // If this is a comment, set the permissions from the parent.
        if ($parent_item) {
            $private = 0;
            // for non native networks use the network of the original post as network of the item
            if ($parent_item['network'] != NETWORK_DIASPORA and $parent_item['network'] != NETWORK_OSTATUS and $network == "") {
                $network = $parent_item['network'];
            }
            if ($parent_item['private'] || strlen($parent_item['allow_cid']) || strlen($parent_item['allow_gid']) || strlen($parent_item['deny_cid']) || strlen($parent_item['deny_gid'])) {
                $private = $parent_item['private'] ? $parent_item['private'] : 1;
            }
            $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'];
        }
        $pubmail_enable = x($_REQUEST, 'pubmail_enable') && intval($_REQUEST['pubmail_enable']) && !$private ? 1 : 0;
        // if using the API, we won't see pubmail_enable - figure out if it should be set
        if ($api_source && $profile_uid && $profile_uid == local_user() && !$private) {
            $mail_disabled = function_exists('imap_open') && !get_config('system', 'imap_disabled') ? 0 : 1;
            if (!$mail_disabled) {
                $r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1", intval(local_user()));
                if (count($r) && intval($r[0]['pubmail'])) {
                    $pubmail_enabled = true;
                }
            }
        }
        if (!strlen($body)) {
            if ($preview) {
                killme();
            }
            info(t('Empty post discarded.') . EOL);
            if (x($_REQUEST, 'return')) {
                goaway($a->get_baseurl() . "/" . $return_path);
            }
            killme();
        }
    }
    if (strlen($categories)) {
        // get the "fileas" tags for this post
        $filedas = file_tag_file_to_list($categories, 'file');
    }
    // save old and new categories, so we can determine what needs to be deleted from pconfig
    $categories_old = $categories;
    $categories = file_tag_list_to_file(trim($_REQUEST['category']), 'category');
    $categories_new = $categories;
    if (strlen($filedas)) {
        // append the fileas stuff to the new categories list
        $categories .= file_tag_list_to_file($filedas, 'file');
    }
    // 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 = (local_user() ? intval(get_pconfig(local_user(),'system','plaintext')) || !feature_enabled($profile_uid,'richtext') : 0);
    	if((! $parent) && (! $api_source) && (! $plaintext)) {
    		$body = fix_mce_lf($body);
    	}*/
    $plaintext = local_user() ? !feature_enabled($profile_uid, 'richtext') : 0;
    if (!$parent && !$api_source && !$plaintext) {
        $body = fix_mce_lf($body);
    }
    // get contact info for poster
    $author = null;
    $self = false;
    $contact_id = 0;
    if (local_user() && local_user() == $profile_uid) {
        $self = true;
        $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", intval($_SESSION['uid']));
    } elseif (remote_user()) {
        if (is_array($_SESSION['remote'])) {
            foreach ($_SESSION['remote'] as $v) {
                if ($v['uid'] == $profile_uid) {
                    $contact_id = $v['cid'];
                    break;
                }
            }
        }
        if ($contact_id) {
            $r = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1", intval($contact_id));
        }
    }
    if (count($r)) {
        $author = $r[0];
        $contact_id = $author['id'];
    }
    // get contact info for owner
    if ($profile_uid == local_user()) {
        $contact_record = $author;
    } else {
        $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", intval($profile_uid));
        if (count($r)) {
            $contact_record = $r[0];
        }
    }
    $post_type = notags(trim($_REQUEST['type']));
    if ($post_type === 'net-comment') {
        if ($parent_item !== null) {
            if ($parent_item['wall'] == 1) {
                $post_type = 'wall-comment';
            } else {
                $post_type = 'remote-comment';
            }
        }
    }
    /**
     *
     * 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 messages that are in the
     * post and set them to the same permissions as the post itself.
     *
     */
    $match = null;
    if (!$preview && preg_match_all("/\\[img([\\=0-9x]*?)\\](.*?)\\[\\/img\\]/", $body, $match)) {
        $images = $match[2];
        if (count($images)) {
            $objecttype = ACTIVITY_OBJ_IMAGE;
            foreach ($images as $image) {
                if (!stristr($image, $a->get_baseurl() . '/photo/')) {
                    continue;
                }
                $image_uri = substr($image, strrpos($image, '/') + 1);
                $image_uri = substr($image_uri, 0, strpos($image_uri, '-'));
                if (!strlen($image_uri)) {
                    continue;
                }
                $srch = '<' . intval($contact_id) . '>';
                $r = q("SELECT `id` FROM `photo` WHERE `allow_cid` = '%s' AND `allow_gid` = '' AND `deny_cid` = '' AND `deny_gid` = ''\n\t\t\t\t\tAND `resource-id` = '%s' AND `uid` = %d LIMIT 1", dbesc($srch), dbesc($image_uri), intval($profile_uid));
                if (!count($r)) {
                    continue;
                }
                $r = q("UPDATE `photo` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s'\n\t\t\t\t\tWHERE `resource-id` = '%s' AND `uid` = %d AND `album` = '%s' ", dbesc($str_contact_allow), dbesc($str_group_allow), dbesc($str_contact_deny), dbesc($str_group_deny), dbesc($image_uri), intval($profile_uid), dbesc(t('Wall Photos')));
            }
        }
    }
    /**
     * Next link in any attachment references we find in the post.
     */
    $match = false;
    if (!$preview && preg_match_all("/\\[attachment\\](.*?)\\[\\/attachment\\]/", $body, $match)) {
        $attaches = $match[1];
        if (count($attaches)) {
            foreach ($attaches as $attach) {
                $r = q("SELECT * FROM `attach` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($attach));
                if (count($r)) {
                    $r = q("UPDATE `attach` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s'\n\t\t\t\t\t\tWHERE `uid` = %d AND `id` = %d", dbesc($str_contact_allow), dbesc($str_group_allow), dbesc($str_contact_deny), dbesc($str_group_deny), intval($profile_uid), intval($attach));
                }
            }
        }
    }
    // embedded bookmark in post? set bookmark flag
    $bookmark = 0;
    if (preg_match_all("/\\[bookmark\\=([^\\]]*)\\](.*?)\\[\\/bookmark\\]/ism", $body, $match, PREG_SET_ORDER)) {
        $objecttype = ACTIVITY_OBJ_BOOKMARK;
        $bookmark = 1;
    }
    $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);
    // Setting the object type if not defined before
    if (!$objecttype) {
        $objecttype = ACTIVITY_OBJ_NOTE;
        // Default value
        require_once "include/plaintext.php";
        $objectdata = get_attached_data($body);
        if ($post["type"] == "link") {
            $objecttype = ACTIVITY_OBJ_BOOKMARK;
        } elseif ($post["type"] == "video") {
            $objecttype = ACTIVITY_OBJ_VIDEO;
        } elseif ($post["type"] == "photo") {
            $objecttype = ACTIVITY_OBJ_IMAGE;
        }
    }
    /**
     * Look for any tags and linkify them
     */
    $str_tags = '';
    $inform = '';
    $tags = get_tags($body);
    /**
     * add a statusnet style reply tag if the original post was from there
     * and we are replying, and there isn't one already
     */
    if ($parent_contact && $parent_contact['network'] === NETWORK_OSTATUS && $parent_contact['nick'] && !in_array('@' . $parent_contact['nick'], $tags)) {
        $body = '@' . $parent_contact['nick'] . ' ' . $body;
        $tags[] = '@' . $parent_contact['nick'];
    }
    $tagged = array();
    $private_forum = false;
    if (count($tags)) {
        foreach ($tags as $tag) {
            if (strpos($tag, '#') === 0) {
                continue;
            }
            // If we already tagged 'Robert Johnson', don't try and tag 'Robert'.
            // Robert Johnson should be first in the $tags array
            $fullnametagged = false;
            for ($x = 0; $x < count($tagged); $x++) {
                if (stristr($tagged[$x], $tag . ' ')) {
                    $fullnametagged = true;
                    break;
                }
            }
            if ($fullnametagged) {
                continue;
            }
            $success = handle_tag($a, $body, $inform, $str_tags, local_user() ? local_user() : $profile_uid, $tag, $network);
            if ($success['replaced']) {
                $tagged[] = $tag;
            }
            if (is_array($success['contact']) && intval($success['contact']['prv'])) {
                $private_forum = true;
                $private_id = $success['contact']['id'];
            }
        }
    }
    if ($private_forum && !$parent && !$private) {
        // we tagged a private forum in a top level post and the message was public.
        // Restrict it.
        $private = 1;
        $str_contact_allow = '<' . $private_id . '>';
    }
    $attachments = '';
    $match = false;
    if (preg_match_all('/(\\[attachment\\]([0-9]+)\\[\\/attachment\\])/', $body, $match)) {
        foreach ($match[2] as $mtch) {
            $r = q("SELECT `id`,`filename`,`filesize`,`filetype` FROM `attach` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($mtch));
            if (count($r)) {
                if (strlen($attachments)) {
                    $attachments .= ',';
                }
                $attachments .= '[attach]href="' . $a->get_baseurl() . '/attach/' . $r[0]['id'] . '" length="' . $r[0]['filesize'] . '" type="' . $r[0]['filetype'] . '" title="' . ($r[0]['filename'] ? $r[0]['filename'] : '') . '"[/attach]';
            }
            $body = str_replace($match[1], '', $body);
        }
    }
    $wall = 0;
    if ($post_type === 'wall' || $post_type === 'wall-comment') {
        $wall = 1;
    }
    if (!strlen($verb)) {
        $verb = ACTIVITY_POST;
    }
    if ($network == "") {
        $network = NETWORK_DFRN;
    }
    $gravity = $parent ? 6 : 0;
    // even if the post arrived via API we are considering that it
    // originated on this site by default for determining relayability.
    $origin = x($_REQUEST, 'origin') ? intval($_REQUEST['origin']) : 1;
    $notify_type = $parent ? 'comment-new' : 'wall-new';
    $uri = $message_id ? $message_id : item_new_uri($a->get_hostname(), $profile_uid);
    // Fallback so that we alway have a thr-parent
    if (!$thr_parent) {
        $thr_parent = $uri;
    }
    $datarray = array();
    $datarray['uid'] = $profile_uid;
    $datarray['type'] = $post_type;
    $datarray['wall'] = $wall;
    $datarray['gravity'] = $gravity;
    $datarray['network'] = $network;
    $datarray['contact-id'] = $contact_id;
    $datarray['owner-name'] = $contact_record['name'];
    $datarray['owner-link'] = $contact_record['url'];
    $datarray['owner-avatar'] = $contact_record['thumb'];
    $datarray['author-name'] = $author['name'];
    $datarray['author-link'] = $author['url'];
    $datarray['author-avatar'] = $author['thumb'];
    $datarray['created'] = datetime_convert();
    $datarray['edited'] = datetime_convert();
    $datarray['commented'] = datetime_convert();
    $datarray['received'] = datetime_convert();
    $datarray['changed'] = datetime_convert();
    $datarray['extid'] = $extid;
    $datarray['guid'] = $guid;
    $datarray['uri'] = $uri;
    $datarray['title'] = $title;
    $datarray['body'] = $body;
    $datarray['app'] = $app;
    $datarray['location'] = $location;
    $datarray['coord'] = $coord;
    $datarray['tag'] = $str_tags;
    $datarray['file'] = $categories;
    $datarray['inform'] = $inform;
    $datarray['verb'] = $verb;
    $datarray['object-type'] = $objecttype;
    $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['private'] = $private;
    $datarray['pubmail'] = $pubmail_enable;
    $datarray['attach'] = $attachments;
    $datarray['bookmark'] = intval($bookmark);
    $datarray['thr-parent'] = $thr_parent;
    $datarray['postopts'] = $postopts;
    $datarray['origin'] = $origin;
    $datarray['moderated'] = $allow_moderated;
    /**
     * These fields are for the convenience of plugins...
     * 'self' if true indicates the owner is posting on their own wall
     * If parent is 0 it is a top-level post.
     */
    $datarray['parent'] = $parent;
    $datarray['self'] = $self;
    //	$datarray['prvnets']       = $user['prvnets'];
    if ($orig_post) {
        $datarray['edit'] = true;
    }
    // Search for hashtags
    item_body_set_hashtags($datarray);
    // preview mode - prepare the body for display and send it via json
    if ($preview) {
        require_once 'include/conversation.php';
        $o = conversation($a, array(array_merge($contact_record, $datarray)), 'search', false, true);
        logger('preview: ' . $o);
        echo json_encode(array('preview' => $o));
        killme();
    }
    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();
    }
    // Fill the cache field
    put_item_in_cache($datarray);
    if ($orig_post) {
        $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `attach` = '%s', `file` = '%s', `rendered-html` = '%s', `rendered-hash` = '%s', `edited` = '%s', `changed` = '%s' WHERE `id` = %d AND `uid` = %d", dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['tag']), dbesc($datarray['attach']), dbesc($datarray['file']), dbesc($datarray['rendered-html']), dbesc($datarray['rendered-hash']), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($post_id), intval($profile_uid));
        create_tags_from_item($post_id);
        create_files_from_item($post_id);
        update_thread($post_id);
        // update filetags in pconfig
        file_tag_update_pconfig($uid, $categories_old, $categories_new, 'category');
        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;
    }
    $r = q("INSERT INTO `item` (`guid`, `extid`, `uid`,`type`,`wall`,`gravity`, `network`, `contact-id`,`owner-name`,`owner-link`,`owner-avatar`, `author-name`, `author-link`, `author-avatar`,\n\t\t`created`, `edited`, `commented`, `received`, `changed`, `uri`, `thr-parent`, `title`, `body`, `app`, `location`, `coord`, `tag`, `inform`, `verb`, `object-type`, `postopts`,\n\t\t`allow_cid`, `allow_gid`, `deny_cid`, `deny_gid`, `private`, `pubmail`, `attach`, `bookmark`,`origin`, `moderated`, `file`, `rendered-html`, `rendered-hash`)\n\t\tVALUES( '%s', '%s', %d, '%s', %d, %d, '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d, '%s', '%s', '%s')", dbesc($datarray['guid']), dbesc($datarray['extid']), intval($datarray['uid']), dbesc($datarray['type']), intval($datarray['wall']), intval($datarray['gravity']), dbesc($datarray['network']), intval($datarray['contact-id']), dbesc($datarray['owner-name']), dbesc($datarray['owner-link']), dbesc($datarray['owner-avatar']), dbesc($datarray['author-name']), dbesc($datarray['author-link']), dbesc($datarray['author-avatar']), dbesc($datarray['created']), dbesc($datarray['edited']), dbesc($datarray['commented']), dbesc($datarray['received']), dbesc($datarray['changed']), dbesc($datarray['uri']), dbesc($datarray['thr-parent']), dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['app']), dbesc($datarray['location']), dbesc($datarray['coord']), dbesc($datarray['tag']), dbesc($datarray['inform']), dbesc($datarray['verb']), dbesc($datarray['object-type']), dbesc($datarray['postopts']), dbesc($datarray['allow_cid']), dbesc($datarray['allow_gid']), dbesc($datarray['deny_cid']), dbesc($datarray['deny_gid']), intval($datarray['private']), intval($datarray['pubmail']), dbesc($datarray['attach']), intval($datarray['bookmark']), intval($datarray['origin']), intval($datarray['moderated']), dbesc($datarray['file']), dbesc($datarray['rendered-html']), dbesc($datarray['rendered-hash']));
    $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' LIMIT 1", dbesc($datarray['uri']));
    if (!count($r)) {
        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
    }
    $post_id = $r[0]['id'];
    logger('mod_item: saved item ' . $post_id);
    $datarray["id"] = $post_id;
    $datarray["plink"] = $a->get_baseurl() . '/display/' . urlencode($datarray["guid"]);
    // update filetags in pconfig
    file_tag_update_pconfig($uid, $categories_old, $categories_new, 'category');
    if ($parent) {
        // This item is the last leaf and gets the comment box, clear any ancestors
        $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent` = %d ", dbesc(datetime_convert()), intval($parent));
        update_thread($parent, true);
        // Inherit ACLs from the parent item.
        $r = q("UPDATE `item` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s', `private` = %d\n\t\t\tWHERE `id` = %d", dbesc($parent_item['allow_cid']), dbesc($parent_item['allow_gid']), dbesc($parent_item['deny_cid']), dbesc($parent_item['deny_gid']), intval($parent_item['private']), intval($post_id));
        if ($contact_record != $author) {
            notification(array('type' => NOTIFY_COMMENT, 'notify_flags' => $user['notify-flags'], 'language' => $user['language'], 'to_name' => $user['username'], 'to_email' => $user['email'], 'uid' => $user['uid'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . urlencode($datarray['guid']), 'source_name' => $datarray['author-name'], 'source_link' => $datarray['author-link'], 'source_photo' => $datarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item', 'parent' => $parent, 'parent_uri' => $parent_item['uri']));
        }
        // Store the comment signature information in case we need to relay to Diaspora
        store_diaspora_comment_sig($datarray, $author, $self ? $a->user['prvkey'] : false, $parent_item, $post_id);
    } else {
        $parent = $post_id;
        if ($contact_record != $author) {
            notification(array('type' => NOTIFY_WALL, 'notify_flags' => $user['notify-flags'], 'language' => $user['language'], 'to_name' => $user['username'], 'to_email' => $user['email'], 'uid' => $user['uid'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . urlencode($datarray['guid']), 'source_name' => $datarray['author-name'], 'source_link' => $datarray['author-link'], 'source_photo' => $datarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item'));
        }
    }
    // fallback so that parent always gets set to non-zero.
    if (!$parent) {
        $parent = $post_id;
    }
    $r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s', `plink` = '%s', `changed` = '%s', `last-child` = 1, `visible` = 1\n\t\tWHERE `id` = %d", intval($parent), dbesc($parent == $post_id ? $uri : $parent_item['uri']), dbesc($a->get_baseurl() . '/display/' . urlencode($datarray['guid'])), dbesc(datetime_convert()), intval($post_id));
    // 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['visible']) {
        $r = q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d", intval($parent_item['id']));
        update_thread($parent_item['id']);
    }
    // update the commented timestamp on the parent
    q("UPDATE `item` set `commented` = '%s', `changed` = '%s' WHERE `id` = %d", dbesc(datetime_convert()), dbesc(datetime_convert()), intval($parent));
    if ($post_id != $parent) {
        update_thread($parent);
    }
    call_hooks('post_local_end', $datarray);
    if (strlen($emailcc) && $profile_uid == local_user()) {
        $erecips = explode(',', $emailcc);
        if (count($erecips)) {
            foreach ($erecips as $recip) {
                $addr = trim($recip);
                if (!strlen($addr)) {
                    continue;
                }
                $disclaimer = '<hr />' . sprintf(t('This message was sent to you by %s, a member of the Friendica social network.'), $a->user['username']) . '<br />';
                $disclaimer .= sprintf(t('You may visit them online at %s'), $a->get_baseurl() . '/profile/' . $a->user['nickname']) . EOL;
                $disclaimer .= t('Please contact the sender by replying to this post if you do not wish to receive these messages.') . EOL;
                if (!$datarray['title'] == '') {
                    $subject = email_header_encode($datarray['title'], 'UTF-8');
                } else {
                    $subject = email_header_encode('[Friendica]' . ' ' . sprintf(t('%s posted an update.'), $a->user['username']), 'UTF-8');
                }
                $link = '<a href="' . $a->get_baseurl() . '/profile/' . $a->user['nickname'] . '"><img src="' . $author['thumb'] . '" alt="' . $a->user['username'] . '" /></a><br /><br />';
                $html = prepare_body($datarray);
                $message = '<html><body>' . $link . $html . $disclaimer . '</body></html>';
                include_once 'include/html2plain.php';
                $params = array('fromName' => $a->user['username'], 'fromEmail' => $a->user['email'], 'toEmail' => $addr, 'replyTo' => $a->user['email'], 'messageSubject' => $subject, 'htmlVersion' => $message, 'textVersion' => html2plain($html . $disclaimer));
                Emailer::send($params);
            }
        }
    }
    create_tags_from_item($post_id);
    create_files_from_item($post_id);
    if ($post_id == $parent) {
        add_thread($post_id);
    }
    // This is a real juggling act on shared hosting services which kill your processes
    // e.g. dreamhost. We used to start delivery to our native delivery agents in the background
    // and then run our plugin delivery from the foreground. We're now doing plugin delivery first,
    // because as soon as you start loading up a bunch of remote delivey processes, *this* page is
    // likely to get killed off. If you end up looking at an /item URL and a blank page,
    // it's very likely the delivery got killed before all your friends could be notified.
    // Currently the only realistic fixes are to use a reliable server - which precludes shared hosting,
    // or cut back on plugins which do remote deliveries.
    proc_run('php', "include/notifier.php", $notify_type, "{$post_id}");
    logger('post_complete');
    item_post_return($a->get_baseurl(), $api_source, $return_path);
    // NOTREACHED
}
Example #7
0
function diaspora2bb($s, $use_zrl = false)
{
    $s = html_entity_decode($s, ENT_COMPAT, 'UTF-8');
    // Too many new lines. So deactivated the following line
    // $s = str_replace("\r","\n",$s);
    // Simply remove cr.
    $s = str_replace("\r", "", $s);
    // <br/> is invalid. Replace it with the valid expression
    $s = str_replace("<br/>", "<br />", $s);
    $s = str_replace("\n", "<br />", $s);
    //	$s = preg_replace('/\@\{(.+?)\; (.+?)\@(.+?)\}/','@[url=https://$3/u/$2]$1[/url]',$s);
    // first try plustags
    $s = preg_replace_callback('/\\@\\{(.+?)\\; (.+?)\\@(.+?)\\}\\+/', 'diaspora_mention_callback', $s);
    $s = preg_replace_callback('/\\@\\{(.+?)\\; (.+?)\\@(.+?)\\}/', 'diaspora_mention_callback', $s);
    // Escaping the hash tags - doesn't always seem to work
    // $s = preg_replace('/\#([^\s\#])/','\\#$1',$s);
    // This seems to work
    $s = preg_replace('/\\#([^\\s\\#])/', '&#35;$1', $s);
    $s = preg_replace_callback('/\\[share(.*?)\\]/ism', 'share_shield', $s);
    $s = Markdown($s);
    $s = str_replace('&#35;', '#', $s);
    // we seem to have double linebreaks
    //	$s = str_replace("\n",'<br />',$s);
    $s = html2bbcode($s);
    //	$s = str_replace('&#42;','*',$s);
    // protect the recycle symbol from turning into a tag, but without unescaping angles and naked ampersands
    $s = str_replace('&#x2672;', html_entity_decode('&#x2672;', ENT_QUOTES, 'UTF-8'), $s);
    // Convert everything that looks like a link to a link
    if ($use_zrl) {
        $s = str_replace(array('[img', '/img]'), array('[zmg', '/zmg]'), $s);
        $s = preg_replace("/([^\\]\\=]|^)(https?\\:\\/\\/)([a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\$\\!\\+\\,]+)/ism", '$1[zrl=$2$3]$2$3[/zrl]', $s);
    } else {
        $s = preg_replace("/([^\\]\\=]|^)(https?\\:\\/\\/)([a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\$\\!\\+\\,]+)/ism", '$1[url=$2$3]$2$3[/url]', $s);
    }
    //$s = preg_replace("/([^\]\=]|^)(https?\:\/\/)(vimeo|youtu|www\.youtube|soundcloud)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2$3$4]$2$3$4[/url]',$s);
    $s = bb_tag_preg_replace("/\\[url\\=?(.*?)\\]https?:\\/\\/www.youtube.com\\/watch\\?v\\=(.*?)\\[\\/url\\]/ism", '[youtube]$2[/youtube]', 'url', $s);
    $s = bb_tag_preg_replace("/\\[url\\=https?:\\/\\/www.youtube.com\\/watch\\?v\\=(.*?)\\].*?\\[\\/url\\]/ism", '[youtube]$1[/youtube]', 'url', $s);
    $s = bb_tag_preg_replace("/\\[url\\=?(.*?)\\]https?:\\/\t\\/vimeo.com\\/([0-9]+)(.*?)\\[\\/url\\]/ism", '[vimeo]$2[/vimeo]', 'url', $s);
    $s = bb_tag_preg_replace("/\\[url\\=https?:\\/\\/vimeo.com\\/([0-9]+)\\](.*?)\\[\\/url\\]/ism", '[vimeo]$1[/vimeo]', 'url', $s);
    // remove duplicate adjacent code tags
    $s = preg_replace("/(\\[code\\])+(.*?)(\\[\\/code\\])+/ism", "[code]\$2[/code]", $s);
    $s = preg_replace_callback('/\\[share(.*?)\\]/ism', 'share_unshield', $s);
    // Don't show link to full picture (until it is fixed)
    $s = scale_external_images($s, false);
    return $s;
}
Example #8
0
function diaspora_photo($importer, $xml, $msg)
{
    $a = get_app();
    logger('diaspora_photo: init', LOGGER_DEBUG);
    $remote_photo_path = notags(unxmlify($xml->remote_photo_path));
    $remote_photo_name = notags(unxmlify($xml->remote_photo_name));
    $status_message_guid = notags(unxmlify($xml->status_message_guid));
    $guid = notags(unxmlify($xml->guid));
    $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
    $public = notags(unxmlify($xml->public));
    $created_at = notags(unxmlify($xml_created_at));
    logger('diaspora_photo: status_message_guid: ' . $status_message_guid, LOGGER_DEBUG);
    $contact = diaspora_get_contact_by_handle($importer['uid'], $msg['author']);
    if (!$contact) {
        logger('diaspora_photo: contact record not found: ' . $msg['author'] . ' handle: ' . $diaspora_handle);
        return;
    }
    if (!diaspora_post_allow($importer, $contact)) {
        logger('diaspora_photo: Ignoring this author.');
        return 202;
    }
    $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1", intval($importer['uid']), dbesc($status_message_guid));
    if (!count($r)) {
        logger('diaspora_photo: parent item not found: parent: ' . $parent_guid . ' item: ' . $guid);
        return;
    }
    $parent_item = $r[0];
    $link_text = '[img]' . $remote_photo_path . $remote_photo_name . '[/img]' . "\n";
    $link_text = scale_external_images($link_text);
    if (strpos($parent_item['body'], $link_text) === false) {
        $r = q("update item set `body` = '%s', `visible` = 1 where `id` = %d and `uid` = %d limit 1", dbesc($link_text . $parent_item['body']), intval($parent_item['id']), intval($parent_item['uid']));
    }
    return;
}
Example #9
0
function diaspora_asphoto($importer, $xml, $msg)
{
    // This call is believed to be obsolete since 2011-2012 and has not been ported
    // from the original Friendica implementation. The code remains in case it is
    // ever reimplemented in Diaspora, though it is unlikely that will occur in the
    // same context.
    logger('diaspora_asphoto called');
    $a = get_app();
    $guid = notags(unxmlify($xml['guid']));
    $diaspora_handle = notags(diaspora_get_author($xml));
    if ($diaspora_handle != $msg['author']) {
        logger('diaspora_post: Potential forgery. Message handle is not the same as envelope sender.');
        return 202;
    }
    $contact = diaspora_get_contact_by_handle($importer['channel_id'], $diaspora_handle);
    if (!$contact) {
        return;
    }
    if (!$importer['system'] && !perm_is_allowed($importer['channel_id'], $contact['xchan_hash'], 'send_stream')) {
        logger('diaspora_asphoto: Ignoring this author.');
        return 202;
    }
    $message_id = $diaspora_handle . ':' . $guid;
    $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `guid` = '%s' LIMIT 1", intval($importer['channel_id']), dbesc($message_id), dbesc($guid));
    if (count($r)) {
        logger('diaspora_asphoto: message exists: ' . $guid);
        return;
    }
    // allocate a guid on our system - we aren't fixing any collisions.
    // we're ignoring them
    $g = q("select * from guid where guid = '%s' limit 1", dbesc($guid));
    if (!count($g)) {
        q("insert into guid ( guid ) values ( '%s' )", dbesc($guid));
    }
    $created = unxmlify($xml['created_at']);
    $private = unxmlify($xml['public']) == 'false' ? 1 : 0;
    if (strlen($xml['objectId']) && $xml['objectId'] != 0 && $xml['image_url']) {
        $body = '[url=' . notags(unxmlify($xml['image_url'])) . '][img]' . notags(unxmlify($xml['objectId'])) . '[/img][/url]' . "\n";
        $body = scale_external_images($body, false);
    } elseif ($xml['image_url']) {
        $body = '[img]' . notags(unxmlify($xml['image_url'])) . '[/img]' . "\n";
        $body = scale_external_images($body);
    } else {
        logger('diaspora_asphoto: no photo url found.');
        return;
    }
    $plink = service_plink($contact, $guid);
    $datarray = array();
    $datarray['uid'] = $importer['channel_id'];
    $datarray['contact-id'] = $contact['id'];
    $datarray['wall'] = 0;
    $datarray['network'] = NETWORK_DIASPORA;
    $datarray['guid'] = $guid;
    $datarray['uri'] = $datarray['parent-uri'] = $message_id;
    $datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert('UTC', 'UTC', $created);
    $datarray['private'] = $private;
    $datarray['parent'] = 0;
    $datarray['plink'] = $plink;
    $datarray['owner-name'] = $contact['name'];
    $datarray['owner-link'] = $contact['url'];
    //$datarray['owner-avatar'] = $contact['thumb'];
    $datarray['owner-avatar'] = x($contact, 'thumb') ? $contact['thumb'] : $contact['photo'];
    $datarray['author-name'] = $contact['name'];
    $datarray['author-link'] = $contact['url'];
    $datarray['author-avatar'] = $contact['thumb'];
    $datarray['body'] = $body;
    $datarray['app'] = 'Diaspora/Cubbi.es';
    $result = item_store($datarray);
    if ($result['success']) {
        sync_an_item($importer['channel_id'], $result['item_id']);
    }
    return;
}
Example #10
0
function diaspora_reshare($importer, $xml, $msg)
{
    logger('diaspora_reshare: init: ' . print_r($xml, true), LOGGER_DATA);
    $a = get_app();
    $guid = notags(unxmlify($xml['guid']));
    $diaspora_handle = notags(diaspora_get_author($xml));
    if ($diaspora_handle != $msg['author']) {
        logger('Potential forgery. Message handle is not the same as envelope sender.');
        return 202;
    }
    $contact = diaspora_get_contact_by_handle($importer['channel_id'], $diaspora_handle);
    if (!$contact) {
        return;
    }
    $search_guid = strlen($guid) == 64 ? $guid . '%' : $guid;
    $r = q("SELECT id FROM item WHERE uid = %d AND mid like '%s' LIMIT 1", intval($importer['channel_id']), dbesc($search_guid));
    if ($r) {
        logger('diaspora_reshare: message exists: ' . $guid);
        return;
    }
    $orig_author = notags(diaspora_get_root_author($xml));
    $orig_guid = notags(unxmlify($xml['root_guid']));
    $source_url = 'https://' . substr($orig_author, strpos($orig_author, '@') + 1) . '/p/' . $orig_guid . '.xml';
    $orig_url = 'https://' . substr($orig_author, strpos($orig_author, '@') + 1) . '/posts/' . $orig_guid;
    $source_xml = get_diaspora_reshare_xml($source_url);
    if ($source_xml['status_message']) {
        $body = diaspora2bb(diaspora_get_body($source_xml['status_message']));
        $orig_author = diaspora_get_author($source_xml['status_message']);
        $orig_guid = notags(unxmlify($source_xml['status_message']['guid']));
        // Checking for embedded pictures
        if ($source_xml['status_message']['photo']['remote_photo_path'] && $source_xml['status_message']['photo']['remote_photo_name']) {
            $remote_photo_path = notags(unxmlify($source_xml['status_message']['photo']['remote_photo_path']));
            $remote_photo_name = notags(unxmlify($source_xml['status_message']['photo']['remote_photo_name']));
            $body = '[img]' . $remote_photo_path . $remote_photo_name . '[/img]' . "\n" . $body;
            logger('diaspora_reshare: embedded picture link found: ' . $body, LOGGER_DEBUG);
        }
        $body = scale_external_images($body);
        // Add OEmbed and other information to the body
        //		$body = add_page_info_to_body($body, false, true);
    } else {
        // Maybe it is a reshare of a photo that will be delivered at a later time (testing)
        logger('diaspora_reshare: no reshare content found: ' . print_r($source_xml, true));
        $body = "";
        //return;
    }
    $maxlen = get_max_import_size();
    if ($maxlen && mb_strlen($body) > $maxlen) {
        $body = mb_substr($body, 0, $maxlen, 'UTF-8');
        logger('message length exceeds max_import_size: truncated');
    }
    $person = find_diaspora_person_by_handle($orig_author);
    if ($person) {
        $orig_author_name = $person['xchan_name'];
        $orig_author_link = $person['xchan_url'];
        $orig_author_photo = $person['xchan_photo_m'];
    }
    $created = unxmlify($xml['created_at']);
    $private = unxmlify($xml['public']) == 'false' ? 1 : 0;
    $datarray = array();
    // Look for tags and linkify them
    $results = linkify_tags(get_app(), $body, $importer['channel_id'], true);
    $datarray['term'] = array();
    if ($results) {
        foreach ($results as $result) {
            $success = $result['success'];
            if ($success['replaced']) {
                $datarray['term'][] = array('uid' => $importer['channel_id'], 'ttype' => $success['termtype'], 'otype' => TERM_OBJ_POST, 'term' => $success['term'], 'url' => $success['url']);
            }
        }
    }
    $cnt = preg_match_all('/@\\[url=(.*?)\\](.*?)\\[\\/url\\]/ism', $body, $matches, PREG_SET_ORDER);
    if ($cnt) {
        foreach ($matches as $mtch) {
            $datarray['term'][] = array('uid' => $importer['channel_id'], 'ttype' => TERM_MENTION, 'otype' => TERM_OBJ_POST, 'term' => $mtch[2], 'url' => $mtch[1]);
        }
    }
    $cnt = preg_match_all('/@\\[zrl=(.*?)\\](.*?)\\[\\/zrl\\]/ism', $body, $matches, PREG_SET_ORDER);
    if ($cnt) {
        foreach ($matches as $mtch) {
            // don't include plustags in the term
            $term = substr($mtch[2], -1, 1) === '+' ? substr($mtch[2], 0, -1) : $mtch[2];
            $datarray['term'][] = array('uid' => $importer['channel_id'], 'ttype' => TERM_MENTION, 'otype' => TERM_OBJ_POST, 'term' => $term, 'url' => $mtch[1]);
        }
    }
    $newbody = "[share author='" . urlencode($orig_author_name) . "' profile='" . $orig_author_link . "' avatar='" . $orig_author_photo . "' link='" . $orig_url . "' posted='" . datetime_convert('UTC', 'UTC', unxmlify($source_xml['status_message']['created_at'])) . "' message_id='" . unxmlify($source_xml['status_message']['guid']) . "']" . $body . "[/share]";
    $plink = service_plink($contact, $guid);
    $datarray['aid'] = $importer['channel_account_id'];
    $datarray['uid'] = $importer['channel_id'];
    $datarray['mid'] = $datarray['parent_mid'] = $guid;
    $datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert('UTC', 'UTC', $created);
    $datarray['item_private'] = $private;
    $datarray['plink'] = $plink;
    $datarray['owner_xchan'] = $contact['xchan_hash'];
    $datarray['author_xchan'] = $contact['xchan_hash'];
    $datarray['body'] = $newbody;
    $datarray['app'] = 'Diaspora';
    $tgroup = tgroup_check($importer['channel_id'], $datarray);
    if (!$importer['system'] && !perm_is_allowed($importer['channel_id'], $contact['xchan_hash'], 'send_stream') && !$tgroup) {
        logger('diaspora_reshare: Ignoring this author.');
        return 202;
    }
    if (!post_is_importable($datarray, $contact)) {
        logger('diaspora_reshare: filtering this author.');
        return 202;
    }
    $result = item_store($datarray);
    if ($result['success']) {
        sync_an_item($importer['channel_id'], $result['item_id']);
    }
    return;
}
Example #11
0
/**
 * @brief
 *
 * We don't want to support a bbcode specific markdown interpreter
 * and the markdown library we have is pretty good, but provides HTML output.
 * So we'll use that to convert to HTML, then convert the HTML back to bbcode,
 * and then clean up a few Diaspora specific constructs.
 *
 * @param string $s
 * @param boolean $use_zrl default false
 * @return string
 */
function diaspora2bb($s, $use_zrl = false)
{
    $s = str_replace("&#xD;", "\r", $s);
    $s = str_replace("&#xD;\n&gt;", "", $s);
    $s = html_entity_decode($s, ENT_COMPAT, 'UTF-8');
    // first try plustags
    $s = preg_replace_callback('/\\@\\{(.+?)\\; (.+?)\\@(.+?)\\}\\+/', 'diaspora_mention_callback', $s);
    $s = preg_replace_callback('/\\@\\{(.+?)\\; (.+?)\\@(.+?)\\}/', 'diaspora_mention_callback', $s);
    // Escaping the hash tags - doesn't always seem to work
    // $s = preg_replace('/\#([^\s\#])/','\\#$1',$s);
    // This seems to work
    $s = preg_replace('/\\#([^\\s\\#])/', '&#35;$1', $s);
    $s = Markdown($s);
    $s = str_replace("\r", "", $s);
    $s = str_replace('&#35;', '#', $s);
    $s = html2bbcode($s);
    // protect the recycle symbol from turning into a tag, but without unescaping angles and naked ampersands
    $s = str_replace('&#x2672;', html_entity_decode('&#x2672;', ENT_QUOTES, 'UTF-8'), $s);
    // Convert everything that looks like a link to a link
    if ($use_zrl) {
        $s = str_replace(array('[img', '/img]'), array('[zmg', '/zmg]'), $s);
        $s = preg_replace("/([^\\]\\=]|^)(https?\\:\\/\\/)([a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\$\\!\\+\\,]+)/ism", '$1[zrl=$2$3]$2$3[/zrl]', $s);
    } else {
        $s = preg_replace("/([^\\]\\=]|^)(https?\\:\\/\\/)([a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\$\\!\\+\\,]+)/ism", '$1[url=$2$3]$2$3[/url]', $s);
    }
    //$s = preg_replace("/([^\]\=]|^)(https?\:\/\/)(vimeo|youtu|www\.youtube|soundcloud)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2$3$4]$2$3$4[/url]',$s);
    $s = bb_tag_preg_replace("/\\[url\\=?(.*?)\\]https?:\\/\\/www.youtube.com\\/watch\\?v\\=(.*?)\\[\\/url\\]/ism", '[embed]https://www.youtube.com/watch?v=$2[/embed]', 'url', $s);
    $s = bb_tag_preg_replace("/\\[url\\=https?:\\/\\/www.youtube.com\\/watch\\?v\\=(.*?)\\].*?\\[\\/url\\]/ism", '[embed]https://www.youtube.com/watch?v=$1[/embed]', 'url', $s);
    $s = bb_tag_preg_replace("/\\[url\\=?(.*?)\\]https?:\\/\t\\/vimeo.com\\/([0-9]+)(.*?)\\[\\/url\\]/ism", '[embed]https://vimeo.com/$2[/embed]', 'url', $s);
    $s = bb_tag_preg_replace("/\\[url\\=https?:\\/\\/vimeo.com\\/([0-9]+)\\](.*?)\\[\\/url\\]/ism", '[embed]https://vimeo.com/$1[/embed]', 'url', $s);
    // remove duplicate adjacent code tags
    $s = preg_replace("/(\\[code\\])+(.*?)(\\[\\/code\\])+/ism", "[code]\$2[/code]", $s);
    // Don't show link to full picture (until it is fixed)
    $s = scale_external_images($s, false);
    return $s;
}
Example #12
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
 }
Example #13
0
function diaspora_photo($importer, $xml, $msg, $attempt = 1)
{
    $a = get_app();
    logger('diaspora_photo: init', LOGGER_DEBUG);
    $remote_photo_path = notags(unxmlify($xml->remote_photo_path));
    $remote_photo_name = notags(unxmlify($xml->remote_photo_name));
    $status_message_guid = notags(unxmlify($xml->status_message_guid));
    $guid = notags(unxmlify($xml->guid));
    $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
    $public = notags(unxmlify($xml->public));
    $created_at = notags(unxmlify($xml_created_at));
    logger('diaspora_photo: status_message_guid: ' . $status_message_guid, LOGGER_DEBUG);
    $contact = diaspora_get_contact_by_handle($importer['uid'], $msg['author']);
    if (!$contact) {
        logger('diaspora_photo: contact record not found: ' . $msg['author'] . ' handle: ' . $diaspora_handle);
        return;
    }
    if (!diaspora_post_allow($importer, $contact)) {
        logger('diaspora_photo: Ignoring this author.');
        return 202;
    }
    $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `guid` = '%s' LIMIT 1", intval($importer['uid']), dbesc($status_message_guid));
    if (!count($r)) {
        if ($attempt <= 3) {
            q("INSERT INTO dsprphotoq (uid, msg, attempt) VALUES (%d, '%s', %d)", intval($importer['uid']), dbesc(serialize($msg)), intval($attempt + 1));
        }
        logger('diaspora_photo: attempt = ' . $attempt . '; status message not found: ' . $status_message_guid . ' for photo: ' . $guid);
        return;
    }
    $parent_item = $r[0];
    $link_text = '[img]' . $remote_photo_path . $remote_photo_name . '[/img]' . "\n";
    $link_text = scale_external_images($link_text, true, array($remote_photo_name, 'scaled_full_' . $remote_photo_name));
    if (strpos($parent_item['body'], $link_text) === false) {
        $r = q("update item set `body` = '%s', `visible` = 1 where `id` = %d and `uid` = %d", dbesc($link_text . $parent_item['body']), intval($parent_item['id']), intval($parent_item['uid']));
    }
    return;
}