From 6fbb03801c7a5a3c6daaab52d603dffbadd8ff98 Mon Sep 17 00:00:00 2001
From: Michael Vogel <icarus@dabo.de>
Date: Sat, 20 Jun 2015 08:44:29 +0200
Subject: [PATCH 01/11] The OStatus completion is now called before the
 original item is stored.

---
 include/items.php                |   5 +-
 include/ostatus.php              |  33 +--
 include/ostatus_conversation.php | 343 +++++++++++++++++++++----------
 3 files changed, 259 insertions(+), 122 deletions(-)

diff --git a/include/items.php b/include/items.php
index fa370c82a8..b085ac8cfa 100644
--- a/include/items.php
+++ b/include/items.php
@@ -1192,12 +1192,15 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
 	// If there is no guid then take the same guid that was taken before for the same plink
 	if ((trim($arr['guid']) == "") AND (trim($arr['plink']) != "") AND (trim($arr['network']) != "")) {
 		logger('item_store: checking for an existing guid for plink '.$arr['plink'], LOGGER_DEBUG);
-		$r = q("SELECT `guid` FROM `guid` WHERE `plink` = '%s' AND `network` = '%s' LIMIT 1",
+		$r = q("SELECT `guid`, `uri` FROM `guid` WHERE `plink` = '%s' AND `network` = '%s' LIMIT 1",
 			dbesc(trim($arr['plink'])), dbesc(trim($arr['network'])));
 
 		if(count($r)) {
 			$arr['guid'] = $r[0]["guid"];
 			logger('item_store: found guid '.$arr['guid'].' for plink '.$arr['plink'], LOGGER_DEBUG);
+
+			if ($r[0]["uri"] != $arr['uri'])
+			logger('Different uri for same guid: '.$arr['uri'].' and '.$r[0]["uri"].' - this shouldnt happen!', LOGGER_DEBUG);
 		}
 	}
 
diff --git a/include/ostatus.php b/include/ostatus.php
index 86d0e36dbe..996cbea1fd 100644
--- a/include/ostatus.php
+++ b/include/ostatus.php
@@ -186,6 +186,7 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 
 		$item["body"] = add_page_info_to_body(html2bbcode($xpath->query('atom:content/text()', $entry)->item(0)->nodeValue));
 		$item["object-type"] = $xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue;
+		$item["object"] = $xml;
 		$item["verb"] = $xpath->query('activity:verb/text()', $entry)->item(0)->nodeValue;
 
 		if ($item["verb"] == ACTIVITY_FOLLOW) {
@@ -218,6 +219,9 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 		if ($georsspoint)
 			$item["coord"] = $georsspoint->item(0)->nodeValue;
 
+		// To-Do
+		// $item["location"] =
+
 		$categories = $xpath->query('atom:category', $entry);
 		if ($categories) {
 			foreach ($categories AS $category) {
@@ -292,7 +296,7 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 		$repeat_of = "";
 
 		$notice_info = $xpath->query('statusnet:notice_info', $entry);
-		if ($notice_info)
+		if ($notice_info AND ($notice_info->length > 0)) {
 			foreach($notice_info->item(0)->attributes AS $attributes) {
 				if ($attributes->name == "source")
 					$item["app"] = strip_tags($attributes->textContent);
@@ -301,6 +305,7 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 				if ($attributes->name == "repeat_of")
 					$repeat_of = $attributes->textContent;
 			}
+		}
 
 		// Is it a repeated post?
 		if ($repeat_of != "") {
@@ -376,12 +381,19 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 		} else
 			$item["parent-uri"] = $item["uri"];
 
-		// We risk the chance of getting orphan items, we correct it some lines later
-		// To-Do: See To-Do line below.
-		$item_id = item_store($item, true);
+		$item_id = ostatus_completion($conversation, $importer["uid"], $item);
+
+		if ($item_id <= 0) {
+			$reason = $item_id;
+			$item["app"] .= $item_id;
+			$item_id = item_store($item, true);
+			if ($item_id) {
+				logger("Shouldn't happen. Code ".$reason." - uri ".$item["uri"], LOGGER_DEBUG);
+				complete_conversation($item_id, $conversation_url, true);
+			}
+		}
 		//echo $xml;
 		//print_r($item);
-		//echo $item_id." ".$item["parent-uri"]."\n";
 
 		if (!$item_id) {
 			logger("Error storing item ".print_r($item, true), LOGGER_DEBUG);
@@ -414,16 +426,5 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 				'parent'       => $item["parent"]
 			));
 		}
-
-		if ($conversation != "") {
-			// Check for duplicates. We really don't need to check the same conversation twice.
-			if (!in_array($conversation, $conversationlist)) {
-				// To-Do:
-				// Call this before item_store is called to avoid posts with orphans
-				// The routine then needs to get the item array.
-				complete_conversation($item_id, $conversation);
-				$conversationlist[] = $conversation;
-			}
-		}
 	}
 }
diff --git a/include/ostatus_conversation.php b/include/ostatus_conversation.php
index e61f5fab4f..fd90ba3dd1 100644
--- a/include/ostatus_conversation.php
+++ b/include/ostatus_conversation.php
@@ -1,6 +1,8 @@
 <?php
 require_once("include/Contact.php");
 require_once("include/threads.php");
+require_once("include/html2bbcode.php");
+require_once("include/items.php");
 
 define('OSTATUS_DEFAULT_POLL_INTERVAL', 30); // given in minutes
 define('OSTATUS_DEFAULT_POLL_TIMEFRAME', 1440); // given in minutes
@@ -29,50 +31,51 @@ function ostatus_convert_href($href) {
 }
 
 function check_conversations($override = false) {
-        $last = get_config('system','ostatus_last_poll');
+	$last = get_config('system','ostatus_last_poll');
 
-        $poll_interval = intval(get_config('system','ostatus_poll_interval'));
-        if(! $poll_interval)
-                $poll_interval = OSTATUS_DEFAULT_POLL_INTERVAL;
+	$poll_interval = intval(get_config('system','ostatus_poll_interval'));
+	if(! $poll_interval)
+		$poll_interval = OSTATUS_DEFAULT_POLL_INTERVAL;
 
 	// Don't poll if the interval is set negative
 	if (($poll_interval < 0) AND !$override)
 		return;
 
-        $poll_timeframe = intval(get_config('system','ostatus_poll_timeframe'));
-        if (!$poll_timeframe)
-                $poll_timeframe = OSTATUS_DEFAULT_POLL_TIMEFRAME;
+	$poll_timeframe = intval(get_config('system','ostatus_poll_timeframe'));
+	if (!$poll_timeframe)
+		$poll_timeframe = OSTATUS_DEFAULT_POLL_TIMEFRAME;
 
-        if ($last AND !$override) {
-                $next = $last + ($poll_interval * 60);
-                if ($next > time()) {
-                        logger('poll interval not reached');
-                        return;
-                }
-        }
+	if ($last AND !$override) {
+		$next = $last + ($poll_interval * 60);
+		if ($next > time()) {
+			logger('poll interval not reached');
+			return;
+		}
+	}
 
-        logger('cron_start');
+	logger('cron_start');
 
-        $start = date("Y-m-d H:i:s", time() - ($poll_timeframe * 60));
-        $conversations = q("SELECT `oid`, `url` FROM `term` WHERE `type` = 7 AND `term` > '%s' GROUP BY `url` ORDER BY `term` DESC",
-                                dbesc($start));
+	$start = date("Y-m-d H:i:s", time() - ($poll_timeframe * 60));
+	$conversations = q("SELECT `oid`, `url`, `uid` FROM `term` WHERE `type` = 7 AND `term` > '%s' GROUP BY `url`, `uid` ORDER BY `term` DESC",
+				dbesc($start));
 
-        foreach ($conversations AS $conversation) {
-                $id = $conversation['oid'];
-                $url = $conversation['url'];
-                complete_conversation($id, $url);
-        }
+	foreach ($conversations AS $conversation) {
+		ostatus_completion($conversation['url'], $conversation['uid']);
+	}
 
-        logger('cron_end');
+	logger('cron_end');
 
-        set_config('system','ostatus_last_poll', time());
+	set_config('system','ostatus_last_poll', time());
 }
 
-function complete_conversation($itemid, $conversation_url, $only_add_conversation = false) {
-	global $a;
+function ostatus_completion($conversation_url, $uid, $item = array()) {
+
+	$item_stored = -3;
 
 	$conversation_url = ostatus_convert_href($conversation_url);
 
+/*
+To-Do:
 	if (intval(get_config('system','ostatus_poll_interval')) == -2)
 		return;
 
@@ -81,43 +84,56 @@ function complete_conversation($itemid, $conversation_url, $only_add_conversatio
 
 	$a->last_ostatus_conversation_url = $conversation_url;
 
-	$messages = q("SELECT `uid`, `parent`, `created`, `received`, `guid` FROM `item` WHERE `id` = %d LIMIT 1", intval($itemid));
-	if (!$messages)
-		return;
-	$message = $messages[0];
-
-	// Store conversation url if not done before
-	$conversation = q("SELECT `url` FROM `term` WHERE `uid` = %d AND `oid` = %d AND `otype` = %d AND `type` = %d",
-		intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION));
-
-	if (!$conversation) {
-		$r = q("INSERT INTO `term` (`uid`, `oid`, `otype`, `type`, `term`, `url`, `created`, `received`, `guid`) VALUES (%d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s')",
-			intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION),
-			dbesc($message["created"]), dbesc($conversation_url), dbesc($message["created"]), dbesc($message["received"]), dbesc($message["guid"]));
-		logger('Storing conversation url '.$conversation_url.' for id '.$itemid);
-	}
-
-	if ($only_add_conversation)
-		return;
+*/
 
 	// Get the parent
-	$parents = q("SELECT `id`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1",
-			intval($message["uid"]), intval($message["parent"]));
-	if (!$parents)
-		return;
-	$parent = $parents[0];
+	$parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `id` IN
+			(SELECT `parent` FROM `item` WHERE `id` IN
+				(SELECT `oid` FROM `term` WHERE `uid` = %d AND `otype` = %d AND `type` = %d AND `url` = '%s'))",
+			intval($uid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION), dbesc($conversation_url));
 
-	require_once('include/html2bbcode.php');
-	require_once('include/items.php');
+	if ($parents)
+		$parent = $parents[0];
+	elseif (count($item) > 0) {
+		$parent = $item;
+		$parent["type"] = "remote";
+		$parent["verb"] = ACTIVITY_POST;
+		$parent["visible"] = 1;
+	} else {
+		// Preset the parent
+		$r = q("SELECT `id` FROM `contact` WHERE `self` AND `uid`=%d", $uid);
+		if (!$r)
+			return(-1);
+
+		$parent = array();
+		$parent["id"] = 0;
+		$parent["parent"] = 0;
+		$parent["uri"] = "";
+		$parent["contact-id"] = $r[0]["id"];
+		$parent["type"] = "remote";
+		$parent["verb"] = ACTIVITY_POST;
+		$parent["visible"] = 1;
+	}
 
 	$conv = str_replace("/conversation/", "/api/statusnet/conversation/", $conversation_url).".as";
 	$pageno = 1;
 	$items = array();
 
-	logger('fetching conversation url '.$conv.' for id '.$itemid.' and parent '.$parent["id"]);
+	logger('fetching conversation url '.$conv.' for user '.$uid);
 
 	do {
-		$conv_as = fetch_url($conv."?page=".$pageno);
+		$conv_arr = z_fetch_url($conv."?page=".$pageno);
+
+		// If it is a non-ssl site and there is an error, then try ssl or vice versa
+		if (!$conv_arr["success"] AND (substr($conv, 0, 7) == "http://")) {
+			$conv = str_replace("http://", "https://", $conv);
+			$conv_as = fetch_url($conv."?page=".$pageno);
+		} elseif (!$conv_arr["success"] AND (substr($conv, 0, 8) == "https://")) {
+			$conv = str_replace("https://", "http://", $conv);
+			$conv_as = fetch_url($conv."?page=".$pageno);
+		} else
+			$conv_as = $conv_arr["body"];
+
 		$conv_as = str_replace(',"statusnet:notice_info":', ',"statusnet_notice_info":', $conv_as);
 		$conv_as = json_decode($conv_as);
 
@@ -130,69 +146,102 @@ function complete_conversation($itemid, $conversation_url, $only_add_conversatio
 
 	} while (true);
 
-	if (!sizeof($items))
-		return;
+	logger('fetching conversation done. Found '.count($items).' items');
+
+	if (!sizeof($items)) {
+		if (count($item) > 0) {
+			$item_stored = item_store($item, true);
+			logger("Conversation ".$conversation_url." couldn't be fetched. Item uri ".$item["uri"]." stored: ".$item_stored, LOGGER_DEBUG);
+
+			if ($item_stored)
+				complete_conversation($item_id, $conversation_url, true);
+
+			return($item_stored);
+		} else
+			return(-2);
+	}
 
 	$items = array_reverse($items);
 
 	foreach ($items as $single_conv) {
+
+		// Test - remove before flight
+		//$tempfile = tempnam(get_temppath(), "conversation");
+		//file_put_contents($tempfile, json_encode($single_conv));
+
+
 		if (isset($single_conv->object->id))
 			$single_conv->id = $single_conv->object->id;
 
-		//logger("Got id ".$single_conv->id, LOGGER_DEBUG);
-
 		$plink = ostatus_convert_href($single_conv->id);
 		if (isset($single_conv->object->url))
 			$plink = ostatus_convert_href($single_conv->object->url);
 
-		//logger("Got url ".$plink, LOGGER_DEBUG);
-
 		if (@!$single_conv->id)
 			continue;
 
+		logger("Got id ".$single_conv->id, LOGGER_DEBUG);
+
 		if ($first_id == "") {
 			$first_id = $single_conv->id;
 
-			$new_parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1",
-				intval($message["uid"]), dbesc($first_id),
-				dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
-			if ($new_parents) {
-				// It can happen that OStatus servers have incomplete threads.
-				// Then keep the current parent
-				if ($parent["id"] == $parent["parent"]) {
-					$parent = $new_parents[0];
-
-					if ($parent["id"] != $message["parent"])
-						logger('Fetch new parent id '.$parent["id"].' - Old parent: '.$message["parent"]);
+			// The first post of the conversation isn't our first post. There are three options:
+			// 1. Our conversation hasn't the "real" thread starter
+			// 2. This first post is a post inside our thread
+			// 3. This first post is a post inside another thread
+			if (($first_id != $parent["uri"]) AND ($parent["uri"] != "")) {
+				$new_parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `id` IN
+							(SELECT `parent` FROM `item`
+								WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s')) LIMIT 1",
+					intval($uid), dbesc($first_id), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
+				if ($new_parents) {
+					if ($new_parents[0]["parent"] == $parent["parent"]) {
+						// Option 2: This post is already present inside our thread - but not as thread starter
+						logger("Option 2: uri present in our thread: ".$first_id, LOGGER_DEBUG);
+						$first_id = $parent["uri"];
+					} else {
+						// Option 3: Not so good. We have mixed parents. We have to see how to clean this up.
+						// For now just take the new parent.
+						$parent = $new_parents[0];
+						$first_id = $parent["uri"];
+						logger("Option 3: mixed parents for uri ".$first_id, LOGGER_DEBUG);
+					}
 				} else {
-					$first_id = $parent["uri"];
-					//logger('Keep parent for '.$itemid.' - Old parent: '.$message["parent"]);
+					// Option 1: We hadn't got the real thread starter
+					// We have to clean up our existing messages.
+					$parent["id"] = 0;
+					$parent["uri"] = $first_id;
+					logger("Option 1: we have a new parent: ".$first_id, LOGGER_DEBUG);
 				}
-			} else {
+			} elseif ($parent["uri"] == "") {
 				$parent["id"] = 0;
 				$parent["uri"] = $first_id;
 			}
 		}
 
-		if (isset($single_conv->context->inReplyTo->id))
+		if (isset($single_conv->context->inReplyTo->id)) {
 			$parent_uri = $single_conv->context->inReplyTo->id;
-		else
+
+			$parent_exists = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1",
+						intval($uid), dbesc($parent_uri), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
+			if (!$parent_exists) {
+				logger("Parent ".$parent_uri." wasn't found here", LOGGER_DEBUG);
+				$parent_uri = $parent["uri"];
+			}
+		} else
 			$parent_uri = $parent["uri"];
 
-		$message_exists = q("SELECT `id`, `parent` FROM `item` WHERE `uid` = %d AND `plink` = '%s' AND `network` IN ('%s','%s') LIMIT 1",
-							intval($message["uid"]), dbesc($plink),
-							dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
-
-		if (!$message_exists)
-			$message_exists = q("SELECT `id`, `parent` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1",
-							intval($message["uid"]), dbesc($single_conv->id),
-							dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
-
+		$message_exists = q("SELECT `id`, `parent`, `uri` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1",
+						intval($uid), dbesc($single_conv->id),
+						dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
 		if ($message_exists) {
+			logger("Message ".$single_conv->id." already existed on the system", LOGGER_DEBUG);
+
 			if ($parent["id"] != 0) {
 				$existing_message = $message_exists[0];
 
 				// We improved the way we fetch OStatus messages, this shouldn't happen very often now
+				// To-Do: we have to change the shadow copies as well. This way here is really ugly.
 				if ($existing_message["parent"] != $parent["id"]) {
 					logger('updating id '.$existing_message["id"].' with parent '.$existing_message["parent"].' to parent '.$parent["id"].' uri '.$parent["uri"].' thread '.$parent_uri, LOGGER_DEBUG);
 
@@ -216,6 +265,13 @@ function complete_conversation($itemid, $conversation_url, $only_add_conversatio
 					delete_thread($existing_message["parent"]);
 				}
 			}
+
+			// The item we are having on the system is the one that we wanted to store via the item array
+			if (isset($item["uri"]) AND ($item["uri"] == $existing_message["uri"])) {
+				$item = array();
+				$item_stored = 0;
+			}
+
 			continue;
 		}
 
@@ -224,7 +280,7 @@ function complete_conversation($itemid, $conversation_url, $only_add_conversatio
 			$actor = $single_conv->actor->url;
 
 		$contact = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s' AND `network` != '%s'",
-				$message["uid"], normalise_link($actor), NETWORK_STATUSNET);
+				$uid, normalise_link($actor), NETWORK_STATUSNET);
 
 		if (count($contact)) {
 			logger("Found contact for url ".$actor, LOGGER_DEBUG);
@@ -245,29 +301,19 @@ function complete_conversation($itemid, $conversation_url, $only_add_conversatio
 		$arr["network"] = NETWORK_OSTATUS;
 		$arr["uri"] = $single_conv->id;
 		$arr["plink"] = $plink;
-		$arr["uid"] = $message["uid"];
+		$arr["uid"] = $uid;
 		$arr["contact-id"] = $contact_id;
-		if ($parent["id"] != 0)
-			$arr["parent"] = $parent["id"];
-		$arr["parent-uri"] = $parent["uri"];
-		$arr["thr-parent"] = $parent_uri;
+		$arr["parent-uri"] = $parent_uri;
 		$arr["created"] = $single_conv->published;
 		$arr["edited"] = $single_conv->published;
-		$arr["owner-name"] = $single_conv->actor->contact->displayName;
-		//$arr["owner-name"] = $single_conv->actor->contact->preferredUsername;
+		$arr["owner-name"] = $single_conv->actor->displayName;
+		if ($arr["owner-name"] == '')
+			$arr["owner-name"] = $single_conv->actor->contact->displayName;
 		if ($arr["owner-name"] == '')
 			$arr["owner-name"] = $single_conv->actor->portablecontacts_net->displayName;
-		if ($arr["owner-name"] == '')
-			$arr["owner-name"] = $single_conv->actor->displayName;
-		if ($arr["owner-name"] == '')
-			$arr["owner-name"] = $single_conv->actor->portablecontacts_net->preferredUsername;
-		if ($arr["owner-name"] == '')
-			$arr["owner-name"] = $single_conv->actor->preferredUsername;
 
 		$arr["owner-link"] = $actor;
 		$arr["owner-avatar"] = $single_conv->actor->image->url;
-		//$arr["author-name"] = $single_conv->actor->contact->displayName;
-		//$arr["author-name"] = $single_conv->actor->contact->preferredUsername;
 		$arr["author-name"] = $arr["owner-name"];
 		$arr["author-link"] = $actor;
 		$arr["author-avatar"] = $single_conv->actor->image->url;
@@ -284,33 +330,120 @@ function complete_conversation($itemid, $conversation_url, $only_add_conversatio
 		else
 			$arr["app"] = "OStatus";
 
+		$arr["app"] .= "*";
+
+		$arr["object"] = json_encode($single_conv);
 		$arr["verb"] = $parent["verb"];
 		$arr["visible"] = $parent["visible"];
 		$arr["location"] = $single_conv->location->displayName;
 		$arr["coord"] = trim($single_conv->location->lat." ".$single_conv->location->lon);
 
+		// Is it a reshared item?
+		if (isset($item->verb) AND ($item->verb == "share") AND isset($item->object)) {
+			if (is_array($item->object))
+				$item->object = $item->object[0];
+
+			logger("Found reshared item ".$single_conv->object->id);
+
+			// $single_conv->object->context->conversation;
+
+			$plink = ostatus_convert_href($single_conv->object->url);
+
+			$arr["uri"] = $single_conv->object->id;
+			$arr["plink"] = $plink;
+			$arr["created"] = $single_conv->object->published;
+			$arr["edited"] = $single_conv->object->published;
+
+			$arr["author-name"] = $single_conv->object->actor->displayName;
+			if ($arr["owner-name"] == '')
+				$arr["author-name"] = $single_conv->object->actor->contact->displayName;
+
+			$arr["author-link"] = $single_conv->object->actor->url;
+			$arr["author-avatar"] = $single_conv->object->actor->image->url;
+
+			$arr["body"] = add_page_info_to_body(html2bbcode($single_conv->object->content));
+			$arr["app"] = $single_conv->object->provider->displayName."#";
+			//$arr["verb"] = $single_conv->object->verb;
+
+			$arr["location"] = $single_conv->object->location->displayName;
+			$arr["coord"] = trim($single_conv->object->location->lat." ".$single_conv->object->location->lon);
+		}
+
 		if ($arr["location"] == "")
 			unset($arr["location"]);
 
 		if ($arr["coord"] == "")
 			unset($arr["coord"]);
 
-		$newitem = item_store($arr);
+		// Copy fields from given item array
+		if (isset($item["uri"]) AND ($item["uri"] == $arr["uri"])) {
+			$copy_fields = array("owner-name", "owner-link", "owner-avatar", "author-name", "author-link", "author-avatar",
+						"gravity", "body", "object-type", "verb", "created", "edited", "coord", "tag",
+						"attach", "app", "type", "location", "contact-id");
+			foreach ($copy_fields AS $field)
+				if (isset($item[$field]))
+					$arr[$field] = $item[$field];
 
-		logger('Stored new item '.$plink.' for parent '.$arr["parent"].' under id '.$newitem, LOGGER_DEBUG);
+			$arr["app"] .= "+";
+		}
+
+		$newitem = item_store($arr);
+		if (!$newitem) {
+			logger("Item wasn't stored ".print_r($arr, true), LOGGER_DEBUG);
+			continue;
+		}
+
+		if (isset($item["uri"]) AND ($item["uri"] == $arr["uri"])) {
+			$item = array();
+			$item_stored = $newitem;
+		}
+
+		logger('Stored new item '.$plink.' for parent '.$arr["parent-uri"].' under id '.$newitem, LOGGER_DEBUG);
 
 		// Add the conversation entry (but don't fetch the whole conversation)
 		complete_conversation($newitem, $conversation_url, true);
 
 		// If the newly created item is the top item then change the parent settings of the thread
 		// This shouldn't happen anymore. This is supposed to be absolote.
-		if ($newitem AND ($arr["uri"] == $first_id)) {
+		if ($arr["uri"] == $first_id) {
 			logger('setting new parent to id '.$newitem);
 			$new_parents = q("SELECT `id`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1",
-				intval($message["uid"]), intval($newitem));
+				intval($uid), intval($newitem));
 			if ($new_parents)
 				$parent = $new_parents[0];
 		}
 	}
+// Test
+/*	if ((count($item) > 0) AND ($item_stored <= 0)) {
+		$item_stored = item_store($item, true);
+		logger("In the conversation ".$conversation_url." the item uri ".$item["uri"]." wasn't found: ".$item_stored, LOGGER_DEBUG);
+
+		if ($item_stored)
+			complete_conversation($item_id, $conversation_url, true);
+	} */
+
+	return($item_stored);
+}
+
+function complete_conversation($itemid, $conversation_url, $only_add_conversation = false) {
+	global $a;
+
+	$conversation_url = ostatus_convert_href($conversation_url);
+
+	$messages = q("SELECT `uid`, `parent`, `created`, `received`, `guid` FROM `item` WHERE `id` = %d LIMIT 1", intval($itemid));
+	if (!$messages)
+		return;
+	$message = $messages[0];
+
+	// Store conversation url if not done before
+	$conversation = q("SELECT `url` FROM `term` WHERE `uid` = %d AND `oid` = %d AND `otype` = %d AND `type` = %d",
+		intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION));
+
+	if (!$conversation) {
+		$r = q("INSERT INTO `term` (`uid`, `oid`, `otype`, `type`, `term`, `url`, `created`, `received`, `guid`) VALUES (%d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s')",
+			intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION),
+			dbesc($message["created"]), dbesc($conversation_url), dbesc($message["created"]), dbesc($message["received"]), dbesc($message["guid"]));
+		logger('Storing conversation url '.$conversation_url.' for id '.$itemid);
+	}
 }
 ?>

From 168906f9c9b3792462a0d494c15a186042239c0b Mon Sep 17 00:00:00 2001
From: Michael Vogel <icarus@dabo.de>
Date: Sat, 20 Jun 2015 09:15:19 +0200
Subject: [PATCH 02/11] Code cleanup

---
 include/items.php                | 32 --------------------------------
 include/ostatus.php              |  2 +-
 include/ostatus_conversation.php | 30 ++++++++----------------------
 3 files changed, 9 insertions(+), 55 deletions(-)

diff --git a/include/items.php b/include/items.php
index b085ac8cfa..7a30130bbc 100644
--- a/include/items.php
+++ b/include/items.php
@@ -9,7 +9,6 @@ require_once('include/tags.php');
 require_once('include/files.php');
 require_once('include/text.php');
 require_once('include/email.php');
-//require_once('include/ostatus_conversation.php');
 require_once('include/threads.php');
 require_once('include/socgraph.php');
 require_once('include/plaintext.php');
@@ -481,7 +480,6 @@ function get_atom_elements($feed, $item, $contact = array()) {
 	// but for now let's just find any author photo
 	// Additionally we look for an alternate author link. On OStatus this one is the one we want.
 
-	// Search for ostatus conversation url
 	$authorlinks = $item->feed->data["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["feed"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["author"][0]["child"]["http://www.w3.org/2005/Atom"]["link"];
 	if (is_array($authorlinks)) {
 		foreach ($authorlinks as $link) {
@@ -886,23 +884,6 @@ function get_atom_elements($feed, $item, $contact = array()) {
 		}
 	}
 
-//	// Search for ostatus conversation url
-//	$links = $item->feed->data["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["feed"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["entry"][0]["child"]["http://www.w3.org/2005/Atom"]["link"];
-//
-//	if (is_array($links)) {
-//		foreach ($links as $link) {
-//			$conversation = array_shift($link["attribs"]);
-//
-//			if ($conversation["rel"] == "ostatus:conversation") {
-//				$res["ostatus_conversation"] = ostatus_convert_href($conversation["href"]);
-//				logger('get_atom_elements: found conversation url '.$res["ostatus_conversation"]);
-//			//} elseif ($conversation["rel"] == "alternate") {
-//			//	$res["plink"] = $conversation["href"];
-//			//	logger('get_atom_elements: found plink '.$res["plink"]);
-//			}
-//		};
-//	}
-
 	if (isset($contact["network"]) AND ($contact["network"] == NETWORK_FEED) AND $contact['fetch_further_information']) {
 		$preview = "";
 
@@ -1139,15 +1120,6 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
 			$arr['plink'] = ostatus_convert_href($arr['uri']);
 	}
 
-//	// if an OStatus conversation url was passed in, it is stored and then
-//	// removed from the array.
-//	$ostatus_conversation = null;
-
-//	if (isset($arr["ostatus_conversation"])) {
-//		$ostatus_conversation = $arr["ostatus_conversation"];
-//		unset($arr["ostatus_conversation"]);
-//	}
-
 	if(x($arr, 'gravity'))
 		$arr['gravity'] = intval($arr['gravity']);
 	elseif($arr['parent-uri'] === $arr['uri'])
@@ -1540,10 +1512,6 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
 		intval($current_post)
 	);
 
-	// Complete ostatus threads
-	//if ($ostatus_conversation)
-	//	complete_conversation($current_post, $ostatus_conversation);
-
 	$arr['id'] = $current_post;
 	$arr['parent'] = $parent_id;
 	$arr['allow_cid'] = $allow_cid;
diff --git a/include/ostatus.php b/include/ostatus.php
index 996cbea1fd..bf88efab9a 100644
--- a/include/ostatus.php
+++ b/include/ostatus.php
@@ -389,7 +389,7 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 			$item_id = item_store($item, true);
 			if ($item_id) {
 				logger("Shouldn't happen. Code ".$reason." - uri ".$item["uri"], LOGGER_DEBUG);
-				complete_conversation($item_id, $conversation_url, true);
+				complete_conversation($item_id, $conversation_url);
 			}
 		}
 		//echo $xml;
diff --git a/include/ostatus_conversation.php b/include/ostatus_conversation.php
index fd90ba3dd1..03678cbb4a 100644
--- a/include/ostatus_conversation.php
+++ b/include/ostatus_conversation.php
@@ -74,17 +74,11 @@ function ostatus_completion($conversation_url, $uid, $item = array()) {
 
 	$conversation_url = ostatus_convert_href($conversation_url);
 
-/*
-To-Do:
-	if (intval(get_config('system','ostatus_poll_interval')) == -2)
-		return;
-
-	if ($a->last_ostatus_conversation_url == $conversation_url)
-		return;
-
-	$a->last_ostatus_conversation_url = $conversation_url;
-
-*/
+	// If the thread shouldn't be completed then store the item and go away
+	if ((intval(get_config('system','ostatus_poll_interval')) == -2) AND (count($item) > 0)) {
+		$item_stored = item_store($item, true);
+		return($item_stored);
+	}
 
 	// Get the parent
 	$parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `id` IN
@@ -154,7 +148,7 @@ To-Do:
 			logger("Conversation ".$conversation_url." couldn't be fetched. Item uri ".$item["uri"]." stored: ".$item_stored, LOGGER_DEBUG);
 
 			if ($item_stored)
-				complete_conversation($item_id, $conversation_url, true);
+				complete_conversation($item_id, $conversation_url);
 
 			return($item_stored);
 		} else
@@ -401,7 +395,7 @@ To-Do:
 		logger('Stored new item '.$plink.' for parent '.$arr["parent-uri"].' under id '.$newitem, LOGGER_DEBUG);
 
 		// Add the conversation entry (but don't fetch the whole conversation)
-		complete_conversation($newitem, $conversation_url, true);
+		complete_conversation($newitem, $conversation_url);
 
 		// If the newly created item is the top item then change the parent settings of the thread
 		// This shouldn't happen anymore. This is supposed to be absolote.
@@ -413,19 +407,11 @@ To-Do:
 				$parent = $new_parents[0];
 		}
 	}
-// Test
-/*	if ((count($item) > 0) AND ($item_stored <= 0)) {
-		$item_stored = item_store($item, true);
-		logger("In the conversation ".$conversation_url." the item uri ".$item["uri"]." wasn't found: ".$item_stored, LOGGER_DEBUG);
-
-		if ($item_stored)
-			complete_conversation($item_id, $conversation_url, true);
-	} */
 
 	return($item_stored);
 }
 
-function complete_conversation($itemid, $conversation_url, $only_add_conversation = false) {
+function complete_conversation($itemid, $conversation_url) {
 	global $a;
 
 	$conversation_url = ostatus_convert_href($conversation_url);

From c8430f4c44f34641953e29e65fd1e268bcc332b1 Mon Sep 17 00:00:00 2001
From: Michael Vogel <icarus@dabo.de>
Date: Sat, 20 Jun 2015 14:40:30 +0200
Subject: [PATCH 03/11] Moved all OStatus code in a single file.

---
 boot.php                         |   3 -
 include/acl_selectors.php        |   2 +-
 include/ostatus.php              | 450 ++++++++++++++++++++++++++++++-
 include/ostatus_conversation.php | 435 ------------------------------
 4 files changed, 444 insertions(+), 446 deletions(-)
 delete mode 100644 include/ostatus_conversation.php

diff --git a/boot.php b/boot.php
index 6c9c8fdc4a..0aa7ab6341 100644
--- a/boot.php
+++ b/boot.php
@@ -415,9 +415,6 @@ if(! class_exists('App')) {
 		// array of instanced template engines ('name'=>'instance')
 		public $template_engine_instance = array();
 
-		// Used for reducing load to the ostatus completion
-		public $last_ostatus_conversation_url;
-
 		private $ldelim = array(
 			'internal' => '',
 			'smarty3' => '{{'
diff --git a/include/acl_selectors.php b/include/acl_selectors.php
index b2c4b31c81..dc2f8d4164 100644
--- a/include/acl_selectors.php
+++ b/include/acl_selectors.php
@@ -422,7 +422,7 @@ function acl_lookup(&$a, $out_type = 'json') {
 				WHERE `uid` = %d AND `self` = 0
 				AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0
 				AND `notify` != '' $sql_extra2" ,
-			intval(local_user())
+			intval(local_user()),
 		);
 		$contact_count = (int)$r[0]['c'];
 	}
diff --git a/include/ostatus.php b/include/ostatus.php
index bf88efab9a..f6056170f2 100644
--- a/include/ostatus.php
+++ b/include/ostatus.php
@@ -1,11 +1,15 @@
 <?php
+require_once("include/Contact.php");
+require_once("include/threads.php");
+require_once("include/html2bbcode.php");
+require_once("include/items.php");
 require_once("mod/share.php");
-require_once('include/html2bbcode.php');
-require_once('include/enotify.php');
-require_once('include/items.php');
-require_once('include/ostatus_conversation.php');
-require_once('include/socgraph.php');
-require_once('include/Photo.php');
+require_once("include/enotify.php");
+require_once("include/socgraph.php");
+require_once("include/Photo.php");
+
+define('OSTATUS_DEFAULT_POLL_INTERVAL', 30); // given in minutes
+define('OSTATUS_DEFAULT_POLL_TIMEFRAME', 1440); // given in minutes
 
 function ostatus_fetchauthor($xpath, $context, $importer, &$contact) {
 
@@ -189,6 +193,11 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 		$item["object"] = $xml;
 		$item["verb"] = $xpath->query('activity:verb/text()', $entry)->item(0)->nodeValue;
 
+		if ($item["verb"] == ACTIVITY_JOIN) {
+			// ignore "Join" messages
+			continue;
+		}
+
 		if ($item["verb"] == ACTIVITY_FOLLOW) {
 			// ignore "Follow" messages
 			continue;
@@ -389,7 +398,7 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 			$item_id = item_store($item, true);
 			if ($item_id) {
 				logger("Shouldn't happen. Code ".$reason." - uri ".$item["uri"], LOGGER_DEBUG);
-				complete_conversation($item_id, $conversation_url);
+				ostatus_store_conversation($item_id, $conversation_url);
 			}
 		}
 		//echo $xml;
@@ -428,3 +437,430 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 		}
 	}
 }
+
+function ostatus_convert_href($href) {
+	$elements = explode(":",$href);
+
+	if ((count($elements) <= 2) OR ($elements[0] != "tag"))
+		return $href;
+
+	$server = explode(",", $elements[1]);
+	$conversation = explode("=", $elements[2]);
+
+	if ((count($elements) == 4) AND ($elements[2] == "post"))
+		return "http://".$server[0]."/notice/".$elements[3];
+
+	if ((count($conversation) != 2) OR ($conversation[1] ==""))
+		return $href;
+
+	if ($elements[3] == "objectType=thread")
+		return "http://".$server[0]."/conversation/".$conversation[1];
+	else
+		return "http://".$server[0]."/notice/".$conversation[1];
+
+	return $href;
+}
+
+function check_conversations($override = false) {
+	$last = get_config('system','ostatus_last_poll');
+
+	$poll_interval = intval(get_config('system','ostatus_poll_interval'));
+	if(! $poll_interval)
+		$poll_interval = OSTATUS_DEFAULT_POLL_INTERVAL;
+
+	// Don't poll if the interval is set negative
+	if (($poll_interval < 0) AND !$override)
+		return;
+
+	$poll_timeframe = intval(get_config('system','ostatus_poll_timeframe'));
+	if (!$poll_timeframe)
+		$poll_timeframe = OSTATUS_DEFAULT_POLL_TIMEFRAME;
+
+	if ($last AND !$override) {
+		$next = $last + ($poll_interval * 60);
+		if ($next > time()) {
+			logger('poll interval not reached');
+			return;
+		}
+	}
+
+	logger('cron_start');
+
+	$start = date("Y-m-d H:i:s", time() - ($poll_timeframe * 60));
+	$conversations = q("SELECT `oid`, `url`, `uid` FROM `term` WHERE `type` = 7 AND `term` > '%s' GROUP BY `url`, `uid` ORDER BY `term` DESC",
+				dbesc($start));
+
+	foreach ($conversations AS $conversation) {
+		ostatus_completion($conversation['url'], $conversation['uid']);
+	}
+
+	logger('cron_end');
+
+	set_config('system','ostatus_last_poll', time());
+}
+
+function ostatus_completion($conversation_url, $uid, $item = array()) {
+
+	$item_stored = -3;
+
+	$conversation_url = ostatus_convert_href($conversation_url);
+
+	// If the thread shouldn't be completed then store the item and go away
+	if ((intval(get_config('system','ostatus_poll_interval')) == -2) AND (count($item) > 0)) {
+		$item_stored = item_store($item, true);
+		return($item_stored);
+	}
+
+	// Get the parent
+	$parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `id` IN
+			(SELECT `parent` FROM `item` WHERE `id` IN
+				(SELECT `oid` FROM `term` WHERE `uid` = %d AND `otype` = %d AND `type` = %d AND `url` = '%s'))",
+			intval($uid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION), dbesc($conversation_url));
+
+	if ($parents)
+		$parent = $parents[0];
+	elseif (count($item) > 0) {
+		$parent = $item;
+		$parent["type"] = "remote";
+		$parent["verb"] = ACTIVITY_POST;
+		$parent["visible"] = 1;
+	} else {
+		// Preset the parent
+		$r = q("SELECT `id` FROM `contact` WHERE `self` AND `uid`=%d", $uid);
+		if (!$r)
+			return(-1);
+
+		$parent = array();
+		$parent["id"] = 0;
+		$parent["parent"] = 0;
+		$parent["uri"] = "";
+		$parent["contact-id"] = $r[0]["id"];
+		$parent["type"] = "remote";
+		$parent["verb"] = ACTIVITY_POST;
+		$parent["visible"] = 1;
+	}
+
+	$conv = str_replace("/conversation/", "/api/statusnet/conversation/", $conversation_url).".as";
+	$pageno = 1;
+	$items = array();
+
+	logger('fetching conversation url '.$conv.' for user '.$uid);
+
+	do {
+		$conv_arr = z_fetch_url($conv."?page=".$pageno);
+
+		// If it is a non-ssl site and there is an error, then try ssl or vice versa
+		if (!$conv_arr["success"] AND (substr($conv, 0, 7) == "http://")) {
+			$conv = str_replace("http://", "https://", $conv);
+			$conv_as = fetch_url($conv."?page=".$pageno);
+		} elseif (!$conv_arr["success"] AND (substr($conv, 0, 8) == "https://")) {
+			$conv = str_replace("https://", "http://", $conv);
+			$conv_as = fetch_url($conv."?page=".$pageno);
+		} else
+			$conv_as = $conv_arr["body"];
+
+		$conv_as = str_replace(',"statusnet:notice_info":', ',"statusnet_notice_info":', $conv_as);
+		$conv_as = json_decode($conv_as);
+
+		if (@is_array($conv_as->items))
+			$items = array_merge($items, $conv_as->items);
+		else
+			break;
+
+		$pageno++;
+
+	} while (true);
+
+	logger('fetching conversation done. Found '.count($items).' items');
+
+	if (!sizeof($items)) {
+		if (count($item) > 0) {
+			$item_stored = item_store($item, true);
+			logger("Conversation ".$conversation_url." couldn't be fetched. Item uri ".$item["uri"]." stored: ".$item_stored, LOGGER_DEBUG);
+
+			if ($item_stored)
+				ostatus_store_conversation($item_id, $conversation_url);
+
+			return($item_stored);
+		} else
+			return(-2);
+	}
+
+	$items = array_reverse($items);
+
+	foreach ($items as $single_conv) {
+
+		// Test - remove before flight
+		//$tempfile = tempnam(get_temppath(), "conversation");
+		//file_put_contents($tempfile, json_encode($single_conv));
+
+
+		if (isset($single_conv->object->id))
+			$single_conv->id = $single_conv->object->id;
+
+		$plink = ostatus_convert_href($single_conv->id);
+		if (isset($single_conv->object->url))
+			$plink = ostatus_convert_href($single_conv->object->url);
+
+		if (@!$single_conv->id)
+			continue;
+
+		logger("Got id ".$single_conv->id, LOGGER_DEBUG);
+
+		if ($first_id == "") {
+			$first_id = $single_conv->id;
+
+			// The first post of the conversation isn't our first post. There are three options:
+			// 1. Our conversation hasn't the "real" thread starter
+			// 2. This first post is a post inside our thread
+			// 3. This first post is a post inside another thread
+			if (($first_id != $parent["uri"]) AND ($parent["uri"] != "")) {
+				$new_parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `id` IN
+							(SELECT `parent` FROM `item`
+								WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s')) LIMIT 1",
+					intval($uid), dbesc($first_id), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
+				if ($new_parents) {
+					if ($new_parents[0]["parent"] == $parent["parent"]) {
+						// Option 2: This post is already present inside our thread - but not as thread starter
+						logger("Option 2: uri present in our thread: ".$first_id, LOGGER_DEBUG);
+						$first_id = $parent["uri"];
+					} else {
+						// Option 3: Not so good. We have mixed parents. We have to see how to clean this up.
+						// For now just take the new parent.
+						$parent = $new_parents[0];
+						$first_id = $parent["uri"];
+						logger("Option 3: mixed parents for uri ".$first_id, LOGGER_DEBUG);
+					}
+				} else {
+					// Option 1: We hadn't got the real thread starter
+					// We have to clean up our existing messages.
+					$parent["id"] = 0;
+					$parent["uri"] = $first_id;
+					logger("Option 1: we have a new parent: ".$first_id, LOGGER_DEBUG);
+				}
+			} elseif ($parent["uri"] == "") {
+				$parent["id"] = 0;
+				$parent["uri"] = $first_id;
+			}
+		}
+
+		if (isset($single_conv->context->inReplyTo->id)) {
+			$parent_uri = $single_conv->context->inReplyTo->id;
+
+			$parent_exists = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1",
+						intval($uid), dbesc($parent_uri), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
+			if (!$parent_exists) {
+				logger("Parent ".$parent_uri." wasn't found here", LOGGER_DEBUG);
+				$parent_uri = $parent["uri"];
+			}
+		} else
+			$parent_uri = $parent["uri"];
+
+		$message_exists = q("SELECT `id`, `parent`, `uri` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1",
+						intval($uid), dbesc($single_conv->id),
+						dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
+		if ($message_exists) {
+			logger("Message ".$single_conv->id." already existed on the system", LOGGER_DEBUG);
+
+			if ($parent["id"] != 0) {
+				$existing_message = $message_exists[0];
+
+				// We improved the way we fetch OStatus messages, this shouldn't happen very often now
+				// To-Do: we have to change the shadow copies as well. This way here is really ugly.
+				if ($existing_message["parent"] != $parent["id"]) {
+					logger('updating id '.$existing_message["id"].' with parent '.$existing_message["parent"].' to parent '.$parent["id"].' uri '.$parent["uri"].' thread '.$parent_uri, LOGGER_DEBUG);
+
+					// Update the parent id of the selected item
+					$r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s' WHERE `id` = %d",
+						intval($parent["id"]), dbesc($parent["uri"]), intval($existing_message["id"]));
+
+					// Update the parent uri in the thread - but only if it points to itself
+					$r = q("UPDATE `item` SET `thr-parent` = '%s' WHERE `id` = %d AND `uri` = `thr-parent`",
+						dbesc($parent_uri), intval($existing_message["id"]));
+
+					// try to change all items of the same parent
+					$r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s' WHERE `parent` = %d",
+						intval($parent["id"]), dbesc($parent["uri"]), intval($existing_message["parent"]));
+
+					// Update the parent uri in the thread - but only if it points to itself
+					$r = q("UPDATE `item` SET `thr-parent` = '%s' WHERE (`parent` = %d) AND (`uri` = `thr-parent`)",
+						dbesc($parent["uri"]), intval($existing_message["parent"]));
+
+					// Now delete the thread
+					delete_thread($existing_message["parent"]);
+				}
+			}
+
+			// The item we are having on the system is the one that we wanted to store via the item array
+			if (isset($item["uri"]) AND ($item["uri"] == $existing_message["uri"])) {
+				$item = array();
+				$item_stored = 0;
+			}
+
+			continue;
+		}
+
+		$actor = $single_conv->actor->id;
+		if (isset($single_conv->actor->url))
+			$actor = $single_conv->actor->url;
+
+		$contact = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s' AND `network` != '%s'",
+				$uid, normalise_link($actor), NETWORK_STATUSNET);
+
+		if (count($contact)) {
+			logger("Found contact for url ".$actor, LOGGER_DEBUG);
+			$contact_id = $contact[0]["id"];
+		} else {
+			logger("No contact found for url ".$actor, LOGGER_DEBUG);
+
+			// Adding a global contact
+			// To-Do: Use this data for the post
+			$global_contact_id = get_contact($actor, 0);
+
+			logger("Global contact ".$global_contact_id." found for url ".$actor, LOGGER_DEBUG);
+
+			$contact_id = $parent["contact-id"];
+		}
+
+		$arr = array();
+		$arr["network"] = NETWORK_OSTATUS;
+		$arr["uri"] = $single_conv->id;
+		$arr["plink"] = $plink;
+		$arr["uid"] = $uid;
+		$arr["contact-id"] = $contact_id;
+		$arr["parent-uri"] = $parent_uri;
+		$arr["created"] = $single_conv->published;
+		$arr["edited"] = $single_conv->published;
+		$arr["owner-name"] = $single_conv->actor->displayName;
+		if ($arr["owner-name"] == '')
+			$arr["owner-name"] = $single_conv->actor->contact->displayName;
+		if ($arr["owner-name"] == '')
+			$arr["owner-name"] = $single_conv->actor->portablecontacts_net->displayName;
+
+		$arr["owner-link"] = $actor;
+		$arr["owner-avatar"] = $single_conv->actor->image->url;
+		$arr["author-name"] = $arr["owner-name"];
+		$arr["author-link"] = $actor;
+		$arr["author-avatar"] = $single_conv->actor->image->url;
+		$arr["body"] = add_page_info_to_body(html2bbcode($single_conv->content));
+
+		if (isset($single_conv->status_net->notice_info->source))
+			$arr["app"] = strip_tags($single_conv->status_net->notice_info->source);
+		elseif (isset($single_conv->statusnet->notice_info->source))
+			$arr["app"] = strip_tags($single_conv->statusnet->notice_info->source);
+		elseif (isset($single_conv->statusnet_notice_info->source))
+			$arr["app"] = strip_tags($single_conv->statusnet_notice_info->source);
+		elseif (isset($single_conv->provider->displayName))
+			$arr["app"] = $single_conv->provider->displayName;
+		else
+			$arr["app"] = "OStatus";
+
+		$arr["app"] .= " (Conversation)";
+
+		$arr["object"] = json_encode($single_conv);
+		$arr["verb"] = $parent["verb"];
+		$arr["visible"] = $parent["visible"];
+		$arr["location"] = $single_conv->location->displayName;
+		$arr["coord"] = trim($single_conv->location->lat." ".$single_conv->location->lon);
+
+		// Is it a reshared item?
+		if (isset($item->verb) AND ($item->verb == "share") AND isset($item->object)) {
+			if (is_array($item->object))
+				$item->object = $item->object[0];
+
+			logger("Found reshared item ".$single_conv->object->id);
+
+			// $single_conv->object->context->conversation;
+
+			$plink = ostatus_convert_href($single_conv->object->url);
+
+			$arr["uri"] = $single_conv->object->id;
+			$arr["plink"] = $plink;
+			$arr["created"] = $single_conv->object->published;
+			$arr["edited"] = $single_conv->object->published;
+
+			$arr["author-name"] = $single_conv->object->actor->displayName;
+			if ($arr["owner-name"] == '')
+				$arr["author-name"] = $single_conv->object->actor->contact->displayName;
+
+			$arr["author-link"] = $single_conv->object->actor->url;
+			$arr["author-avatar"] = $single_conv->object->actor->image->url;
+
+			$arr["body"] = add_page_info_to_body(html2bbcode($single_conv->object->content));
+			$arr["app"] = $single_conv->object->provider->displayName."#";
+			//$arr["verb"] = $single_conv->object->verb;
+
+			$arr["location"] = $single_conv->object->location->displayName;
+			$arr["coord"] = trim($single_conv->object->location->lat." ".$single_conv->object->location->lon);
+		}
+
+		if ($arr["location"] == "")
+			unset($arr["location"]);
+
+		if ($arr["coord"] == "")
+			unset($arr["coord"]);
+
+		// Copy fields from given item array
+		if (isset($item["uri"]) AND ($item["uri"] == $arr["uri"])) {
+			$copy_fields = array("owner-name", "owner-link", "owner-avatar", "author-name", "author-link", "author-avatar",
+						"gravity", "body", "object-type", "verb", "created", "edited", "coord", "tag",
+						"attach", "app", "type", "location", "contact-id");
+			foreach ($copy_fields AS $field)
+				if (isset($item[$field]))
+					$arr[$field] = $item[$field];
+
+			$arr["app"] .= " (OStatus)";
+		}
+
+		$newitem = item_store($arr);
+		if (!$newitem) {
+			logger("Item wasn't stored ".print_r($arr, true), LOGGER_DEBUG);
+			continue;
+		}
+
+		if (isset($item["uri"]) AND ($item["uri"] == $arr["uri"])) {
+			$item = array();
+			$item_stored = $newitem;
+		}
+
+		logger('Stored new item '.$plink.' for parent '.$arr["parent-uri"].' under id '.$newitem, LOGGER_DEBUG);
+
+		// Add the conversation entry (but don't fetch the whole conversation)
+		ostatus_store_conversation($newitem, $conversation_url);
+
+		// If the newly created item is the top item then change the parent settings of the thread
+		// This shouldn't happen anymore. This is supposed to be absolote.
+		if ($arr["uri"] == $first_id) {
+			logger('setting new parent to id '.$newitem);
+			$new_parents = q("SELECT `id`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1",
+				intval($uid), intval($newitem));
+			if ($new_parents)
+				$parent = $new_parents[0];
+		}
+	}
+
+	return($item_stored);
+}
+
+function ostatus_store_conversation($itemid, $conversation_url) {
+	global $a;
+
+	$conversation_url = ostatus_convert_href($conversation_url);
+
+	$messages = q("SELECT `uid`, `parent`, `created`, `received`, `guid` FROM `item` WHERE `id` = %d LIMIT 1", intval($itemid));
+	if (!$messages)
+		return;
+	$message = $messages[0];
+
+	// Store conversation url if not done before
+	$conversation = q("SELECT `url` FROM `term` WHERE `uid` = %d AND `oid` = %d AND `otype` = %d AND `type` = %d",
+		intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION));
+
+	if (!$conversation) {
+		$r = q("INSERT INTO `term` (`uid`, `oid`, `otype`, `type`, `term`, `url`, `created`, `received`, `guid`) VALUES (%d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s')",
+			intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION),
+			dbesc($message["created"]), dbesc($conversation_url), dbesc($message["created"]), dbesc($message["received"]), dbesc($message["guid"]));
+		logger('Storing conversation url '.$conversation_url.' for id '.$itemid);
+	}
+}
+?>
diff --git a/include/ostatus_conversation.php b/include/ostatus_conversation.php
deleted file mode 100644
index 03678cbb4a..0000000000
--- a/include/ostatus_conversation.php
+++ /dev/null
@@ -1,435 +0,0 @@
-<?php
-require_once("include/Contact.php");
-require_once("include/threads.php");
-require_once("include/html2bbcode.php");
-require_once("include/items.php");
-
-define('OSTATUS_DEFAULT_POLL_INTERVAL', 30); // given in minutes
-define('OSTATUS_DEFAULT_POLL_TIMEFRAME', 1440); // given in minutes
-
-function ostatus_convert_href($href) {
-	$elements = explode(":",$href);
-
-	if ((count($elements) <= 2) OR ($elements[0] != "tag"))
-		return $href;
-
-	$server = explode(",", $elements[1]);
-	$conversation = explode("=", $elements[2]);
-
-	if ((count($elements) == 4) AND ($elements[2] == "post"))
-		return "http://".$server[0]."/notice/".$elements[3];
-
-	if ((count($conversation) != 2) OR ($conversation[1] ==""))
-		return $href;
-
-	if ($elements[3] == "objectType=thread")
-		return "http://".$server[0]."/conversation/".$conversation[1];
-	else
-		return "http://".$server[0]."/notice/".$conversation[1];
-
-	return $href;
-}
-
-function check_conversations($override = false) {
-	$last = get_config('system','ostatus_last_poll');
-
-	$poll_interval = intval(get_config('system','ostatus_poll_interval'));
-	if(! $poll_interval)
-		$poll_interval = OSTATUS_DEFAULT_POLL_INTERVAL;
-
-	// Don't poll if the interval is set negative
-	if (($poll_interval < 0) AND !$override)
-		return;
-
-	$poll_timeframe = intval(get_config('system','ostatus_poll_timeframe'));
-	if (!$poll_timeframe)
-		$poll_timeframe = OSTATUS_DEFAULT_POLL_TIMEFRAME;
-
-	if ($last AND !$override) {
-		$next = $last + ($poll_interval * 60);
-		if ($next > time()) {
-			logger('poll interval not reached');
-			return;
-		}
-	}
-
-	logger('cron_start');
-
-	$start = date("Y-m-d H:i:s", time() - ($poll_timeframe * 60));
-	$conversations = q("SELECT `oid`, `url`, `uid` FROM `term` WHERE `type` = 7 AND `term` > '%s' GROUP BY `url`, `uid` ORDER BY `term` DESC",
-				dbesc($start));
-
-	foreach ($conversations AS $conversation) {
-		ostatus_completion($conversation['url'], $conversation['uid']);
-	}
-
-	logger('cron_end');
-
-	set_config('system','ostatus_last_poll', time());
-}
-
-function ostatus_completion($conversation_url, $uid, $item = array()) {
-
-	$item_stored = -3;
-
-	$conversation_url = ostatus_convert_href($conversation_url);
-
-	// If the thread shouldn't be completed then store the item and go away
-	if ((intval(get_config('system','ostatus_poll_interval')) == -2) AND (count($item) > 0)) {
-		$item_stored = item_store($item, true);
-		return($item_stored);
-	}
-
-	// Get the parent
-	$parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `id` IN
-			(SELECT `parent` FROM `item` WHERE `id` IN
-				(SELECT `oid` FROM `term` WHERE `uid` = %d AND `otype` = %d AND `type` = %d AND `url` = '%s'))",
-			intval($uid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION), dbesc($conversation_url));
-
-	if ($parents)
-		$parent = $parents[0];
-	elseif (count($item) > 0) {
-		$parent = $item;
-		$parent["type"] = "remote";
-		$parent["verb"] = ACTIVITY_POST;
-		$parent["visible"] = 1;
-	} else {
-		// Preset the parent
-		$r = q("SELECT `id` FROM `contact` WHERE `self` AND `uid`=%d", $uid);
-		if (!$r)
-			return(-1);
-
-		$parent = array();
-		$parent["id"] = 0;
-		$parent["parent"] = 0;
-		$parent["uri"] = "";
-		$parent["contact-id"] = $r[0]["id"];
-		$parent["type"] = "remote";
-		$parent["verb"] = ACTIVITY_POST;
-		$parent["visible"] = 1;
-	}
-
-	$conv = str_replace("/conversation/", "/api/statusnet/conversation/", $conversation_url).".as";
-	$pageno = 1;
-	$items = array();
-
-	logger('fetching conversation url '.$conv.' for user '.$uid);
-
-	do {
-		$conv_arr = z_fetch_url($conv."?page=".$pageno);
-
-		// If it is a non-ssl site and there is an error, then try ssl or vice versa
-		if (!$conv_arr["success"] AND (substr($conv, 0, 7) == "http://")) {
-			$conv = str_replace("http://", "https://", $conv);
-			$conv_as = fetch_url($conv."?page=".$pageno);
-		} elseif (!$conv_arr["success"] AND (substr($conv, 0, 8) == "https://")) {
-			$conv = str_replace("https://", "http://", $conv);
-			$conv_as = fetch_url($conv."?page=".$pageno);
-		} else
-			$conv_as = $conv_arr["body"];
-
-		$conv_as = str_replace(',"statusnet:notice_info":', ',"statusnet_notice_info":', $conv_as);
-		$conv_as = json_decode($conv_as);
-
-		if (@is_array($conv_as->items))
-			$items = array_merge($items, $conv_as->items);
-		else
-			break;
-
-		$pageno++;
-
-	} while (true);
-
-	logger('fetching conversation done. Found '.count($items).' items');
-
-	if (!sizeof($items)) {
-		if (count($item) > 0) {
-			$item_stored = item_store($item, true);
-			logger("Conversation ".$conversation_url." couldn't be fetched. Item uri ".$item["uri"]." stored: ".$item_stored, LOGGER_DEBUG);
-
-			if ($item_stored)
-				complete_conversation($item_id, $conversation_url);
-
-			return($item_stored);
-		} else
-			return(-2);
-	}
-
-	$items = array_reverse($items);
-
-	foreach ($items as $single_conv) {
-
-		// Test - remove before flight
-		//$tempfile = tempnam(get_temppath(), "conversation");
-		//file_put_contents($tempfile, json_encode($single_conv));
-
-
-		if (isset($single_conv->object->id))
-			$single_conv->id = $single_conv->object->id;
-
-		$plink = ostatus_convert_href($single_conv->id);
-		if (isset($single_conv->object->url))
-			$plink = ostatus_convert_href($single_conv->object->url);
-
-		if (@!$single_conv->id)
-			continue;
-
-		logger("Got id ".$single_conv->id, LOGGER_DEBUG);
-
-		if ($first_id == "") {
-			$first_id = $single_conv->id;
-
-			// The first post of the conversation isn't our first post. There are three options:
-			// 1. Our conversation hasn't the "real" thread starter
-			// 2. This first post is a post inside our thread
-			// 3. This first post is a post inside another thread
-			if (($first_id != $parent["uri"]) AND ($parent["uri"] != "")) {
-				$new_parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `id` IN
-							(SELECT `parent` FROM `item`
-								WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s')) LIMIT 1",
-					intval($uid), dbesc($first_id), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
-				if ($new_parents) {
-					if ($new_parents[0]["parent"] == $parent["parent"]) {
-						// Option 2: This post is already present inside our thread - but not as thread starter
-						logger("Option 2: uri present in our thread: ".$first_id, LOGGER_DEBUG);
-						$first_id = $parent["uri"];
-					} else {
-						// Option 3: Not so good. We have mixed parents. We have to see how to clean this up.
-						// For now just take the new parent.
-						$parent = $new_parents[0];
-						$first_id = $parent["uri"];
-						logger("Option 3: mixed parents for uri ".$first_id, LOGGER_DEBUG);
-					}
-				} else {
-					// Option 1: We hadn't got the real thread starter
-					// We have to clean up our existing messages.
-					$parent["id"] = 0;
-					$parent["uri"] = $first_id;
-					logger("Option 1: we have a new parent: ".$first_id, LOGGER_DEBUG);
-				}
-			} elseif ($parent["uri"] == "") {
-				$parent["id"] = 0;
-				$parent["uri"] = $first_id;
-			}
-		}
-
-		if (isset($single_conv->context->inReplyTo->id)) {
-			$parent_uri = $single_conv->context->inReplyTo->id;
-
-			$parent_exists = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1",
-						intval($uid), dbesc($parent_uri), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
-			if (!$parent_exists) {
-				logger("Parent ".$parent_uri." wasn't found here", LOGGER_DEBUG);
-				$parent_uri = $parent["uri"];
-			}
-		} else
-			$parent_uri = $parent["uri"];
-
-		$message_exists = q("SELECT `id`, `parent`, `uri` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s','%s') LIMIT 1",
-						intval($uid), dbesc($single_conv->id),
-						dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DFRN));
-		if ($message_exists) {
-			logger("Message ".$single_conv->id." already existed on the system", LOGGER_DEBUG);
-
-			if ($parent["id"] != 0) {
-				$existing_message = $message_exists[0];
-
-				// We improved the way we fetch OStatus messages, this shouldn't happen very often now
-				// To-Do: we have to change the shadow copies as well. This way here is really ugly.
-				if ($existing_message["parent"] != $parent["id"]) {
-					logger('updating id '.$existing_message["id"].' with parent '.$existing_message["parent"].' to parent '.$parent["id"].' uri '.$parent["uri"].' thread '.$parent_uri, LOGGER_DEBUG);
-
-					// Update the parent id of the selected item
-					$r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s' WHERE `id` = %d",
-						intval($parent["id"]), dbesc($parent["uri"]), intval($existing_message["id"]));
-
-					// Update the parent uri in the thread - but only if it points to itself
-					$r = q("UPDATE `item` SET `thr-parent` = '%s' WHERE `id` = %d AND `uri` = `thr-parent`",
-						dbesc($parent_uri), intval($existing_message["id"]));
-
-					// try to change all items of the same parent
-					$r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s' WHERE `parent` = %d",
-						intval($parent["id"]), dbesc($parent["uri"]), intval($existing_message["parent"]));
-
-					// Update the parent uri in the thread - but only if it points to itself
-					$r = q("UPDATE `item` SET `thr-parent` = '%s' WHERE (`parent` = %d) AND (`uri` = `thr-parent`)",
-						dbesc($parent["uri"]), intval($existing_message["parent"]));
-
-					// Now delete the thread
-					delete_thread($existing_message["parent"]);
-				}
-			}
-
-			// The item we are having on the system is the one that we wanted to store via the item array
-			if (isset($item["uri"]) AND ($item["uri"] == $existing_message["uri"])) {
-				$item = array();
-				$item_stored = 0;
-			}
-
-			continue;
-		}
-
-		$actor = $single_conv->actor->id;
-		if (isset($single_conv->actor->url))
-			$actor = $single_conv->actor->url;
-
-		$contact = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s' AND `network` != '%s'",
-				$uid, normalise_link($actor), NETWORK_STATUSNET);
-
-		if (count($contact)) {
-			logger("Found contact for url ".$actor, LOGGER_DEBUG);
-			$contact_id = $contact[0]["id"];
-		} else {
-			logger("No contact found for url ".$actor, LOGGER_DEBUG);
-
-			// Adding a global contact
-			// To-Do: Use this data for the post
-			$global_contact_id = get_contact($actor, 0);
-
-			logger("Global contact ".$global_contact_id." found for url ".$actor, LOGGER_DEBUG);
-
-			$contact_id = $parent["contact-id"];
-		}
-
-		$arr = array();
-		$arr["network"] = NETWORK_OSTATUS;
-		$arr["uri"] = $single_conv->id;
-		$arr["plink"] = $plink;
-		$arr["uid"] = $uid;
-		$arr["contact-id"] = $contact_id;
-		$arr["parent-uri"] = $parent_uri;
-		$arr["created"] = $single_conv->published;
-		$arr["edited"] = $single_conv->published;
-		$arr["owner-name"] = $single_conv->actor->displayName;
-		if ($arr["owner-name"] == '')
-			$arr["owner-name"] = $single_conv->actor->contact->displayName;
-		if ($arr["owner-name"] == '')
-			$arr["owner-name"] = $single_conv->actor->portablecontacts_net->displayName;
-
-		$arr["owner-link"] = $actor;
-		$arr["owner-avatar"] = $single_conv->actor->image->url;
-		$arr["author-name"] = $arr["owner-name"];
-		$arr["author-link"] = $actor;
-		$arr["author-avatar"] = $single_conv->actor->image->url;
-		$arr["body"] = add_page_info_to_body(html2bbcode($single_conv->content));
-
-		if (isset($single_conv->status_net->notice_info->source))
-			$arr["app"] = strip_tags($single_conv->status_net->notice_info->source);
-		elseif (isset($single_conv->statusnet->notice_info->source))
-			$arr["app"] = strip_tags($single_conv->statusnet->notice_info->source);
-		elseif (isset($single_conv->statusnet_notice_info->source))
-			$arr["app"] = strip_tags($single_conv->statusnet_notice_info->source);
-		elseif (isset($single_conv->provider->displayName))
-			$arr["app"] = $single_conv->provider->displayName;
-		else
-			$arr["app"] = "OStatus";
-
-		$arr["app"] .= "*";
-
-		$arr["object"] = json_encode($single_conv);
-		$arr["verb"] = $parent["verb"];
-		$arr["visible"] = $parent["visible"];
-		$arr["location"] = $single_conv->location->displayName;
-		$arr["coord"] = trim($single_conv->location->lat." ".$single_conv->location->lon);
-
-		// Is it a reshared item?
-		if (isset($item->verb) AND ($item->verb == "share") AND isset($item->object)) {
-			if (is_array($item->object))
-				$item->object = $item->object[0];
-
-			logger("Found reshared item ".$single_conv->object->id);
-
-			// $single_conv->object->context->conversation;
-
-			$plink = ostatus_convert_href($single_conv->object->url);
-
-			$arr["uri"] = $single_conv->object->id;
-			$arr["plink"] = $plink;
-			$arr["created"] = $single_conv->object->published;
-			$arr["edited"] = $single_conv->object->published;
-
-			$arr["author-name"] = $single_conv->object->actor->displayName;
-			if ($arr["owner-name"] == '')
-				$arr["author-name"] = $single_conv->object->actor->contact->displayName;
-
-			$arr["author-link"] = $single_conv->object->actor->url;
-			$arr["author-avatar"] = $single_conv->object->actor->image->url;
-
-			$arr["body"] = add_page_info_to_body(html2bbcode($single_conv->object->content));
-			$arr["app"] = $single_conv->object->provider->displayName."#";
-			//$arr["verb"] = $single_conv->object->verb;
-
-			$arr["location"] = $single_conv->object->location->displayName;
-			$arr["coord"] = trim($single_conv->object->location->lat." ".$single_conv->object->location->lon);
-		}
-
-		if ($arr["location"] == "")
-			unset($arr["location"]);
-
-		if ($arr["coord"] == "")
-			unset($arr["coord"]);
-
-		// Copy fields from given item array
-		if (isset($item["uri"]) AND ($item["uri"] == $arr["uri"])) {
-			$copy_fields = array("owner-name", "owner-link", "owner-avatar", "author-name", "author-link", "author-avatar",
-						"gravity", "body", "object-type", "verb", "created", "edited", "coord", "tag",
-						"attach", "app", "type", "location", "contact-id");
-			foreach ($copy_fields AS $field)
-				if (isset($item[$field]))
-					$arr[$field] = $item[$field];
-
-			$arr["app"] .= "+";
-		}
-
-		$newitem = item_store($arr);
-		if (!$newitem) {
-			logger("Item wasn't stored ".print_r($arr, true), LOGGER_DEBUG);
-			continue;
-		}
-
-		if (isset($item["uri"]) AND ($item["uri"] == $arr["uri"])) {
-			$item = array();
-			$item_stored = $newitem;
-		}
-
-		logger('Stored new item '.$plink.' for parent '.$arr["parent-uri"].' under id '.$newitem, LOGGER_DEBUG);
-
-		// Add the conversation entry (but don't fetch the whole conversation)
-		complete_conversation($newitem, $conversation_url);
-
-		// If the newly created item is the top item then change the parent settings of the thread
-		// This shouldn't happen anymore. This is supposed to be absolote.
-		if ($arr["uri"] == $first_id) {
-			logger('setting new parent to id '.$newitem);
-			$new_parents = q("SELECT `id`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1",
-				intval($uid), intval($newitem));
-			if ($new_parents)
-				$parent = $new_parents[0];
-		}
-	}
-
-	return($item_stored);
-}
-
-function complete_conversation($itemid, $conversation_url) {
-	global $a;
-
-	$conversation_url = ostatus_convert_href($conversation_url);
-
-	$messages = q("SELECT `uid`, `parent`, `created`, `received`, `guid` FROM `item` WHERE `id` = %d LIMIT 1", intval($itemid));
-	if (!$messages)
-		return;
-	$message = $messages[0];
-
-	// Store conversation url if not done before
-	$conversation = q("SELECT `url` FROM `term` WHERE `uid` = %d AND `oid` = %d AND `otype` = %d AND `type` = %d",
-		intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION));
-
-	if (!$conversation) {
-		$r = q("INSERT INTO `term` (`uid`, `oid`, `otype`, `type`, `term`, `url`, `created`, `received`, `guid`) VALUES (%d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s')",
-			intval($message["uid"]), intval($itemid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION),
-			dbesc($message["created"]), dbesc($conversation_url), dbesc($message["created"]), dbesc($message["received"]), dbesc($message["guid"]));
-		logger('Storing conversation url '.$conversation_url.' for id '.$itemid);
-	}
-}
-?>

From 1bbbf2a5f26c420d688705a70c287865267a7426 Mon Sep 17 00:00:00 2001
From: Michael Vogel <icarus@dabo.de>
Date: Sat, 20 Jun 2015 14:41:53 +0200
Subject: [PATCH 04/11] Stuff ...

---
 include/acl_selectors.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/acl_selectors.php b/include/acl_selectors.php
index dc2f8d4164..b2c4b31c81 100644
--- a/include/acl_selectors.php
+++ b/include/acl_selectors.php
@@ -422,7 +422,7 @@ function acl_lookup(&$a, $out_type = 'json') {
 				WHERE `uid` = %d AND `self` = 0
 				AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0
 				AND `notify` != '' $sql_extra2" ,
-			intval(local_user()),
+			intval(local_user())
 		);
 		$contact_count = (int)$r[0]['c'];
 	}

From 846edd5bbb7adb965303c9dfd1912c006b2c6668 Mon Sep 17 00:00:00 2001
From: Michael Vogel <icarus@dabo.de>
Date: Sat, 20 Jun 2015 17:26:47 +0200
Subject: [PATCH 05/11] Bugfix for repeated items in conversations

---
 include/ostatus.php | 64 +++++++++++++++++++++++++++++----------------
 1 file changed, 42 insertions(+), 22 deletions(-)

diff --git a/include/ostatus.php b/include/ostatus.php
index f6056170f2..80a67f201c 100644
--- a/include/ostatus.php
+++ b/include/ostatus.php
@@ -322,29 +322,33 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 
 			if (is_object($activityobjects)) {
 
-				$orig_uris = $xpath->query("activity:object/atom:link[@rel='alternate']", $activityobjects);
-				if ($orig_uris)
-					foreach($orig_uris->item(0)->attributes AS $attributes)
-						if ($attributes->name == "href")
-							$orig_uri = $attributes->textContent;
-
-				if (!isset($orig_uri))
-					$orig_uri = $xpath->query("atom:link[@rel='alternate']", $activityobjects)->item(0)->nodeValue;
-
-				if (!isset($orig_uri))
-					$orig_uri = $xpath->query("activity:object/atom:id", $activityobjects)->item(0)->nodeValue;
-
+				$orig_uri = $xpath->query("activity:object/atom:id", $activityobjects)->item(0)->nodeValue;
 				if (!isset($orig_uri))
 					$orig_uri = $xpath->query('atom:id/text()', $activityobjects)->item(0)->nodeValue;
 
-				$orig_body = $xpath->query('atom:content/text()', $activityobjects)->item(0)->nodeValue;
+				$orig_links = $xpath->query("activity:object/atom:link[@rel='alternate']", $activityobjects);
+				if ($orig_links AND ($orig_links->length > 0))
+					foreach($orig_links->item(0)->attributes AS $attributes)
+						if ($attributes->name == "href")
+							$orig_link = $attributes->textContent;
+
+				if (!isset($orig_link))
+					$orig_link = $xpath->query("atom:link[@rel='alternate']", $activityobjects)->item(0)->nodeValue;
+
+				if (!isset($orig_link))
+					$orig_link =  ostatus_convert_href($orig_uri);
+
+				$orig_body = $xpath->query('activity:object/atom:content/text()', $activityobjects)->item(0)->nodeValue;
+				if (!isset($orig_body))
+					$orig_body = $xpath->query('atom:content/text()', $activityobjects)->item(0)->nodeValue;
+
 				$orig_created = $xpath->query('atom:published/text()', $activityobjects)->item(0)->nodeValue;
 
 				$orig_contact = $contact;
 				$orig_author = ostatus_fetchauthor($xpath, $activityobjects, $importer, $orig_contact);
 
 				//if (!intval(get_config('system','wall-to-wall_share'))) {
-				//	$prefix = share_header($orig_author['author-name'], $orig_author['author-link'], $orig_author['author-avatar'], "", $orig_created, $orig_uri);
+				//	$prefix = share_header($orig_author['author-name'], $orig_author['author-link'], $orig_author['author-avatar'], "", $orig_created, $orig_link);
 				//	$item["body"] = $prefix.add_page_info_to_body(html2bbcode($orig_body))."[/share]";
 				//} else {
 					$item["author-name"] = $orig_author["author-name"];
@@ -354,10 +358,14 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 					$item["created"] = $orig_created;
 
 					$item["uri"] = $orig_uri;
+					$item["plink"] = $orig_link;
 				//}
 
 				$item["verb"] = $xpath->query('activity:verb/text()', $activityobjects)->item(0)->nodeValue;
-				$item["object-type"] = $xpath->query('activity:object-type/text()', $activityobjects)->item(0)->nodeValue;
+
+				$item["object-type"] = $xpath->query('activity:object/activity:object-type/text()', $activityobjects)->item(0)->nodeValue;
+				if (!isset($item["object-type"]))
+					$item["object-type"] = $xpath->query('activity:object-type/text()', $activityobjects)->item(0)->nodeValue;
 			}
 		}
 
@@ -397,7 +405,7 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 			$item["app"] .= $item_id;
 			$item_id = item_store($item, true);
 			if ($item_id) {
-				logger("Shouldn't happen. Code ".$reason." - uri ".$item["uri"], LOGGER_DEBUG);
+				logger("Uri ".$item["uri"]." wasn't found in conversation ".$conversation, LOGGER_DEBUG);
 				ostatus_store_conversation($item_id, $conversation_url);
 			}
 		}
@@ -764,18 +772,31 @@ function ostatus_completion($conversation_url, $uid, $item = array()) {
 		$arr["coord"] = trim($single_conv->location->lat." ".$single_conv->location->lon);
 
 		// Is it a reshared item?
-		if (isset($item->verb) AND ($item->verb == "share") AND isset($item->object)) {
-			if (is_array($item->object))
-				$item->object = $item->object[0];
+		if (isset($single_conv->verb) AND ($single_conv->verb == "share") AND isset($single_conv->object)) {
+			if (is_array($single_conv->object))
+				$single_conv->object = $single_conv->object[0];
 
 			logger("Found reshared item ".$single_conv->object->id);
 
 			// $single_conv->object->context->conversation;
 
-			$plink = ostatus_convert_href($single_conv->object->url);
+			if (isset($single_conv->object->object->id))
+				$arr["uri"] = $single_conv->object->object->id;
+			else
+				$arr["uri"] = $single_conv->object->id;
+
+			if (isset($single_conv->object->object->url))
+				$plink = ostatus_convert_href($single_conv->object->object->url);
+			else
+				$plink = ostatus_convert_href($single_conv->object->url);
+
+			if (isset($single_conv->object->object->content))
+				$arr["body"] = add_page_info_to_body(html2bbcode($single_conv->object->object->content));
+			else
+				$arr["body"] = add_page_info_to_body(html2bbcode($single_conv->object->content));
 
-			$arr["uri"] = $single_conv->object->id;
 			$arr["plink"] = $plink;
+
 			$arr["created"] = $single_conv->object->published;
 			$arr["edited"] = $single_conv->object->published;
 
@@ -786,7 +807,6 @@ function ostatus_completion($conversation_url, $uid, $item = array()) {
 			$arr["author-link"] = $single_conv->object->actor->url;
 			$arr["author-avatar"] = $single_conv->object->actor->image->url;
 
-			$arr["body"] = add_page_info_to_body(html2bbcode($single_conv->object->content));
 			$arr["app"] = $single_conv->object->provider->displayName."#";
 			//$arr["verb"] = $single_conv->object->verb;
 

From df7b907bc48923316520bc7504d1379361d2b270 Mon Sep 17 00:00:00 2001
From: Michael Vogel <icarus@dabo.de>
Date: Sun, 21 Jun 2015 01:34:57 +0200
Subject: [PATCH 06/11] Display: Look for the network name when fetching the
 contact (important because of the statusnet connector)

---
 mod/display.php | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/mod/display.php b/mod/display.php
index 02ff37bf83..c8b72ecc40 100644
--- a/mod/display.php
+++ b/mod/display.php
@@ -102,8 +102,17 @@ function display_fetchauthor($a, $item) {
 	$profiledata["network"] = $item["network"];
 
 	// Fetching further contact data from the contact table
-	$r = q("SELECT `photo`, `nick`, `location`, `about` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d",
-		normalise_link($profiledata["url"]), $item["uid"]);
+	$r = q("SELECT `photo`, `nick`, `location`, `about` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d AND `network` = '%s'",
+		dbesc(normalise_link($profiledata["url"])), intval($item["uid"]), dbesc($item["network"]));
+
+	if (!count($r))
+		$r = q("SELECT `photo`, `nick`, `location`, `about` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d",
+			dbesc(normalise_link($profiledata["url"])), intval($item["uid"]));
+
+	if (!count($r))
+		$r = q("SELECT `photo`, `nick`, `location`, `about` FROM `contact` WHERE `nurl` = '%s' AND `uid` = 0",
+			dbesc(normalise_link($profiledata["url"])));
+
 	if (count($r)) {
 		$profiledata["photo"] = proxy_url($r[0]["photo"]);
 		$profiledata["address"] = proxy_parse_html(bbcode($r[0]["location"]));
@@ -113,7 +122,7 @@ function display_fetchauthor($a, $item) {
 	}
 
 	// Fetching profile data from unique contacts
-	$r = q("SELECT `avatar`, `nick`, `location`, `about` FROM `unique_contacts` WHERE `url` = '%s'", normalise_link($profiledata["url"]));
+	$r = q("SELECT `avatar`, `nick`, `location`, `about` FROM `unique_contacts` WHERE `url` = '%s'", dbesc(normalise_link($profiledata["url"])));
 	if (count($r)) {
 		if ($profiledata["photo"] == "")
 			$profiledata["photo"] = proxy_url($r[0]["avatar"]);
@@ -181,7 +190,7 @@ function display_fetchauthor($a, $item) {
 
 		// Fetching profile data from unique contacts
 		if ($profiledata["url"] != "") {
-			$r = q("SELECT `avatar`, `nick`, `location`, `about` FROM `unique_contacts` WHERE `url` = '%s'", normalise_link($profiledata["url"]));
+			$r = q("SELECT `avatar`, `nick`, `location`, `about` FROM `unique_contacts` WHERE `url` = '%s'", dbesc(normalise_link($profiledata["url"])));
 			if (count($r)) {
 				$profiledata["photo"] = proxy_url($r[0]["avatar"]);
 				$profiledata["address"] = proxy_parse_html(bbcode($r[0]["location"]));

From 8229737d2d63c31a02af000b08bc63fbd5586193 Mon Sep 17 00:00:00 2001
From: Michael Vogel <icarus@dabo.de>
Date: Sun, 21 Jun 2015 01:36:23 +0200
Subject: [PATCH 07/11] Small restructuring

---
 include/ostatus.php | 30 +++++++++++++-----------------
 1 file changed, 13 insertions(+), 17 deletions(-)

diff --git a/include/ostatus.php b/include/ostatus.php
index 80a67f201c..a03e561320 100644
--- a/include/ostatus.php
+++ b/include/ostatus.php
@@ -400,18 +400,6 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 
 		$item_id = ostatus_completion($conversation, $importer["uid"], $item);
 
-		if ($item_id <= 0) {
-			$reason = $item_id;
-			$item["app"] .= $item_id;
-			$item_id = item_store($item, true);
-			if ($item_id) {
-				logger("Uri ".$item["uri"]." wasn't found in conversation ".$conversation, LOGGER_DEBUG);
-				ostatus_store_conversation($item_id, $conversation_url);
-			}
-		}
-		//echo $xml;
-		//print_r($item);
-
 		if (!$item_id) {
 			logger("Error storing item ".print_r($item, true), LOGGER_DEBUG);
 			continue;
@@ -509,7 +497,7 @@ function check_conversations($override = false) {
 
 function ostatus_completion($conversation_url, $uid, $item = array()) {
 
-	$item_stored = -3;
+	$item_stored = -1;
 
 	$conversation_url = ostatus_convert_href($conversation_url);
 
@@ -536,7 +524,7 @@ function ostatus_completion($conversation_url, $uid, $item = array()) {
 		// Preset the parent
 		$r = q("SELECT `id` FROM `contact` WHERE `self` AND `uid`=%d", $uid);
 		if (!$r)
-			return(-1);
+			return(-2);
 
 		$parent = array();
 		$parent["id"] = 0;
@@ -591,7 +579,7 @@ function ostatus_completion($conversation_url, $uid, $item = array()) {
 
 			return($item_stored);
 		} else
-			return(-2);
+			return(-3);
 	}
 
 	$items = array_reverse($items);
@@ -821,10 +809,10 @@ function ostatus_completion($conversation_url, $uid, $item = array()) {
 			unset($arr["coord"]);
 
 		// Copy fields from given item array
-		if (isset($item["uri"]) AND ($item["uri"] == $arr["uri"])) {
+		if (isset($item["uri"]) AND (($item["uri"] == $arr["uri"]) OR ($item["uri"] ==  $single_conv->id))) {
 			$copy_fields = array("owner-name", "owner-link", "owner-avatar", "author-name", "author-link", "author-avatar",
 						"gravity", "body", "object-type", "verb", "created", "edited", "coord", "tag",
-						"attach", "app", "type", "location", "contact-id");
+						"attach", "app", "type", "location", "contact-id", "uri");
 			foreach ($copy_fields AS $field)
 				if (isset($item[$field]))
 					$arr[$field] = $item[$field];
@@ -859,6 +847,14 @@ function ostatus_completion($conversation_url, $uid, $item = array()) {
 		}
 	}
 
+	if (($item_stored < 0) AND (count($item) > 0)) {
+		$item_stored = item_store($item, true);
+		if ($item_stored) {
+			logger("Uri ".$item["uri"]." wasn't found in conversation ".$conversation_url, LOGGER_DEBUG);
+			ostatus_store_conversation($item_stored, $conversation_url);
+		}
+	}
+
 	return($item_stored);
 }
 

From 5221f38db79490847b62e58861639fed63a0ce53 Mon Sep 17 00:00:00 2001
From: Michael Vogel <icarus@dabo.de>
Date: Sun, 21 Jun 2015 01:37:09 +0200
Subject: [PATCH 08/11] ACL: Don't show OStatus contacts in ACL, since you
 cannot send private messages to them.

---
 include/acl_selectors.php | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/include/acl_selectors.php b/include/acl_selectors.php
index b2c4b31c81..c1e62ac36b 100644
--- a/include/acl_selectors.php
+++ b/include/acl_selectors.php
@@ -399,6 +399,7 @@ function acl_lookup(&$a, $out_type = 'json') {
 		$search = $_REQUEST['query'];
 	}
 
+	logger("Searching for ".$search." - type ".$type, LOGGER_DEBUG);
 
 	if ($search!=""){
 		$sql_extra = "AND `name` LIKE '%%".dbesc($search)."%%'";
@@ -496,9 +497,11 @@ function acl_lookup(&$a, $out_type = 'json') {
 
 		$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, forum FROM `contact`
 			WHERE `uid` = %d AND `self` = 0 AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0 AND `notify` != ''
+			AND NOT (`network` IN ('%s', '%s'))
 			$sql_extra2
 			ORDER BY `name` ASC ",
-			intval(local_user())
+			intval(local_user()),
+			dbesc(NETWORK_OSTATUS), dbesc(NETWORK_STATUSNET)
 		);
 	}
 	elseif($type == 'm') {

From 2afc9c31f96b613bdf985197806fb0bebbb128c3 Mon Sep 17 00:00:00 2001
From: Michael Vogel <icarus@dabo.de>
Date: Sun, 21 Jun 2015 08:32:03 +0200
Subject: [PATCH 09/11] Changed logging behaviour

---
 include/ostatus.php | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/include/ostatus.php b/include/ostatus.php
index a03e561320..d1a1f4f988 100644
--- a/include/ostatus.php
+++ b/include/ostatus.php
@@ -401,7 +401,7 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 		$item_id = ostatus_completion($conversation, $importer["uid"], $item);
 
 		if (!$item_id) {
-			logger("Error storing item ".print_r($item, true), LOGGER_DEBUG);
+			logger("Error storing item", LOGGER_DEBUG);
 			continue;
 		}
 
@@ -572,10 +572,11 @@ function ostatus_completion($conversation_url, $uid, $item = array()) {
 	if (!sizeof($items)) {
 		if (count($item) > 0) {
 			$item_stored = item_store($item, true);
-			logger("Conversation ".$conversation_url." couldn't be fetched. Item uri ".$item["uri"]." stored: ".$item_stored, LOGGER_DEBUG);
 
-			if ($item_stored)
+			if ($item_stored) {
+				logger("Conversation ".$conversation_url." couldn't be fetched. Item uri ".$item["uri"]." stored: ".$item_stored, LOGGER_DEBUG);
 				ostatus_store_conversation($item_id, $conversation_url);
+			}
 
 			return($item_stored);
 		} else

From da9bbc92d378e3b000bdf72f637516fd691618e6 Mon Sep 17 00:00:00 2001
From: Michael Vogel <icarus@dabo.de>
Date: Sun, 21 Jun 2015 22:02:44 +0200
Subject: [PATCH 10/11] OStatus: Support for bookmarks

---
 include/ostatus.php | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/include/ostatus.php b/include/ostatus.php
index d1a1f4f988..ab5c00a6a0 100644
--- a/include/ostatus.php
+++ b/include/ostatus.php
@@ -190,6 +190,12 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 
 		$item["body"] = add_page_info_to_body(html2bbcode($xpath->query('atom:content/text()', $entry)->item(0)->nodeValue));
 		$item["object-type"] = $xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue;
+
+		if ($item["object-type"] == ACTIVITY_OBJ_BOOKMARK) {
+			$item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue;
+			$item["body"] = $xpath->query('atom:summary/text()', $entry)->item(0)->nodeValue;
+		}
+
 		$item["object"] = $xml;
 		$item["verb"] = $xpath->query('activity:verb/text()', $entry)->item(0)->nodeValue;
 
@@ -283,11 +289,14 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 							$item["attach"] .= '[attach]href="'.$href.'" length="'.$length.'" type="'.$type.'" title="'.$title.'"[/attach]';
 							break;
 						case "related":
-							if (!isset($item["parent-uri"]))
-								$item["parent-uri"] = $href;
+							if ($item["object-type"] != ACTIVITY_OBJ_BOOKMARK) {
+								if (!isset($item["parent-uri"]))
+									$item["parent-uri"] = $href;
 
-							if ($related == "")
-								$related = $href;
+								if ($related == "")
+									$related = $href;
+							} else
+								$item["body"] .= add_page_info($href);
 							break;
 						case "self":
 							$self = $href;
@@ -812,8 +821,8 @@ function ostatus_completion($conversation_url, $uid, $item = array()) {
 		// Copy fields from given item array
 		if (isset($item["uri"]) AND (($item["uri"] == $arr["uri"]) OR ($item["uri"] ==  $single_conv->id))) {
 			$copy_fields = array("owner-name", "owner-link", "owner-avatar", "author-name", "author-link", "author-avatar",
-						"gravity", "body", "object-type", "verb", "created", "edited", "coord", "tag",
-						"attach", "app", "type", "location", "contact-id", "uri");
+						"gravity", "body", "object-type", "object", "verb", "created", "edited", "coord", "tag",
+						"title", "attach", "app", "type", "location", "contact-id", "uri");
 			foreach ($copy_fields AS $field)
 				if (isset($item[$field]))
 					$arr[$field] = $item[$field];

From e9542a8d1715279faadf3a36fd2db8ce3f8c4589 Mon Sep 17 00:00:00 2001
From: Michael Vogel <icarus@dabo.de>
Date: Sun, 21 Jun 2015 22:36:24 +0200
Subject: [PATCH 11/11] OStatus: Support for events and questions

---
 boot.php            | 1 +
 include/ostatus.php | 8 ++++++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/boot.php b/boot.php
index 0aa7ab6341..193b34a60b 100644
--- a/boot.php
+++ b/boot.php
@@ -290,6 +290,7 @@ define ( 'ACTIVITY_OBJ_EVENT',   NAMESPACE_ACTIVITY_SCHEMA . 'event' );
 define ( 'ACTIVITY_OBJ_GROUP',   NAMESPACE_ACTIVITY_SCHEMA . 'group' );
 define ( 'ACTIVITY_OBJ_TAGTERM', NAMESPACE_DFRN            . '/tagterm' );
 define ( 'ACTIVITY_OBJ_PROFILE', NAMESPACE_DFRN            . '/profile' );
+define ( 'ACTIVITY_OBJ_QUESTION', 'http://activityschema.org/object/question' );
 
 /**
  * item weight for query ordering
diff --git a/include/ostatus.php b/include/ostatus.php
index ab5c00a6a0..463ebcd30a 100644
--- a/include/ostatus.php
+++ b/include/ostatus.php
@@ -191,10 +191,11 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 		$item["body"] = add_page_info_to_body(html2bbcode($xpath->query('atom:content/text()', $entry)->item(0)->nodeValue));
 		$item["object-type"] = $xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue;
 
-		if ($item["object-type"] == ACTIVITY_OBJ_BOOKMARK) {
+		if (($item["object-type"] == ACTIVITY_OBJ_BOOKMARK) OR ($item["object-type"] == ACTIVITY_OBJ_EVENT)) {
 			$item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue;
 			$item["body"] = $xpath->query('atom:summary/text()', $entry)->item(0)->nodeValue;
-		}
+		} elseif ($item["object-type"] == ACTIVITY_OBJ_QUESTION)
+			$item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue;
 
 		$item["object"] = $xml;
 		$item["verb"] = $xpath->query('activity:verb/text()', $entry)->item(0)->nodeValue;
@@ -277,6 +278,9 @@ function ostatus_import($xml,$importer,&$contact, &$hub) {
 					switch($rel) {
 						case "alternate":
 							$item["plink"] = $href;
+							if (($item["object-type"] == ACTIVITY_OBJ_QUESTION) OR
+								($item["object-type"] == ACTIVITY_OBJ_EVENT))
+								$item["body"] .= add_page_info($href);
 							break;
 						case "ostatus:conversation":
 							$conversation = $href;