Beispiel #1
0
function wppost_post_remote_end(&$a, &$b)
{
    // We are only looking for public comments
    logger('wppost_post_remote_end');
    if ($b['mid'] === $b['parent_mid']) {
        return;
    }
    if (!is_item_normal($b) || $b['item_private']) {
        return;
    }
    // Does the post owner have this plugin installed?
    $wp_post = intval(get_pconfig($b['uid'], 'wppost', 'post'));
    if (!$wp_post) {
        return;
    }
    // Are we allowed to forward comments?
    $wp_forward_comments = intval(get_pconfig($b['uid'], 'wppost', 'forward_comments'));
    if (!$wp_forward_comments) {
        return;
    }
    // how about our stream permissions?
    if (!perm_is_allowed($b['uid'], '', 'view_stream')) {
        return;
    }
    // Now we have to get down and dirty. Was the parent shared with wordpress?
    $r = q("select * from iconfig left join item on iconfig.iid = item.id where cat = 'system' and k = 'wordpress' and iid = %d and item.uid = %d limit 1", intval($b['parent']), intval($b['uid']));
    if (!$r) {
        return;
    }
    $wp_parent_id = intval(basename($r[0]['v']));
    $x = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($b['author_xchan']));
    if (!$x) {
        return;
    }
    logger('Wordpress xpost comment invoked', LOGGER_DEBUG);
    $edited = $b['created'] !== $b['edited'] ? true : false;
    if ($edited) {
        $r = q("select * from iconfig left join item on iconfig.iid = item.id\n\t\t\twhere cat = 'system' and k = 'wordpress' and iid = %d and uid = %d limit 1", intval($b['id']), intval($b['uid']));
        if (!$r) {
            return;
        }
        $wp_comment_id = intval(basename($r[0]['v']));
    }
    $wp_username = get_pconfig($b['uid'], 'wppost', 'wp_username');
    $wp_password = z_unobscure(get_pconfig($b['uid'], 'wppost', 'wp_password'));
    $wp_blog = get_pconfig($b['uid'], 'wppost', 'wp_blog');
    $wp_blogid = get_pconfig($b['uid'], 'wppost', 'wp_blogid');
    if (!$wp_blogid) {
        $wp_blogid = 1;
    }
    if ($wp_username && $wp_password && $wp_blog) {
        require_once 'include/bbcode.php';
        $data = array('author' => $x[0]['xchan_name'], 'author_email' => $x[0]['xchan_addr'], 'author_url' => $x[0]['xchan_url'], 'content' => bbcode($b['body']), 'approved' => 1);
        if ($edited) {
            $data['comment_id'] = $wp_comment_id;
        } else {
            $data['red_avatar'] = $x[0]['xchan_photo_m'];
        }
        $client = new IXR_Client($wp_blog);
        // this will fail if the post_to_red plugin isn't installed on the wordpress site
        $res = $client->query('red.Comment', $wp_blogid, $wp_username, $wp_password, $wp_parent_id, $data);
        if (!$res) {
            logger('wppost: comment failed.');
            return;
        }
        $post_id = $client->getResponse();
        logger('wppost: comment returns post_id: ' . $post_id, LOGGER_DEBUG);
        // edited just returns true
        if ($edited) {
            return;
        }
        if ($post_id) {
            q("insert into iconfig ( iid, cat, v, k, sharing ) values ( %d, 'system', '%s', '%s', 1 )", intval($b['id']), dbesc(dirname($wp_blog) . '/' . $post_id), dbesc('wordpress'));
        }
    }
}
Beispiel #2
0
function dwpost_send(&$a, &$b)
{
    if (!is_item_normal($b) || $b['item_private'] || $b['created'] !== $b['edited']) {
        return;
    }
    if (!perm_is_allowed($b['uid'], '', 'view_stream')) {
        return;
    }
    if (!strstr($b['postopts'], 'dwpost')) {
        return;
    }
    if ($b['parent'] != $b['id']) {
        return;
    }
    // dreamwidth post in the LJ user's timezone.
    // Hopefully the person's Friendica account
    // will be set to the same thing.
    $tz = 'UTC';
    $x = q("select channel_timezone from channel where channel_id = %d limit 1", intval($b['uid']));
    if ($x && strlen($x[0]['channel_timezone'])) {
        $tz = $x[0]['channel_timezone'];
    }
    $dw_username = get_pconfig($b['uid'], 'dwpost', 'dw_username');
    $dw_password = z_unobscure(get_pconfig($b['uid'], 'dwpost', 'dw_password'));
    $dw_blog = 'http://www.dreamwidth.org/interface/xmlrpc';
    if ($dw_username && $dw_password && $dw_blog) {
        require_once 'include/bbcode.php';
        require_once 'include/datetime.php';
        $title = $b['title'];
        $post = bbcode($b['body']);
        $post = xmlify($post);
        $tags = dwpost_get_tags($b['tag']);
        $date = datetime_convert('UTC', $tz, $b['created'], 'Y-m-d H:i:s');
        $year = intval(substr($date, 0, 4));
        $mon = intval(substr($date, 5, 2));
        $day = intval(substr($date, 8, 2));
        $hour = intval(substr($date, 11, 2));
        $min = intval(substr($date, 14, 2));
        $xml = <<<EOT
<?xml version="1.0" encoding="utf-8"?>
<methodCall><methodName>LJ.XMLRPC.postevent</methodName>
<params><param>
<value><struct>
<member><name>year</name><value><int>{$year}</int></value></member>
<member><name>mon</name><value><int>{$mon}</int></value></member>
<member><name>day</name><value><int>{$day}</int></value></member>
<member><name>hour</name><value><int>{$hour}</int></value></member>
<member><name>min</name><value><int>{$min}</int></value></member>
<member><name>event</name><value><string>{$post}</string></value></member>
<member><name>username</name><value><string>{$dw_username}</string></value></member>
<member><name>password</name><value><string>{$dw_password}</string></value></member>
<member><name>subject</name><value><string>{$title}</string></value></member>
<member><name>lineendings</name><value><string>unix</string></value></member>
<member><name>ver</name><value><int>1</int></value></member>
<member><name>props</name>
<value><struct>
<member><name>useragent</name><value><string>Friendica</string></value></member>
<member><name>taglist</name><value><string>{$tags}</string></value></member>
</struct></value></member>
</struct></value>
</param></params>
</methodCall>

EOT;
        logger('dwpost: data: ' . $xml, LOGGER_DATA);
        if ($dw_blog !== 'test') {
            $x = z_post_url($dw_blog, $xml, array('headers' => array("Content-Type: text/xml")));
        }
        logger('posted to dreamwidth: ' . print_r($x, true), LOGGER_DEBUG);
    }
}
function diaspost_send(&$a, &$b)
{
    $hostname = 'hubzilla ' . '(' . $a->get_hostname() . ')';
    logger('diaspost_send: invoked', LOGGER_DEBUG);
    if ($b['mid'] != $b['parent_mid']) {
        return;
    }
    if (!is_item_normal($b) || $b['item_private'] || $b['created'] !== $b['edited']) {
        return;
    }
    if (!perm_is_allowed($b['uid'], '', 'view_stream')) {
        return;
    }
    if (!strstr($b['postopts'], 'diaspost')) {
        return;
    }
    logger('diaspost_send: prepare posting', LOGGER_DEBUG);
    $diaspost_username = get_pconfig($b['uid'], 'diaspost', 'diaspost_username');
    $diaspost_password = z_unobscure(get_pconfig($b['uid'], 'diaspost', 'diaspost_password'));
    $diaspost_url = get_pconfig($b['uid'], 'diaspost', 'diaspost_url');
    if ($diaspost_url && $diaspost_username && $diaspost_password) {
        logger('diaspost_send: all values seem to be okay', LOGGER_DEBUG);
        require_once 'include/bb2diaspora.php';
        $tag_arr = array();
        $tags = '';
        $x = preg_match_all('/\\#\\[(.*?)\\](.*?)\\[/', $b['tag'], $matches, PREG_SET_ORDER);
        if ($x) {
            foreach ($matches as $mtch) {
                $tag_arr[] = $mtch[2];
            }
        }
        if (count($tag_arr)) {
            $tags = implode(',', $tag_arr);
        }
        $title = $b['title'];
        $body = $b['body'];
        // Insert a newline before and after a quote
        $body = str_ireplace("[quote", "\n\n[quote", $body);
        $body = str_ireplace("[/quote]", "[/quote]\n\n", $body);
        // strip bookmark indicators
        $body = preg_replace('/\\#\\^\\[([zu])rl/i', '[$1rl', $body);
        $body = preg_replace('/\\#\\^http/i', 'http', $body);
        if (intval(get_pconfig($item['uid'], 'system', 'prevent_tag_hijacking'))) {
            $new_tag = html_entity_decode('&#x22d5;', ENT_COMPAT, 'UTF-8');
            $new_mention = html_entity_decode('&#xff20;', ENT_COMPAT, 'UTF-8');
            // #-tags
            $body = preg_replace('/\\#\\[url/i', $new_tag . '[url', $body);
            $body = preg_replace('/\\#\\[zrl/i', $new_tag . '[zrl', $body);
            // @-mentions
            $body = preg_replace('/\\@\\!?\\[url/i', $new_mention . '[url', $body);
            $body = preg_replace('/\\@\\!?\\[zrl/i', $new_mention . '[zrl', $body);
        }
        // remove multiple newlines
        do {
            $oldbody = $body;
            $body = str_replace("\n\n\n", "\n\n", $body);
        } while ($oldbody != $body);
        // convert to markdown
        $body = bb2diaspora($body, false, true);
        // Adding the title
        if (strlen($title)) {
            $body = "## " . html_entity_decode($title) . "\n\n" . $body;
        }
        require_once "addon/diaspost/diasphp.php";
        try {
            logger('diaspost_send: prepare', LOGGER_DEBUG);
            $conn = new Diasphp($diaspost_url);
            logger('diaspost_send: try to log in ' . $diaspost_username, LOGGER_DEBUG);
            $conn->login($diaspost_username, $diaspost_password);
            logger('diaspost_send: try to send ' . $body, LOGGER_DEBUG);
            //throw new Exception('Test');
            $conn->post($body, $hostname);
            logger('diaspost_send: success');
        } catch (Exception $e) {
            logger("diaspost_send: Error submitting the post: " . $e->getMessage());
            //			logger('diaspost_send: requeueing '.$b['uid'], LOGGER_DEBUG);
            //			$r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `self`", $b['uid']);
            //			if (count($r))
            //				$a->contact = $r[0]["id"];
            //			$s = serialize(array('url' => $url, 'item' => $b['id'], 'post' => $body));
            //			require_once('include/queue_fn.php');
            //			add_to_queue($a->contact,NETWORK_DIASPORA2,$s);
            //			notice(t('Diaspost post failed. Queued for retry.').EOL);
        }
    }
}
function rtof_post_hook(&$a, &$b)
{
    /**
     * Post to Friendica
     */
    // for now, just top level posts.
    if ($b['mid'] != $b['parent_mid']) {
        return;
    }
    if (!is_item_normal($b) || $b['item_private'] || $b['created'] !== $b['edited']) {
        return;
    }
    if (!perm_is_allowed($b['uid'], '', 'view_stream')) {
        return;
    }
    if (!strstr($b['postopts'], 'rtof')) {
        return;
    }
    logger('Red-to-Friendica post invoked');
    load_pconfig($b['uid'], 'rtof');
    $api = get_pconfig($b['uid'], 'rtof', 'baseapi');
    if (substr($api, -1, 1) != '/') {
        $api .= '/';
    }
    $username = get_pconfig($b['uid'], 'rtof', 'username');
    $password = z_unobscure(get_pconfig($b['uid'], 'rtof', 'password'));
    $msg = $b['body'];
    $postdata = array('status' => $b['body'], 'title' => $b['title'], 'message_id' => $b['mid'], 'source' => 'Red Matrix');
    if (strlen($b['body'])) {
        $ret = z_post_url($api . 'statuses/update', $postdata, 0, array('http_auth' => $username . ':' . $password, 'novalidate' => 1));
        if ($ret['success']) {
            logger('rtof: returns: ' . print_r($ret['body'], true));
        } else {
            logger('rtof: z_post_url failed: ' . print_r($ret['debug'], true));
        }
    }
}
function twitter_post_hook(&$a, &$b)
{
    /**
     * Post to Twitter
     */
    if (!is_item_normal($b) || $b['item_private'] || $b['created'] !== $b['edited']) {
        return;
    }
    if (!perm_is_allowed($b['uid'], '', 'view_stream')) {
        return;
    }
    if (!strstr($b['postopts'], 'twitter')) {
        return;
    }
    if ($b['parent'] != $b['id']) {
        return;
    }
    logger('twitter post invoked');
    load_pconfig($b['uid'], 'twitter');
    $ckey = get_config('twitter', 'consumerkey');
    $csecret = get_config('twitter', 'consumersecret');
    $otoken = get_pconfig($b['uid'], 'twitter', 'oauthtoken');
    $osecret = get_pconfig($b['uid'], 'twitter', 'oauthsecret');
    $intelligent_shortening = get_pconfig($b['uid'], 'twitter', 'intelligent_shortening');
    // Global setting overrides this
    if (get_config('twitter', 'intelligent_shortening')) {
        $intelligent_shortening = get_config('twitter', 'intelligent_shortening');
    }
    if ($ckey && $csecret && $otoken && $osecret) {
        logger('twitter: we have customer key and oauth stuff, going to send.', LOGGER_DEBUG);
        // If it's a repeated message from twitter then do a native retweet and exit
        //		if (twitter_is_retweet($a, $b['uid'], $b['body']))
        //			return;
        require_once 'library/twitteroauth.php';
        require_once 'include/bbcode.php';
        $tweet = new TwitterOAuth($ckey, $csecret, $otoken, $osecret);
        // in theory max char is 140 but T. uses t.co to make links
        // longer so we give them 10 characters extra
        if (!$intelligent_shortening) {
            $max_char = 130;
            // max. length for a tweet
            // we will only work with up to two times the length of the dent
            // we can later send to Twitter. This way we can "gain" some
            // information during shortening of potential links but do not
            // shorten all the links in a 200000 character long essay.
            if (!$b['title'] == '') {
                $tmp = $b['title'] . ' : ' . $b['body'];
                //                    $tmp = substr($tmp, 0, 4*$max_char);
            } else {
                $tmp = $b['body'];
                // substr($b['body'], 0, 3*$max_char);
            }
            // if [url=bla][img]blub.png[/img][/url] get blub.png
            $tmp = preg_replace('/\\[url\\=(https?\\:\\/\\/[a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\\$\\!\\+\\,]+)\\]\\[img\\](\\w+.*?)\\[\\/img\\]\\[\\/url\\]/i', '$2', $tmp);
            $tmp = preg_replace('/\\[zrl\\=(https?\\:\\/\\/[a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\\$\\!\\+\\,]+)\\]\\[zmg\\](\\w+.*?)\\[\\/zmg\\]\\[\\/zrl\\]/i', '$2', $tmp);
            // preserve links to images, videos and audios
            $tmp = preg_replace('/\\[img\\=([0-9]*)x([0-9]*)\\](.*?)\\[\\/img\\]/ism', '$3', $tmp);
            $tmp = preg_replace('/\\[\\/?img(\\s+.*?\\]|\\])/i', '', $tmp);
            $tmp = preg_replace('/\\[zmg\\=([0-9]*)x([0-9]*)\\](.*?)\\[\\/zmg\\]/ism', '$3', $tmp);
            $tmp = preg_replace('/\\[\\/?zmg(\\s+.*?\\]|\\])/i', '', $tmp);
            $tmp = preg_replace('/\\[\\/?video(\\s+.*?\\]|\\])/i', '', $tmp);
            $tmp = preg_replace('/\\[\\/?youtube(\\s+.*?\\]|\\])/i', '', $tmp);
            $tmp = preg_replace('/\\[\\/?vimeo(\\s+.*?\\]|\\])/i', '', $tmp);
            $tmp = preg_replace('/\\[\\/?audio(\\s+.*?\\]|\\])/i', '', $tmp);
            $linksenabled = get_pconfig($b['uid'], 'twitter', 'post_taglinks');
            // if a #tag is linked, don't send the [url] over to SN
            // that is, don't send if the option is not set in the
            // connector settings
            if ($linksenabled == '0') {
                // #-tags
                $tmp = preg_replace('/#\\[url\\=(\\w+.*?)\\](\\w+.*?)\\[\\/url\\]/i', '#$2', $tmp);
                // @-mentions
                $tmp = preg_replace('/@\\[url\\=(\\w+.*?)\\](\\w+.*?)\\[\\/url\\]/i', '@$2', $tmp);
                $tmp = preg_replace('/#\\[zrl\\=(\\w+.*?)\\](\\w+.*?)\\[\\/zrl\\]/i', '#$2', $tmp);
                // @-mentions
                $tmp = preg_replace('/@\\[zrl\\=(\\w+.*?)\\](\\w+.*?)\\[\\/zrl\\]/i', '@$2', $tmp);
                // recycle 1
            }
            $tmp = preg_replace('/\\[url\\=(https?\\:\\/\\/[a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\\$\\!\\+\\,]+)\\](\\w+.*?)\\[\\/url\\]/i', '$2 $1', $tmp);
            // find all http or https links in the body of the entry and
            // apply the shortener if the link is longer then 20 characters
            if (strlen($tmp) > $max_char && $max_char > 0) {
                preg_match_all('/(https?\\:\\/\\/[a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\\$\\!\\+\\,]+)/i', $tmp, $allurls);
                foreach ($allurls as $url) {
                    foreach ($url as $u) {
                        if (strlen($u) > 20) {
                            $sl = short_link($u);
                            $tmp = str_replace($u, $sl, $tmp);
                        }
                    }
                }
            }
            // ok, all the links we want to send out are save, now strip
            // away the remaining bbcode
            //$msg = strip_tags(bbcode($tmp, false, false));
            $msg = bbcode($tmp, false, false);
            $msg = str_replace(array('<br>', '<br />'), "\n", $msg);
            $msg = strip_tags($msg);
            // quotes not working - let's try this
            $msg = html_entity_decode($msg);
            if (strlen($msg) > $max_char && $max_char > 0) {
                $shortlink = short_link($b['plink']);
                // the new message will be shortened such that "... $shortlink"
                // will fit into the character limit
                $msg = nl2br(substr($msg, 0, $max_char - strlen($shortlink) - 4));
                $msg = str_replace(array('<br>', '<br />'), ' ', $msg);
                $e = explode(' ', $msg);
                //  remove the last word from the cut down message to
                //  avoid sending cut words to the MicroBlog
                array_pop($e);
                $msg = implode(' ', $e);
                $msg .= '... ' . $shortlink;
            }
            $msg = trim($msg);
            $image = "";
        } else {
            $msgarr = twitter_shortenmsg($b);
            $msg = $msgarr["msg"];
            $image = $msgarr["image"];
        }
        // and now tweet it :-)
        //		if(strlen($msg) and ($image != "")) {
        //			$img_str = z_fetch_url($image);
        //			$tempfile = tempnam(get_config("system","temppath"), "cache");
        //			file_put_contents($tempfile, $img_str);
        // Twitter had changed something so that the old library doesn't work anymore
        // so we are using a new library for twitter
        // To-Do:
        // Switching completely to this library with all functions
        require_once "addon/twitter/codebird.php";
        //			$cb = \Codebird\Codebird::getInstance();
        //			$cb->setConsumerKey($ckey, $csecret);
        //			$cb->setToken($otoken, $osecret);
        //			$post = array('status' => $msg, 'media[]' => $tempfile);
        //			if ($iscomment)
        //				$post["in_reply_to_status_id"] = substr($orig_post["uri"], 9);
        //			$result = $cb->statuses_updateWithMedia($post);
        //			unlink($tempfile);
        //			logger('twitter_post_with_media send, result: ' . print_r($result, true), LOGGER_DEBUG);
        //			if ($result->errors OR $result->error) {
        //				logger('Send to Twitter failed: "' . print_r($result->errors, true) . '"');
        // Workaround: Remove the picture link so that the post can be reposted without it
        //				$msg .= " ".$image;
        //				$image = "";
        //			} elseif ($iscomment) {
        //				logger('twitter_post: Update extid '.$result->id_str." for post id ".$b['id']);
        //				q("UPDATE `item` SET `extid` = '%s', `body` = '%s' WHERE `id` = %d",
        //					dbesc("twitter::".$result->id_str),
        //					dbesc($result->text),
        //					intval($b['id'])
        //				);
        //			}
        //		}
        if (strlen($msg) and $image == "") {
            $url = 'statuses/update';
            $post = array('status' => $msg);
            if ($iscomment) {
                $post["in_reply_to_status_id"] = substr($orig_post["uri"], 9);
            }
            $result = $tweet->post($url, $post);
            logger('twitter_post send, result: ' . print_r($result, true), LOGGER_DEBUG);
            if ($result->errors) {
                logger('Send to Twitter failed: "' . print_r($result->errors, true) . '"');
            }
            //		elseif ($iscomment) {
            //				logger('twitter_post: Update extid '.$result->id_str." for post id ".$b['id']);
            //				q("UPDATE `item` SET `extid` = '%s' WHERE `id` = %d",
            //					dbesc("twitter::".$result->id_str),
            //					intval($b['id'])
            //				);
            //q("UPDATE `item` SET `extid` = '%s', `body` = '%s' WHERE `id` = %d",
            //	dbesc("twitter::".$result->id_str),
            //	dbesc($result->text),
            //	intval($b['id'])
            //);
            //			}
        }
    }
}
Beispiel #6
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_TYPE_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) && 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($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_wall'] && $parent_item['item_origin'])) {
                $walltowall_comment = true;
                $walltowall = true;
            }
            if (!$parent) {
                $walltowall = true;
            }
        }
    }
    $acl = new AccessList($channel);
    $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) {
            $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 && (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);
        }
        $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($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();
            }
        }
    }
    $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';
        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) {
                $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' => $a->get_baseurl() . '/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], $attach_link, $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 = 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;
    // 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_thead_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['item_private'] = $private;
    $datarray['item_wall'] = $item_wall;
    $datarray['attach'] = $attachments;
    $datarray['thr_parent'] = $thr_parent;
    $datarray['postopts'] = $postopts;
    $datarray['item_unseen'] = $item_unseen;
    $datarray['item_wall'] = $item_wall;
    $datarray['item_origin'] = $item_origin;
    $datarray['item_type'] = $webpage;
    $datarray['item_thread_top'] = $item_thread_top;
    $datarray['item_unseen'] = $item_unseen;
    $datarray['item_starred'] = $item_starred;
    $datarray['item_uplink'] = $item_uplink;
    $datarray['item_consensus'] = $item_consensus;
    $datarray['item_notshown'] = $item_notshown;
    $datarray['item_nsfw'] = $item_nsfw;
    $datarray['item_relay'] = $item_relay;
    $datarray['item_mentionsme'] = $item_mentionsme;
    $datarray['item_nocomment'] = $item_nocomment;
    $datarray['item_obscured'] = $item_obscured;
    $datarray['item_verified'] = $item_verified;
    $datarray['item_retained'] = $item_retained;
    $datarray['item_rss'] = $item_rss;
    $datarray['item_deleted'] = $item_deleted;
    $datarray['item_hidden'] = $item_hidden;
    $datarray['item_unpublished'] = $item_unpublished;
    $datarray['item_delayed'] = $item_delayed;
    $datarray['item_pending_remove'] = $item_pending_remove;
    $datarray['item_blocked'] = $item_blocked;
    $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;
    // 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_verified'] = 1;
            }
        }
    }
    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 (!$parent) {
            $r = q("select * from item where id = %d", intval($post_id));
            if ($r) {
                xchan_query($r);
                $sync_item = fetch_post_tags($r);
                $rid = q("select * from item_id where iid = %d", intval($post_id));
                build_sync_packet($uid, array('item' => array(encode_item($sync_item[0], true)), 'item_id' => $rid));
            }
        }
        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'] && intval($parent_item['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 && 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($a->get_baseurl() . "/" . $return_path);
        // NOTREACHED
    }
    update_remote_id($channel, $post_id, $webpage, $pagetitle, $namespace, $remote_id, $mid);
    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);
            $rid = q("select * from item_id where iid = %d", intval($post_id));
            build_sync_packet($uid, array('item' => array(encode_item($sync_item[0], true)), 'item_id' => $rid));
        }
    }
    $datarray['id'] = $post_id;
    $datarray['llink'] = $a->get_baseurl() . '/display/' . $channel['channel_address'] . '/' . $post_id;
    call_hooks('post_local_end', $datarray);
    if (!$nopush) {
        proc_run('php', 'include/notifier.php', $notify_type, $post_id);
    }
    logger('post_complete');
    // figure out how to return, depending on from whence we came
    if ($api_source) {
        return $post;
    }
    if ($return_path) {
        goaway($a->get_baseurl() . "/" . $return_path);
    }
    $json = array('success' => 1);
    if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload'])) {
        $json['reload'] = $a->get_baseurl() . '/' . $_REQUEST['jsreload'];
    }
    logger('post_json: ' . print_r($json, true), LOGGER_DEBUG);
    echo json_encode($json);
    killme();
    // NOTREACHED
}
Beispiel #7
0
function statusnet_post_hook(&$a, &$b)
{
    /**
     * Post to statusnet
     */
    if (!strstr($b['postopts'], 'statusnet')) {
        logger('crosspost not enabled.');
        return;
    }
    if (!is_item_normal($b) || $b['item_private'] || $b['created'] !== $b['edited']) {
        logger('not a usable post. ' . print_r($b, true), LOGGER_DEBUG);
        return;
    }
    if (!perm_is_allowed($b['uid'], '', 'view_stream')) {
        logger('permissions prevent crossposting.', LOGGER_DEBUG);
        return;
    }
    if ($b['parent'] != $b['id']) {
        logger('not a top level post.', LOGGER_DEBUG);
        return;
    }
    // if posts comes from statusnet don't send it back
    if ($b['app'] == "StatusNet") {
        logger('potential recursion. Crosspost ignored.');
        return;
    }
    logger('statusnet post invoked');
    load_pconfig($b['uid'], 'statusnet');
    $api = get_pconfig($b['uid'], 'statusnet', 'baseapi');
    $ckey = get_pconfig($b['uid'], 'statusnet', 'consumerkey');
    $csecret = get_pconfig($b['uid'], 'statusnet', 'consumersecret');
    $otoken = get_pconfig($b['uid'], 'statusnet', 'oauthtoken');
    $osecret = get_pconfig($b['uid'], 'statusnet', 'oauthsecret');
    $intelligent_shortening = get_pconfig($b['uid'], 'statusnet', 'intelligent_shortening');
    // Global setting overrides this
    if (get_config('statusnet', 'intelligent_shortening')) {
        $intelligent_shortening = get_config('statusnet', 'intelligent_shortening');
    }
    if ($ckey && $csecret && $otoken && $osecret) {
        require_once 'include/bbcode.php';
        $dent = new StatusNetOAuth($api, $ckey, $csecret, $otoken, $osecret);
        $max_char = $dent->get_maxlength();
        // max. length for a dent
        // we will only work with up to two times the length of the dent
        // we can later send to GNU social. This way we can "gain" some
        // information during shortening of potential links but do not
        // shorten all the links in a 200000 character long essay.
        $tempfile = "";
        $intelligent_shortening = get_config('statusnet', 'intelligent_shortening');
        if (!$intelligent_shortening) {
            if (!$b['title'] == '') {
                $tmp = $b['title'] . ": \n" . $b['body'];
                //					$tmp = substr($tmp, 0, 4*$max_char);
            } else {
                $tmp = $b['body'];
                // substr($b['body'], 0, 3*$max_char);
            }
            // if [url=bla][img]blub.png[/img][/url] get blub.png
            $tmp = preg_replace('/\\[url\\=(https?\\:\\/\\/[a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\\$\\!\\+\\,]+)\\]\\[img\\](\\w+.*?)\\[\\/img\\]\\[\\/url\\]/i', '$2', $tmp);
            $tmp = preg_replace('/\\[zrl\\=(https?\\:\\/\\/[a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\\$\\!\\+\\,]+)\\]\\[zmg\\](\\w+.*?)\\[\\/zmg\\]\\[\\/zrl\\]/i', '$2', $tmp);
            // preserve links to images, videos and audios
            $tmp = preg_replace('/\\[img\\=([0-9]*)x([0-9]*)\\](.*?)\\[\\/img\\]/ism', '$3', $tmp);
            $tmp = preg_replace('/\\[\\/?img(\\s+.*?\\]|\\])/i', '', $tmp);
            $tmp = preg_replace('/\\[zmg\\=([0-9]*)x([0-9]*)\\](.*?)\\[\\/zmg\\]/ism', '$3', $tmp);
            $tmp = preg_replace('/\\[\\/?zmg(\\s+.*?\\]|\\])/i', '', $tmp);
            $tmp = preg_replace('/\\[\\/?video(\\s+.*?\\]|\\])/i', '', $tmp);
            $tmp = preg_replace('/\\[\\/?audio(\\s+.*?\\]|\\])/i', '', $tmp);
            $linksenabled = get_pconfig($b['uid'], 'statusnet', 'post_taglinks');
            // if a #tag is linked, don't send the [url] over to SN
            // that is, don't send if the option is not set in the
            // connector settings
            if ($linksenabled == '0') {
                // #-tags
                $tmp = preg_replace('/#\\[url\\=(\\w+.*?)\\](\\w+.*?)\\[\\/url\\]/i', '#$2', $tmp);
                // @-mentions
                $tmp = preg_replace('/@\\[url\\=(\\w+.*?)\\](\\w+.*?)\\[\\/url\\]/i', '@$2', $tmp);
                // #-tags
                $tmp = preg_replace('/#\\[zrl\\=(\\w+.*?)\\](\\w+.*?)\\[\\/zrl\\]/i', '#$2', $tmp);
                // @-mentions
                $tmp = preg_replace('/@\\[zrl\\=(\\w+.*?)\\](\\w+.*?)\\[\\/zrl\\]/i', '@$2', $tmp);
                // recycle 1
                $recycle = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8');
                $tmp = preg_replace('/' . $recycle . '\\[url\\=(\\w+.*?)\\](\\w+.*?)\\[\\/url\\]/i', $recycle . '$2', $tmp);
                // recycle 2 (test)
                $recycle = html_entity_decode("&#x25CC; ", ENT_QUOTES, 'UTF-8');
                $tmp = preg_replace('/' . $recycle . '\\[url\\=(\\w+.*?)\\](\\w+.*?)\\[\\/url\\]/i', $recycle . '$2', $tmp);
            }
            // preserve links to webpages
            $tmp = preg_replace('/\\[url\\=(https?\\:\\/\\/[a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\\$\\!\\+\\,]+)\\](\\w+.*?)\\[\\/url\\]/i', '$2 $1', $tmp);
            $tmp = preg_replace('/\\[zrl\\=(https?\\:\\/\\/[a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\\$\\!\\+\\,]+)\\](\\w+.*?)\\[\\/zrl\\]/i', '$2 $1', $tmp);
            // find all http or https links in the body of the entry and
            // apply the shortener if the link is longer then 20 characters
            if (strlen($tmp) > $max_char && $max_char > 0) {
                preg_match_all('/(https?\\:\\/\\/[a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\\$\\!\\+\\,]+)/i', $tmp, $allurls);
                foreach ($allurls as $url) {
                    foreach ($url as $u) {
                        if (strlen($u) > 20) {
                            $sl = short_link($u);
                            $tmp = str_replace($u, $sl, $tmp);
                        }
                    }
                }
            }
            // ok, all the links we want to send out are save, now strip
            // away the remaining bbcode
            $msg = bbcode($tmp, false, false, true);
            $msg = str_replace(array('<br>', '<br />'), "\n", $msg);
            $msg = strip_tags($msg);
            // quotes not working - let's try this
            $msg = html_entity_decode($msg);
            if (strlen($msg) > $max_char && $max_char > 0) {
                $shortlink = short_link($b['plink']);
                // the new message will be shortened such that "... $shortlink"
                // will fit into the character limit
                $msg = nl2br(substr($msg, 0, $max_char - strlen($shortlink) - 4));
                $msg = str_replace(array('<br>', '<br />'), ' ', $msg);
                $e = explode(' ', $msg);
                //  remove the last word from the cut down message to
                //  avoid sending cut words to the MicroBlog
                array_pop($e);
                $msg = implode(' ', $e);
                $msg .= '... ' . $shortlink;
            }
            $msg = trim($msg);
            $postdata = array('status' => $msg);
        } else {
            $msgarr = statusnet_shortenmsg($b, $max_char);
            $msg = $msgarr["msg"];
            $image = $msgarr["image"];
            if ($image != "") {
                $x = z_fetch_url($image, true, 0, array('novalidate' => true));
                if ($x['success']) {
                    $imagedata = $x['body'];
                    $tempfile = tempnam(get_config("system", "temppath"), "upload");
                    file_put_contents($tempfile, $imagedata);
                    $postdata = array("status" => $msg, "media" => "@" . $tempfile);
                }
            } else {
                $postdata = array("status" => $msg);
            }
        }
        // and now dent it :-)
        if (strlen($msg)) {
            $result = $dent->post('statuses/update', $postdata);
            logger('statusnet_post send, result: ' . print_r($result, true) . "\nmessage: " . $msg, LOGGER_DEBUG);
            logger("Original post: " . print_r($b, true) . "\nPost Data: " . print_r($postdata, true), LOGGER_DEBUG);
            if ($result->error) {
                logger('Send to GNU social failed: queued."' . $result->error . '"');
                // @fixme - unable to queue media uploads
                if (!$image) {
                    queue_insert(array('hash' => random_string(), 'account_id' => $b['aid'], 'channel_id' => $b['uid'], 'driver' => 'statusnet', 'posturl' => $api, 'msg' => $msg));
                }
            }
        }
        if ($tempfile != "") {
            unlink($tempfile);
        }
    }
}
function libertree_send(&$a, &$b)
{
    if (!is_item_normal($b) || $b['item_private'] || $b['created'] !== $b['edited']) {
        return;
    }
    if (!perm_is_allowed($b['uid'], '', 'view_stream')) {
        return;
    }
    if (!strstr($b['postopts'], 'libertree')) {
        return;
    }
    if ($b['parent'] != $b['id']) {
        return;
    }
    logger('libertree xpost invoked');
    $ltree_api_token = get_pconfig($b['uid'], 'libertree', 'libertree_api_token');
    $ltree_url = get_pconfig($b['uid'], 'libertree', 'libertree_url');
    $ltree_blog = "{$ltree_url}/api/v1/posts/create/?token={$ltree_api_token}";
    $ltree_source = "[" . $a->config['system']['sitename'] . "](" . $a->get_baseurl() . ")";
    // $ltree_source = "RedMatrix";
    logger('sitename: ' . print_r($ltree_source, true));
    if ($ltree_url && $ltree_api_token && $ltree_blog && $ltree_source) {
        require_once 'include/bb2diaspora.php';
        $tag_arr = array();
        $tags = '';
        $x = preg_match_all('/\\#\\[(.*?)\\](.*?)\\[/', $b['tag'], $matches, PREG_SET_ORDER);
        if ($x) {
            foreach ($matches as $mtch) {
                $tag_arr[] = $mtch[2];
            }
        }
        if (count($tag_arr)) {
            $tags = implode(',', $tag_arr);
        }
        $title = $b['title'];
        $body = $b['body'];
        // Insert a newline before and after a quote
        $body = str_ireplace("[quote", "\n\n[quote", $body);
        $body = str_ireplace("[/quote]", "[/quote]\n\n", $body);
        // Removal of tags and mentions
        // #-tags
        $body = preg_replace('/#\\[url\\=(\\w+.*?)\\](\\w+.*?)\\[\\/url\\]/i', '#$2', $body);
        // @-mentions
        $body = preg_replace('/@\\[url\\=(\\w+.*?)\\](\\w+.*?)\\[\\/url\\]/i', '@$2', $body);
        // remove multiple newlines
        do {
            $oldbody = $body;
            $body = str_replace("\n\n\n", "\n\n", $body);
        } while ($oldbody != $body);
        // convert to markdown
        $body = bb2diaspora($body, false, false);
        // Adding the title
        if (strlen($title)) {
            $body = "## " . html_entity_decode($title) . "\n\n" . $body;
        }
        $params = array('text' => $body, 'source' => $ltree_source);
        $level = 0;
        $result = z_post_url($ltree_blog, $params, $level, array('novalidate' => true));
        logger('libertree: ' . print_r($result, true));
    }
}
Beispiel #9
0
function pumpio_send(&$a, &$b)
{
    if (!is_item_normal($b) || $b['item_private'] || $b['created'] !== $b['edited']) {
        return;
    }
    if (!perm_is_allowed($b['uid'], '', 'view_stream')) {
        return;
    }
    if (!strstr($b['postopts'], 'pumpio')) {
        return;
    }
    if ($b['parent'] != $b['id']) {
        return;
    }
    // if post comes from pump.io don't send it back
    if ($b['app'] == "pump.io") {
        return;
    }
    $oauth_token = get_pconfig($b['uid'], "pumpio", "oauth_token");
    $oauth_token_secret = get_pconfig($b['uid'], "pumpio", "oauth_token_secret");
    $consumer_key = get_pconfig($b['uid'], "pumpio", "consumer_key");
    $consumer_secret = get_pconfig($b['uid'], "pumpio", "consumer_secret");
    $host = get_pconfig($b['uid'], "pumpio", "host");
    $user = get_pconfig($b['uid'], "pumpio", "user");
    $public = get_pconfig($b['uid'], "pumpio", "public");
    if ($oauth_token && $oauth_token_secret) {
        require_once 'include/bbcode.php';
        $title = trim($b['title']);
        if ($title != '') {
            $title = "<h4>" . $title . "</h4>";
        }
        $params = array();
        $params["verb"] = "post";
        $params["object"] = array('objectType' => "note", 'content' => $title . bbcode($b['body'], false, false));
        if ($public) {
            $params["to"] = array(array("objectType" => "collection", "id" => "http://activityschema.org/collection/public"));
        }
        $client = new oauth_client_class();
        $client->oauth_version = '1.0a';
        $client->url_parameters = false;
        $client->authorization_header = true;
        $client->access_token = $oauth_token;
        $client->access_token_secret = $oauth_token_secret;
        $client->client_id = $consumer_key;
        $client->client_secret = $consumer_secret;
        $success = $client->CallAPI('https://' . $host . '/api/user/' . $user . '/feed', 'POST', $params, array('FailOnAccessError' => true, 'RequestContentType' => 'application/json'), $user);
        if ($success) {
            logger('pumpio_send: success');
        } else {
            logger('pumpio_send: general error: ' . print_r($user, true));
        }
    }
}