+ /**
+ * @brief Adds the header elements to the XML document
+ *
+ * @param object $doc XML document
+ * @param array $owner Contact data of the poster
+ *
+ * @return object header root element
+ */
+ private function add_header($doc, $owner) {
+
+ $a = get_app();
+
+ $root = $doc->createElementNS(NAMESPACE_ATOM1, 'feed');
+ $doc->appendChild($root);
+
+ $root->setAttribute("xmlns:thr", NAMESPACE_THREAD);
+ $root->setAttribute("xmlns:georss", NAMESPACE_GEORSS);
+ $root->setAttribute("xmlns:activity", NAMESPACE_ACTIVITY);
+ $root->setAttribute("xmlns:media", NAMESPACE_MEDIA);
+ $root->setAttribute("xmlns:poco", NAMESPACE_POCO);
+ $root->setAttribute("xmlns:ostatus", NAMESPACE_OSTATUS);
+ $root->setAttribute("xmlns:statusnet", NAMESPACE_STATUSNET);
+
+ $attributes = array("uri" => "https://friendi.ca", "version" => FRIENDICA_VERSION."-".DB_UPDATE_VERSION);
+ xml::add_element($doc, $root, "generator", FRIENDICA_PLATFORM, $attributes);
+ xml::add_element($doc, $root, "id", App::get_baseurl()."/profile/".$owner["nick"]);
+ xml::add_element($doc, $root, "title", sprintf("%s timeline", $owner["name"]));
+ xml::add_element($doc, $root, "subtitle", sprintf("Updates from %s on %s", $owner["name"], $a->config["sitename"]));
+ xml::add_element($doc, $root, "logo", $owner["photo"]);
+ xml::add_element($doc, $root, "updated", datetime_convert("UTC", "UTC", "now", ATOM_TIME));
+
+ $author = self::add_author($doc, $owner);
+ $root->appendChild($author);
+
+ $attributes = array("href" => $owner["url"], "rel" => "alternate", "type" => "text/html");
+ xml::add_element($doc, $root, "link", "", $attributes);
+
+ /// @TODO We have to find out what this is
+ /// $attributes = array("href" => App::get_baseurl()."/sup",
+ /// "rel" => "http://api.friendfeed.com/2008/03#sup",
+ /// "type" => "application/json");
+ /// xml::add_element($doc, $root, "link", "", $attributes);
+
+ self::hublinks($doc, $root);
+
+ $attributes = array("href" => App::get_baseurl()."/salmon/".$owner["nick"], "rel" => "salmon");
+ xml::add_element($doc, $root, "link", "", $attributes);
+
+ $attributes = array("href" => App::get_baseurl()."/salmon/".$owner["nick"], "rel" => "http://salmon-protocol.org/ns/salmon-replies");
+ xml::add_element($doc, $root, "link", "", $attributes);
+
+ $attributes = array("href" => App::get_baseurl()."/salmon/".$owner["nick"], "rel" => "http://salmon-protocol.org/ns/salmon-mention");
+ xml::add_element($doc, $root, "link", "", $attributes);
+
+ $attributes = array("href" => App::get_baseurl()."/api/statuses/user_timeline/".$owner["nick"].".atom",
+ "rel" => "self", "type" => "application/atom+xml");
+ xml::add_element($doc, $root, "link", "", $attributes);
+
+ return $root;
+ }
+
+ /**
+ * @brief Add the link to the push hubs to the XML document
+ *
+ * @param object $doc XML document
+ * @param object $root XML root element where the hub links are added
+ */
+ public static function hublinks($doc, $root) {
+ $hub = get_config('system','huburl');
+
+ $hubxml = '';
+ if(strlen($hub)) {
+ $hubs = explode(',', $hub);
+ if(count($hubs)) {
+ foreach($hubs as $h) {
+ $h = trim($h);
+ if(! strlen($h))
+ continue;
+ if ($h === '[internal]')
+ $h = App::get_baseurl() . '/pubsubhubbub';
+ xml::add_element($doc, $root, "link", "", array("href" => $h, "rel" => "hub"));
+ }
+ }
+ }
+ }
+
+ /**
+ * @brief Adds attachement data to the XML document
+ *
+ * @param object $doc XML document
+ * @param object $root XML root element where the hub links are added
+ * @param array $item Data of the item that is to be posted
+ */
+ private function get_attachment($doc, $root, $item) {
+ $o = "";
+ $siteinfo = get_attached_data($item["body"]);
+
+ switch($siteinfo["type"]) {
+ case 'link':
+ $attributes = array("rel" => "enclosure",
+ "href" => $siteinfo["url"],
+ "type" => "text/html; charset=UTF-8",
+ "length" => "",
+ "title" => $siteinfo["title"]);
+ xml::add_element($doc, $root, "link", "", $attributes);
+ break;
+ case 'photo':
+ $imgdata = get_photo_info($siteinfo["image"]);
+ $attributes = array("rel" => "enclosure",
+ "href" => $siteinfo["image"],
+ "type" => $imgdata["mime"],
+ "length" => intval($imgdata["size"]));
+ xml::add_element($doc, $root, "link", "", $attributes);
+ break;
+ case 'video':
+ $attributes = array("rel" => "enclosure",
+ "href" => $siteinfo["url"],
+ "type" => "text/html; charset=UTF-8",
+ "length" => "",
+ "title" => $siteinfo["title"]);
+ xml::add_element($doc, $root, "link", "", $attributes);
+ break;
+ default:
+ break;
+ }
+
+ if (($siteinfo["type"] != "photo") AND isset($siteinfo["image"])) {
+ $photodata = get_photo_info($siteinfo["image"]);
+
+ $attributes = array("rel" => "preview", "href" => $siteinfo["image"], "media:width" => $photodata[0], "media:height" => $photodata[1]);
+ xml::add_element($doc, $root, "link", "", $attributes);
+ }
+
+
+ $arr = explode('[/attach],',$item['attach']);
+ if(count($arr)) {
+ foreach($arr as $r) {
+ $matches = false;
+ $cnt = preg_match('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\" title=\"(.*?)\"|',$r,$matches);
+ if($cnt) {
+ $attributes = array("rel" => "enclosure",
+ "href" => $matches[1],
+ "type" => $matches[3]);
+
+ if(intval($matches[2]))
+ $attributes["length"] = intval($matches[2]);
+
+ if(trim($matches[4]) != "")
+ $attributes["title"] = trim($matches[4]);
+
+ xml::add_element($doc, $root, "link", "", $attributes);
+ }
+ }
+ }
+ }
+
+ /**
+ * @brief Adds the author element to the XML document
+ *
+ * @param object $doc XML document
+ * @param array $owner Contact data of the poster
+ *
+ * @return object author element
+ */
+ private function add_author($doc, $owner) {
+
+ $r = q("SELECT `homepage` FROM `profile` WHERE `uid` = %d AND `is-default` LIMIT 1", intval($owner["uid"]));
+ if ($r)
+ $profile = $r[0];
+
+ $author = $doc->createElement("author");
+ xml::add_element($doc, $author, "activity:object-type", ACTIVITY_OBJ_PERSON);
+ xml::add_element($doc, $author, "uri", $owner["url"]);
+ xml::add_element($doc, $author, "name", $owner["name"]);
+ xml::add_element($doc, $author, "summary", bbcode($owner["about"], false, false, 7));
+
+ $attributes = array("rel" => "alternate", "type" => "text/html", "href" => $owner["url"]);
+ xml::add_element($doc, $author, "link", "", $attributes);
+
+ $attributes = array(
+ "rel" => "avatar",
+ "type" => "image/jpeg", // To-Do?
+ "media:width" => 175,
+ "media:height" => 175,
+ "href" => $owner["photo"]);
+ xml::add_element($doc, $author, "link", "", $attributes);
+
+ if (isset($owner["thumb"])) {
+ $attributes = array(
+ "rel" => "avatar",
+ "type" => "image/jpeg", // To-Do?
+ "media:width" => 80,
+ "media:height" => 80,
+ "href" => $owner["thumb"]);
+ xml::add_element($doc, $author, "link", "", $attributes);
+ }
+
+ xml::add_element($doc, $author, "poco:preferredUsername", $owner["nick"]);
+ xml::add_element($doc, $author, "poco:displayName", $owner["name"]);
+ xml::add_element($doc, $author, "poco:note", bbcode($owner["about"], false, false, 7));
+
+ if (trim($owner["location"]) != "") {
+ $element = $doc->createElement("poco:address");
+ xml::add_element($doc, $element, "poco:formatted", $owner["location"]);
+ $author->appendChild($element);
+ }
+
+ if (trim($profile["homepage"]) != "") {
+ $urls = $doc->createElement("poco:urls");
+ xml::add_element($doc, $urls, "poco:type", "homepage");
+ xml::add_element($doc, $urls, "poco:value", $profile["homepage"]);
+ xml::add_element($doc, $urls, "poco:primary", "true");
+ $author->appendChild($urls);
+ }
+
+ if (count($profile)) {
+ xml::add_element($doc, $author, "followers", "", array("url" => App::get_baseurl()."/viewcontacts/".$owner["nick"]));
+ xml::add_element($doc, $author, "statusnet:profile_info", "", array("local_id" => $owner["uid"]));
+ }
+
+ return $author;
+ }
+
+ /**
+ * @TODO Picture attachments should look like this:
+ * <a href="https://status.pirati.ca/attachment/572819" title="https://status.pirati.ca/file/heluecht-20151202T222602-rd3u49p.gif"
+ * class="attachment thumbnail" id="attachment-572819" rel="nofollow external">https://status.pirati.ca/attachment/572819</a>
+ *
+ */
+
+ /**
+ * @brief Returns the given activity if present - otherwise returns the "post" activity
+ *
+ * @param array $item Data of the item that is to be posted
+ *
+ * @return string activity
+ */
+ function construct_verb($item) {
+ if ($item['verb'])
+ return $item['verb'];
+ return ACTIVITY_POST;
+ }
+
+ /**
+ * @brief Returns the given object type if present - otherwise returns the "note" object type
+ *
+ * @param array $item Data of the item that is to be posted
+ *
+ * @return string Object type
+ */
+ function construct_objecttype($item) {
+ if (in_array($item['object-type'], array(ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_COMMENT)))
+ return $item['object-type'];
+ return ACTIVITY_OBJ_NOTE;
+ }
+
+ /**
+ * @brief Adds an entry element to the XML document
+ *
+ * @param object $doc XML document
+ * @param array $item Data of the item that is to be posted
+ * @param array $owner Contact data of the poster
+ * @param bool $toplevel
+ *
+ * @return object Entry element
+ */
+ private function entry($doc, $item, $owner, $toplevel = false) {
+ $repeated_guid = self::get_reshared_guid($item);
+ if ($repeated_guid != "")
+ $xml = self::reshare_entry($doc, $item, $owner, $repeated_guid, $toplevel);
+
+ if ($xml)
+ return $xml;
+
+ if ($item["verb"] == ACTIVITY_LIKE)
+ return self::like_entry($doc, $item, $owner, $toplevel);
+ else
+ return self::note_entry($doc, $item, $owner, $toplevel);
+ }