From c8449e6019b0ec6d77b4f652500cc18d8e73c09e Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Mon, 4 Jan 2016 20:41:24 +0100 Subject: [PATCH 01/18] Code cleanup --- include/items.php | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/include/items.php b/include/items.php index c9e13b1a1..02942db97 100644 --- a/include/items.php +++ b/include/items.php @@ -19,7 +19,7 @@ require_once('mod/share.php'); require_once('library/defuse/php-encryption-1.2.1/Crypto.php'); -function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0, $forpubsub = false) { +function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) { $sitefeed = ((strlen($owner_nick)) ? false : true); // not yet implemented, need to rewrite huge chunks of following logic @@ -120,18 +120,8 @@ function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0, else $sort = 'ASC'; - // Include answers to status.net posts in pubsub feeds - if($forpubsub) { - $sql_post_table = "INNER JOIN `thread` ON `thread`.`iid` = `item`.`parent` - LEFT JOIN `item` AS `thritem` ON `thritem`.`uri`=`item`.`thr-parent` AND `thritem`.`uid`=`item`.`uid`"; - $visibility = sprintf("AND (`item`.`parent` = `item`.`id`) OR (`item`.`network` = '%s' AND ((`thread`.`network`='%s') OR (`thritem`.`network` = '%s')))", - dbesc(NETWORK_DFRN), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_OSTATUS)); - $date_field = "`received`"; - $sql_order = "`item`.`received` DESC"; - } else { - $date_field = "`changed`"; - $sql_order = "`item`.`parent` ".$sort.", `item`.`created` ASC"; - } + $date_field = "`changed`"; + $sql_order = "`item`.`parent` ".$sort.", `item`.`created` ASC"; if(! strlen($last_update)) $last_update = 'now -30 days'; From ea9a42259df530d280f4a4331a9fca7737a79de1 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Fri, 22 Jan 2016 01:58:36 +0100 Subject: [PATCH 02/18] First version of dfrn.php - unfinished --- include/dfrn.php | 323 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 323 insertions(+) create mode 100644 include/dfrn.php diff --git a/include/dfrn.php b/include/dfrn.php new file mode 100644 index 000000000..4fdc99172 --- /dev/null +++ b/include/dfrn.php @@ -0,0 +1,323 @@ +argc > 2) { + for($x = 2; $x < $a->argc; $x++) { + if($a->argv[$x] == 'converse') + $converse = true; + if($a->argv[$x] == 'starred') + $starred = true; + if($a->argv[$x] === 'category' && $a->argc > ($x + 1) && strlen($a->argv[$x+1])) + $category = $a->argv[$x+1]; + } + } + + + + // default permissions - anonymous user + + $sql_extra = " AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = '' "; + + $r = q("SELECT `contact`.*, `user`.`uid` AS `user_uid`, `user`.`nickname`, `user`.`timezone`, `user`.`page-flags` + FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid` + WHERE `contact`.`self` = 1 AND `user`.`nickname` = '%s' LIMIT 1", + dbesc($owner_nick) + ); + + if(! count($r)) + killme(); + + $owner = $r[0]; + $owner_id = $owner['user_uid']; + $owner_nick = $owner['nickname']; + + $birthday = feed_birthday($owner_id,$owner['timezone']); + + $sql_post_table = ""; + $visibility = ""; + + if(! $public_feed) { + + $sql_extra = ''; + switch($direction) { + case (-1): + $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($dfrn_id)); + $my_id = $dfrn_id; + break; + case 0: + $sql_extra = sprintf(" AND `issued-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); + $my_id = '1:' . $dfrn_id; + break; + case 1: + $sql_extra = sprintf(" AND `dfrn-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); + $my_id = '0:' . $dfrn_id; + break; + default: + return false; + break; // NOTREACHED + } + + $r = q("SELECT * FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `contact`.`uid` = %d $sql_extra LIMIT 1", + intval($owner_id) + ); + + if(! count($r)) + killme(); + + $contact = $r[0]; + require_once('include/security.php'); + $groups = init_groups_visitor($contact['id']); + + if(count($groups)) { + for($x = 0; $x < count($groups); $x ++) + $groups[$x] = '<' . intval($groups[$x]) . '>' ; + $gs = implode('|', $groups); + } + else + $gs = '<<>>' ; // Impossible to match + + $sql_extra = sprintf(" + AND ( `allow_cid` = '' OR `allow_cid` REGEXP '<%d>' ) + AND ( `deny_cid` = '' OR NOT `deny_cid` REGEXP '<%d>' ) + AND ( `allow_gid` = '' OR `allow_gid` REGEXP '%s' ) + AND ( `deny_gid` = '' OR NOT `deny_gid` REGEXP '%s') + ", + intval($contact['id']), + intval($contact['id']), + dbesc($gs), + dbesc($gs) + ); + } + + if($public_feed) + $sort = 'DESC'; + else + $sort = 'ASC'; + + $date_field = "`changed`"; + $sql_order = "`item`.`parent` ".$sort.", `item`.`created` ASC"; + + if(! strlen($last_update)) + $last_update = 'now -30 days'; + + if(isset($category)) { + $sql_post_table = sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ", + dbesc(protect_sprintf($category)), intval(TERM_OBJ_POST), intval(TERM_CATEGORY), intval($owner_id)); + //$sql_extra .= file_tag_file_query('item',$category,'category'); + } + + if($public_feed) { + if(! $converse) + $sql_extra .= " AND `contact`.`self` = 1 "; + } + + $check_date = datetime_convert('UTC','UTC',$last_update,'Y-m-d H:i:s'); + + // AND ( `item`.`edited` > '%s' OR `item`.`changed` > '%s' ) + // dbesc($check_date), + + $r = q("SELECT STRAIGHT_JOIN `item`.*, `item`.`id` AS `item_id`, + `contact`.`name`, `contact`.`network`, `contact`.`photo`, `contact`.`url`, + `contact`.`name-date`, `contact`.`uri-date`, `contact`.`avatar-date`, + `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, + `contact`.`id` AS `contact-id`, `contact`.`uid` AS `contact-uid`, + `sign`.`signed_text`, `sign`.`signature`, `sign`.`signer` + FROM `item` $sql_post_table + INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` + AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0 + LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` + WHERE `item`.`uid` = %d AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`parent` != 0 + AND ((`item`.`wall` = 1) $visibility) AND `item`.$date_field > '%s' + $sql_extra + ORDER BY $sql_order LIMIT 0, 300", + intval($owner_id), + dbesc($check_date), + dbesc($sort) + ); + + // Will check further below if this actually returned results. + // We will provide an empty feed if that is the case. + + $items = $r; + + //$feed_template = get_markup_template(($dfrn_id) ? 'atom_feed_dfrn.tpl' : 'atom_feed.tpl'); + + //$atom = ''; + $doc = new DOMDocument('1.0', 'utf-8'); + $doc->formatOutput = true; + + $xpath = new DomXPath($doc); + $xpath->registerNamespace('atom', "http://www.w3.org/2005/Atom"); + $xpath->registerNamespace('thr', "http://purl.org/syndication/thread/1.0"); + $xpath->registerNamespace('georss', "http://www.georss.org/georss"); + $xpath->registerNamespace('activity', "http://activitystrea.ms/spec/1.0/"); + $xpath->registerNamespace('media', "http://purl.org/syndication/atommedia"); + $xpath->registerNamespace('poco', "http://portablecontacts.net/spec/1.0"); + $xpath->registerNamespace('ostatus', "http://ostatus.org/schema/1.0"); + $xpath->registerNamespace('statusnet', "http://status.net/schema/api/1/"); + + $root = ostatus_add_header($doc, $owner); + dfrn_add_header($root, $doc, $xpath, $owner); + + // Todo $hubxml = feed_hublinks(); + + // Todo $salmon = feed_salmonlinks($owner_nick); + + // todo $alternatelink = $owner['url']; + +/* + if(isset($category)) + $alternatelink .= "/category/".$category; + + $atom .= replace_macros($feed_template, array( + '$version' => xmlify(FRIENDICA_VERSION), + '$feed_id' => xmlify($a->get_baseurl() . '/profile/' . $owner_nick), + '$feed_title' => xmlify($owner['name']), + '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', 'now' , ATOM_TIME)) , + '$hub' => $hubxml, + '$salmon' => $salmon, + '$alternatelink' => xmlify($alternatelink), + '$name' => xmlify($owner['name']), + '$profile_page' => xmlify($owner['url']), + '$photo' => xmlify($owner['photo']), + '$thumb' => xmlify($owner['thumb']), + '$picdate' => xmlify(datetime_convert('UTC','UTC',$owner['avatar-date'] . '+00:00' , ATOM_TIME)) , + '$uridate' => xmlify(datetime_convert('UTC','UTC',$owner['uri-date'] . '+00:00' , ATOM_TIME)) , + '$namdate' => xmlify(datetime_convert('UTC','UTC',$owner['name-date'] . '+00:00' , ATOM_TIME)) , + '$birthday' => ((strlen($birthday)) ? '' . xmlify($birthday) . '' : ''), + '$community' => (($owner['page-flags'] == PAGE_COMMUNITY) ? '1' : '') + )); +*/ + call_hooks('atom_feed', $atom); + + if(! count($items)) { + + call_hooks('atom_feed_end', $atom); + + //$atom .= '' . "\r\n"; + //return $atom; + return(trim($doc->saveXML())); + } + + foreach($items as $item) { + + // prevent private email from leaking. + if($item['network'] === NETWORK_MAIL) + continue; + + // public feeds get html, our own nodes use bbcode + + if($public_feed) { + $type = 'html'; + // catch any email that's in a public conversation and make sure it doesn't leak + if($item['private']) + continue; + } + else { + $type = 'text'; + } + + //$atom .= atom_entry($item,$type,null,$owner,true); + $entry = ostatus_entry($doc, $item, $owner); + dfrn_entry($entry, $doc, $xpath, $item, $owner); + $root->appendChild($entry); + + } + + call_hooks('atom_feed_end', $atom); + + //$atom .= '' . "\r\n"; + + //return $atom; + return(trim($doc->saveXML())); +} + +/** + * @brief Adds the header elements for thr DFRN protocol + * + * We use the XML from OStatus as a base and are adding the DFRN parts to it. + * + * @root Class XML root element + * @doc Class XML document + * @xpath Class XML xpath + * @owner array Owner record + * + */ +function dfrn_add_header(&$root, $doc, $xpath, $owner) { + + $root->setAttribute("xmlns:at", "http://purl.org/atompub/tombstones/1.0"); + $root->setAttribute("xmlns:xmlns:dfrn", "http://purl.org/macgirvin/dfrn/1.0"); + + $attributes = array("href" => "http://creativecommons.org/licenses/by/3.0/", "rel" => "license"); + xml_add_element($doc, $root, "link", "", $attributes); + + xml_replace_element($doc, $root, $xpath, "title", $owner["name"]); + xml_remove_element($root, $xpath, "/atom:feed/subtitle"); + xml_remove_element($root, $xpath, "/atom:feed/logo"); + xml_remove_element($root, $xpath, "/atom:feed/author"); + + $author = dfrn_add_author($doc, $owner); + $root->appendChild($author); +} + +function dfrn_add_author($doc, $owner) { + $a = get_app(); + + $author = $doc->createElement("author"); + + $namdate = datetime_convert('UTC', 'UTC', $owner['name-date'].'+00:00' , ATOM_TIME); + $uridate = datetime_convert('UTC', 'UTC', $owner['uri-date'].'+00:00', ATOM_TIME); + $picdate = datetime_convert('UTC', 'UTC', $owner['avatar-date'].'+00:00', ATOM_TIME); + + $attributes = array("dfrn:updated" => $namdate); + xml_add_element($doc, $author, "name", $owner["name"], $attributes); + + $attributes = array("dfrn:updated" => $namdate); + xml_add_element($doc, $author, "uri", $a->get_baseurl().'/profile/'.$owner["nickname"], $attributes); + + $attributes = array("rel" => "photo", "type" => "image/jpeg", "dfrn:updated" => $picdate, + "media:width" => 175, "media:height" => 175, "href" => $owner['photo']); + xml_add_element($doc, $author, "link", "", $attributes); + + $attributes = array("rel" => "avatar", "type" => "image/jpeg", "dfrn:updated" => $picdate, + "media:width" => 175, "media:height" => 175, "href" => $owner['photo']); + xml_add_element($doc, $author, "link", "", $attributes); + + return $author; +} + +function dfrn_entry($entry, $doc, $xpath, $item, $owner) { + $a = get_app(); + + $author = ostatus_add_author($doc, $owner); + $entry->appendChild($author); + +} + +function xml_replace_element($doc, $parent, $xpath, $element, $value = "", $attributes = array()) { + $old_element = $xpath->query("/atom:feed/".$element)->item(0); + + $element = $doc->createElement($element, xmlify($value)); + + foreach ($attributes AS $key => $value) { + $attribute = $doc->createAttribute($key); + $attribute->value = xmlify($value); + $element->appendChild($attribute); + } + + $parent->replaceChild($element, $old_element); +} + +function xml_remove_element($parent, $xpath, $element) { + $old_element = $xpath->query($element)->item(0); + $parent->removeChild($old_element); +} From c66b4387bf87874f18c52a94d719c118c58c2c7c Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Fri, 22 Jan 2016 20:26:11 +0100 Subject: [PATCH 03/18] dfrn functions could now work/Removed unused code --- include/Contact.php | 10 +- include/cron.php | 1 - include/delivery.php | 1 - include/dfrn.php | 426 +++++++++++++++++++++++++++++++++---------- include/expire.php | 1 - include/items.php | 70 +------ include/onepoll.php | 1 - mod/dfrn_notify.php | 3 +- 8 files changed, 340 insertions(+), 173 deletions(-) diff --git a/include/Contact.php b/include/Contact.php index 93d6237cb..f80cb80e2 100644 --- a/include/Contact.php +++ b/include/Contact.php @@ -208,15 +208,15 @@ function get_contact_details_by_url($url, $uid = -1) { } // Fetching further contact data from the contact table - $r = q("SELECT `id`, `uid`, `url`, `network`, `name`, `nick`, `addr`, `location`, `about`, `keywords`, `gender`, `photo`, `addr`, `forum`, `prv`, `bd` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d AND `network` = '%s'", + $r = q("SELECT `id`, `uid`, `url`, `network`, `name`, `nick`, `addr`, `location`, `about`, `keywords`, `gender`, `photo`, `thumb`, `addr`, `forum`, `prv`, `bd`, `self` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d AND `network` IN ('%s', '')", dbesc(normalise_link($url)), intval($uid), dbesc($profile["network"])); if (!count($r) AND !isset($profile)) - $r = q("SELECT `id`, `uid`, `url`, `network`, `name`, `nick`, `addr`, `location`, `about`, `keywords`, `gender`, `photo`, `addr`, `forum`, `prv`, `bd` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d", + $r = q("SELECT `id`, `uid`, `url`, `network`, `name`, `nick`, `addr`, `location`, `about`, `keywords`, `gender`, `photo`, `thumb`, `addr`, `forum`, `prv`, `bd`, `self` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d", dbesc(normalise_link($url)), intval($uid)); if (!count($r) AND !isset($profile)) - $r = q("SELECT `id`, `uid`, `url`, `network`, `name`, `nick`, `addr`, `location`, `about`, `keywords`, `gender`, `photo`, `addr`, `forum`, `prv`, `bd` FROM `contact` WHERE `nurl` = '%s' AND `uid` = 0", + $r = q("SELECT `id`, `uid`, `url`, `network`, `name`, `nick`, `addr`, `location`, `about`, `keywords`, `gender`, `photo`, `thumb`, `addr`, `forum`, `prv`, `bd` FROM `contact` WHERE `nurl` = '%s' AND `uid` = 0", dbesc(normalise_link($url))); if ($r) { @@ -228,7 +228,7 @@ function get_contact_details_by_url($url, $uid = -1) { $profile["nick"] = $r[0]["nick"]; if (!isset($profile["addr"]) AND $r[0]["addr"]) $profile["addr"] = $r[0]["addr"]; - if (!isset($profile["photo"]) AND $r[0]["photo"]) + if ((!isset($profile["photo"]) OR $r[0]["self"]) AND $r[0]["photo"]) $profile["photo"] = $r[0]["photo"]; if (!isset($profile["location"]) AND $r[0]["location"]) $profile["location"] = $r[0]["location"]; @@ -246,6 +246,8 @@ function get_contact_details_by_url($url, $uid = -1) { $profile["addr"] = $r[0]["addr"]; if (!isset($profile["bd"]) AND $r[0]["bd"]) $profile["bd"] = $r[0]["bd"]; + if (isset($r[0]["thumb"])) + $profile["thumb"] = $r[0]["thumb"]; if ($r[0]["uid"] == 0) $profile["cid"] = 0; else diff --git a/include/cron.php b/include/cron.php index bf3243cb6..d8ebf7de6 100644 --- a/include/cron.php +++ b/include/cron.php @@ -30,7 +30,6 @@ function cron_run(&$argv, &$argc){ require_once('include/session.php'); require_once('include/datetime.php'); - require_once('library/simplepie/simplepie.inc'); require_once('include/items.php'); require_once('include/Contact.php'); require_once('include/email.php'); diff --git a/include/delivery.php b/include/delivery.php index a88873361..0007b96ae 100644 --- a/include/delivery.php +++ b/include/delivery.php @@ -458,7 +458,6 @@ function delivery_run(&$argv, &$argc){ if (($x[0]['page-flags'] == PAGE_SOAPBOX) AND $top_level) break; - require_once('library/simplepie/simplepie.inc'); logger('mod-delivery: local delivery'); local_delivery($x[0],$atom); break; diff --git a/include/dfrn.php b/include/dfrn.php index 4fdc99172..775455b83 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -2,6 +2,24 @@ require_once('include/items.php'); +function dfrn_entries($items,$owner) { + + $doc = new DOMDocument('1.0', 'utf-8'); + $doc->formatOutput = true; + + $root = dfrn_add_header($doc, $owner, "dfrn:owner"); + + if(! count($items)) + return trim($doc->saveXML()); + + foreach($items as $item) { + $entry = dfrn_entry($doc, "text", $item, $owner, $item["entry:comment-allow"], $item["entry:cid"]); + $root->appendChild($entry); + } + + return(trim($doc->saveXML())); +} + function dfrn_feed(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) { @@ -40,8 +58,6 @@ function dfrn_feed(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) { $owner_id = $owner['user_uid']; $owner_nick = $owner['nickname']; - $birthday = feed_birthday($owner_id,$owner['timezone']); - $sql_post_table = ""; $visibility = ""; @@ -149,63 +165,25 @@ function dfrn_feed(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) { $items = $r; - //$feed_template = get_markup_template(($dfrn_id) ? 'atom_feed_dfrn.tpl' : 'atom_feed.tpl'); - - //$atom = ''; $doc = new DOMDocument('1.0', 'utf-8'); $doc->formatOutput = true; - $xpath = new DomXPath($doc); - $xpath->registerNamespace('atom', "http://www.w3.org/2005/Atom"); - $xpath->registerNamespace('thr', "http://purl.org/syndication/thread/1.0"); - $xpath->registerNamespace('georss', "http://www.georss.org/georss"); - $xpath->registerNamespace('activity', "http://activitystrea.ms/spec/1.0/"); - $xpath->registerNamespace('media', "http://purl.org/syndication/atommedia"); - $xpath->registerNamespace('poco', "http://portablecontacts.net/spec/1.0"); - $xpath->registerNamespace('ostatus', "http://ostatus.org/schema/1.0"); - $xpath->registerNamespace('statusnet', "http://status.net/schema/api/1/"); + $alternatelink = $owner['url']; - $root = ostatus_add_header($doc, $owner); - dfrn_add_header($root, $doc, $xpath, $owner); - - // Todo $hubxml = feed_hublinks(); - - // Todo $salmon = feed_salmonlinks($owner_nick); - - // todo $alternatelink = $owner['url']; - -/* if(isset($category)) $alternatelink .= "/category/".$category; - $atom .= replace_macros($feed_template, array( - '$version' => xmlify(FRIENDICA_VERSION), - '$feed_id' => xmlify($a->get_baseurl() . '/profile/' . $owner_nick), - '$feed_title' => xmlify($owner['name']), - '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', 'now' , ATOM_TIME)) , - '$hub' => $hubxml, - '$salmon' => $salmon, - '$alternatelink' => xmlify($alternatelink), - '$name' => xmlify($owner['name']), - '$profile_page' => xmlify($owner['url']), - '$photo' => xmlify($owner['photo']), - '$thumb' => xmlify($owner['thumb']), - '$picdate' => xmlify(datetime_convert('UTC','UTC',$owner['avatar-date'] . '+00:00' , ATOM_TIME)) , - '$uridate' => xmlify(datetime_convert('UTC','UTC',$owner['uri-date'] . '+00:00' , ATOM_TIME)) , - '$namdate' => xmlify(datetime_convert('UTC','UTC',$owner['name-date'] . '+00:00' , ATOM_TIME)) , - '$birthday' => ((strlen($birthday)) ? '' . xmlify($birthday) . '' : ''), - '$community' => (($owner['page-flags'] == PAGE_COMMUNITY) ? '1' : '') - )); -*/ - call_hooks('atom_feed', $atom); + $root = dfrn_add_header($doc, $owner, "author", $alternatelink); + + // This hook can't work anymore + // call_hooks('atom_feed', $atom); if(! count($items)) { + $atom = trim($doc->saveXML()); call_hooks('atom_feed_end', $atom); - //$atom .= '' . "\r\n"; - //return $atom; - return(trim($doc->saveXML())); + return $atom; } foreach($items as $item) { @@ -226,19 +204,16 @@ function dfrn_feed(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) { $type = 'text'; } - //$atom .= atom_entry($item,$type,null,$owner,true); - $entry = ostatus_entry($doc, $item, $owner); - dfrn_entry($entry, $doc, $xpath, $item, $owner); + $entry = dfrn_entry($doc, $type, $item, $owner, true); $root->appendChild($entry); } + $atom = trim($doc->saveXML()); + call_hooks('atom_feed_end', $atom); - //$atom .= '' . "\r\n"; - - //return $atom; - return(trim($doc->saveXML())); + return $atom; } /** @@ -246,33 +221,68 @@ function dfrn_feed(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) { * * We use the XML from OStatus as a base and are adding the DFRN parts to it. * - * @root Class XML root element * @doc Class XML document - * @xpath Class XML xpath * @owner array Owner record * + * @return Class XML root object */ -function dfrn_add_header(&$root, $doc, $xpath, $owner) { - - $root->setAttribute("xmlns:at", "http://purl.org/atompub/tombstones/1.0"); - $root->setAttribute("xmlns:xmlns:dfrn", "http://purl.org/macgirvin/dfrn/1.0"); - - $attributes = array("href" => "http://creativecommons.org/licenses/by/3.0/", "rel" => "license"); - xml_add_element($doc, $root, "link", "", $attributes); - - xml_replace_element($doc, $root, $xpath, "title", $owner["name"]); - xml_remove_element($root, $xpath, "/atom:feed/subtitle"); - xml_remove_element($root, $xpath, "/atom:feed/logo"); - xml_remove_element($root, $xpath, "/atom:feed/author"); - - $author = dfrn_add_author($doc, $owner); - $root->appendChild($author); -} - -function dfrn_add_author($doc, $owner) { +function dfrn_add_header($doc, $owner, $authorelement, $alternatelink = "") { $a = get_app(); - $author = $doc->createElement("author"); + if ($alternatelink == "") + $alternatelink = $owner['url']; + + $root = $doc->createElementNS(NS_ATOM, 'feed'); + $doc->appendChild($root); + + $root->setAttribute("xmlns:thr", NS_THR); + $root->setAttribute("xmlns:at", "http://purl.org/atompub/tombstones/1.0"); + $root->setAttribute("xmlns:media", NS_MEDIA); + $root->setAttribute("xmlns:dfrn", "http://purl.org/macgirvin/dfrn/1.0"); + $root->setAttribute("xmlns:activity", NS_ACTIVITY); + $root->setAttribute("xmlns:georss", NS_GEORSS); + $root->setAttribute("xmlns:poco", NS_POCO); + $root->setAttribute("xmlns:ostatus", NS_OSTATUS); + $root->setAttribute("xmlns:statusnet", NS_STATUSNET); + + xml_add_element($doc, $root, "id", $a->get_baseurl()."/profile/".$owner["nick"]); + xml_add_element($doc, $root, "title", $owner["name"]); + + $attributes = array("uri" => "https://friendi.ca", "version" => FRIENDICA_VERSION."-".DB_UPDATE_VERSION); + xml_add_element($doc, $root, "generator", FRIENDICA_PLATFORM, $attributes); + + $attributes = array("rel" => "license", "href" => "http://creativecommons.org/licenses/by/3.0/"); + xml_add_element($doc, $root, "link", "", $attributes); + + $attributes = array("rel" => "alternate", "type" => "text/html", "href" => $alternatelink); + xml_add_element($doc, $root, "link", "", $attributes); + + ostatus_hublinks($doc, $root); + + $attributes = array("rel" => "salmon", "href" => $a->get_baseurl()."/salmon/".$owner["nick"]); + xml_add_element($doc, $root, "link", "", $attributes); + + $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-replies", "href" => $a->get_baseurl()."/salmon/".$owner["nick"]); + xml_add_element($doc, $root, "link", "", $attributes); + + $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-mention", "href" => $a->get_baseurl()."/salmon/".$owner["nick"]); + xml_add_element($doc, $root, "link", "", $attributes); + + if ($owner['page-flags'] == PAGE_COMMUNITY) + xml_add_element($doc, $root, "dfrn:community", 1); + + xml_add_element($doc, $root, "updated", datetime_convert("UTC", "UTC", "now", ATOM_TIME)); + + $author = dfrn_add_author($doc, $owner, $authorelement); + $root->appendChild($author); + + return $root; +} + +function dfrn_add_author($doc, $owner, $authorelement) { + $a = get_app(); + + $author = $doc->createElement($authorelement); $namdate = datetime_convert('UTC', 'UTC', $owner['name-date'].'+00:00' , ATOM_TIME); $uridate = datetime_convert('UTC', 'UTC', $owner['uri-date'].'+00:00', ATOM_TIME); @@ -292,32 +302,256 @@ function dfrn_add_author($doc, $owner) { "media:width" => 175, "media:height" => 175, "href" => $owner['photo']); xml_add_element($doc, $author, "link", "", $attributes); + $birthday = feed_birthday($owner['user_uid'], $owner['timezone']); + + if ($birthday) + xml_add_element($doc, $author, "dfrn:birthday", $birthday); + return $author; } -function dfrn_entry($entry, $doc, $xpath, $item, $owner) { +function dfrn_add_entry_author($doc, $element, $contact_url, $item) { $a = get_app(); - $author = ostatus_add_author($doc, $owner); + $contact = get_contact_details_by_url($contact_url, $item["uid"]); + + $r = q("SELECT `profile`.`about`, `profile`.`name`, `profile`.`homepage`, `contact`.`nick`, `contact`.`location` FROM `profile` + INNER JOIN `contact` ON `contact`.`uid` = `profile`.`uid` + INNER JOIN `user` ON `user`.`uid` = `profile`.`uid` + WHERE `contact`.`self` AND `profile`.`is-default` AND NOT `user`.`hidewall` AND `contact`.`nurl`='%s'", + dbesc(normalise_link($contact_url))); + if ($r) + $profile = $r[0]; + + $author = $doc->createElement($element); + xml_add_element($doc, $author, "name", $contact["name"]); + xml_add_element($doc, $author, "uri", $contact["url"]); + + /// @Todo + /// - Check real image type and image size + /// - Check which of these boths elements we really use + $attributes = array( + "rel" => "photo", + "type" => "image/jpeg", + "media:width" => 80, + "media:height" => 80, + "href" => $contact["photo"]); + xml_add_element($doc, $author, "link", "", $attributes); + + $attributes = array( + "rel" => "avatar", + "type" => "image/jpeg", + "media:width" => 80, + "media:height" => 80, + "href" => $contact["photo"]); + xml_add_element($doc, $author, "link", "", $attributes); + + // Only show contact details when it is a user from our system and we are allowed to + if ($profile) { + xml_add_element($doc, $author, "poco:preferredUsername", $profile["nick"]); + xml_add_element($doc, $author, "poco:displayName", $profile["name"]); + xml_add_element($doc, $author, "poco:note", $profile["about"]); + + if (trim($contact["location"]) != "") { + $element = $doc->createElement("poco:address"); + xml_add_element($doc, $element, "poco:formatted", $profile["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); + } + } + + return $author; +} + +function dfrn_create_activity($doc, $element, $activity) { + + if($activity) { + $entry = $doc->createElement($element); + + $r = parse_xml_string($activity, false); + if(!$r) + return false; + if($r->type) + xml_add_element($doc, $entry, "activity:object-type", $r->type); + if($r->id) + xml_add_element($doc, $entry, "id", $r->id); + if($r->title) + xml_add_element($doc, $entry, "title", $r->title); + if($r->link) { + if(substr($r->link,0,1) === '<') { + if(strstr($r->link,'&') && (! strstr($r->link,'&'))) + $r->link = str_replace('&','&', $r->link); + + $r->link = preg_replace('/\/','',$r->link); + + $data = parse_xml_string($r->link, false); + foreach ($data->attributes() AS $parameter => $value) + $attributes[$parameter] = $value; + } else + $attributes = array("rel" => "alternate", "type" => "text/html", "href" => $r->link); + + xml_add_element($doc, $entry, "link", "", $attributes); + } + if($r->content) + xml_add_element($doc, $entry, "content", bbcode($r->content), array("type" => "html")); + + return $entry; + } + + return false; +} + +function dfrn_get_attachment($doc, $root, $item) { + $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); + } + } + } +} + +function dfrn_entry($doc, $type, $item, $owner, $comment = false, $cid = 0) { + $a = get_app(); + + $mentioned = array(); + + if(!$item['parent']) + return; + + $entry = $doc->createElement("entry"); + + if($item['deleted']) { + $attributes = array("ref" => $item['uri'], "when" => datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)); + xml_add_element($doc, $entry, "at:deleted-entry", "", $attributes); + return $entry; + } + + if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid']) + $body = fix_private_photos($item['body'],$owner['uid'],$item,$cid); + else + $body = $item['body']; + + if ($type == 'html') { + $htmlbody = $body; + + if ($item['title'] != "") + $htmlbody = "[b]".$item['title']."[/b]\n\n".$htmlbody; + + $htmlbody = bbcode($htmlbody, false, false, 7); + } + + $author = dfrn_add_entry_author($doc, "author", $item["author-link"], $item); $entry->appendChild($author); -} - -function xml_replace_element($doc, $parent, $xpath, $element, $value = "", $attributes = array()) { - $old_element = $xpath->query("/atom:feed/".$element)->item(0); - - $element = $doc->createElement($element, xmlify($value)); - - foreach ($attributes AS $key => $value) { - $attribute = $doc->createAttribute($key); - $attribute->value = xmlify($value); - $element->appendChild($attribute); - } - - $parent->replaceChild($element, $old_element); -} - -function xml_remove_element($parent, $xpath, $element) { - $old_element = $xpath->query($element)->item(0); - $parent->removeChild($old_element); + $dfrnowner = dfrn_add_entry_author($doc, "dfrn:owner", $item["owner-link"], $item); + $entry->appendChild($dfrnowner); + + if(($item['parent'] != $item['id']) || ($item['parent-uri'] !== $item['uri']) || (($item['thr-parent'] !== '') && ($item['thr-parent'] !== $item['uri']))) { + $parent = q("SELECT `guid` FROM `item` WHERE `id` = %d", intval($item["parent"])); + $parent_item = (($item['thr-parent']) ? $item['thr-parent'] : $item['parent-uri']); + $attributes = array("ref" => $parent_item, "type" => "text/html", "href" => $a->get_baseurl().'/display/'.$parent[0]['guid']); + xml_add_element($doc, $entry, "thr:in-reply-to", "", $attributes); + } + + xml_add_element($doc, $entry, "id", $item["uri"]); + xml_add_element($doc, $entry, "title", $item["title"]); + + xml_add_element($doc, $entry, "published", datetime_convert("UTC","UTC",$item["created"]."+00:00",ATOM_TIME)); + xml_add_element($doc, $entry, "updated", datetime_convert("UTC","UTC",$item["edited"]."+00:00",ATOM_TIME)); + + xml_add_element($doc, $entry, "dfrn:env", base64url_encode($body, true)); + xml_add_element($doc, $entry, "content", (($type === 'html') ? $htmlbody : $body), array("type" => $type)); + + xml_add_element($doc, $entry, "link", "", array("rel" => "alternate", "type" => "text/html", + "href" => $a->get_baseurl()."/display/".$item["guid"])); + + if ($comment) + xml_add_element($doc, $entry, "dfrn:comment-allow", intval($item['last-child'])); + + if($item['location']) + xml_add_element($doc, $entry, "dfrn:location", $item['location']); + + if($item['coord']) + xml_add_element($doc, $entry, "georss:point", $item['coord']); + + if(($item['private']) || strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])) + xml_add_element($doc, $entry, "dfrn:private", (($item['private']) ? $item['private'] : 1)); + + if($item['extid']) + xml_add_element($doc, $entry, "dfrn:extid", $item['extid']); + + if($item['bookmark']) + xml_add_element($doc, $entry, "dfrn:bookmark", "true"); + + if($item['app']) + xml_add_element($doc, $entry, "statusnet:notice_info", "", array("local_id" => $item['id'], "source" => $item['app'])); + + xml_add_element($doc, $entry, "dfrn:diaspora_guid", $item["guid"]); + + if($item['signed_text']) { + $sign = base64_encode(json_encode(array('signed_text' => $item['signed_text'],'signature' => $item['signature'],'signer' => $item['signer']))); + xml_add_element($doc, $entry, "dfrn:diaspora_signature", $sign); + } + + xml_add_element($doc, $entry, "activity:verb", construct_verb($item)); + + $actobj = dfrn_create_activity($doc, "activity:object", $item['object']); + if ($actobj) + $entry->appendChild($actobj); + + $actarg = dfrn_create_activity($doc, "activity:target", $item['target']); + if ($actarg) + $entry->appendChild($actarg); + + $tags = item_getfeedtags($item); + + if(count($tags)) { + foreach($tags as $t) + if (($type != 'html') OR ($t[0] != "@")) + xml_add_element($doc, $entry, "category", "", array("scheme" => "X-DFRN:".$t[0].":".$t[1], "term" => $t[2])); + } + + if(count($tags)) + foreach($tags as $t) + if ($t[0] == "@") + $mentioned[$t[1]] = $t[1]; + + foreach ($mentioned AS $mention) { + $r = q("SELECT `forum`, `prv` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s'", + intval($owner["uid"]), + dbesc(normalise_link($mention))); + if ($r[0]["forum"] OR $r[0]["prv"]) + xml_add_element($doc, $entry, "link", "", array("rel" => "mentioned", + "ostatus:object-type" => ACTIVITY_OBJ_GROUP, + "href" => $mention)); + else + xml_add_element($doc, $entry, "link", "", array("rel" => "mentioned", + "ostatus:object-type" => ACTIVITY_OBJ_PERSON, + "href" => $mention)); + } + + dfrn_get_attachment($doc, $entry, $item); + + return $entry; } diff --git a/include/expire.php b/include/expire.php index 308680421..873c594e8 100644 --- a/include/expire.php +++ b/include/expire.php @@ -18,7 +18,6 @@ function expire_run(&$argv, &$argc){ require_once('include/session.php'); require_once('include/datetime.php'); - require_once('library/simplepie/simplepie.inc'); require_once('include/items.php'); require_once('include/Contact.php'); diff --git a/include/items.php b/include/items.php index 7931b8c3d..8afee31ad 100644 --- a/include/items.php +++ b/include/items.php @@ -455,17 +455,6 @@ function get_atom_elements($feed, $item, $contact = array()) { $res['body'] = unxmlify($item->get_content()); $res['plink'] = unxmlify($item->get_link(0)); - if (isset($contact["network"]) AND ($contact["network"] == NETWORK_FEED) AND strstr($res['plink'], ".app.net/")) { - logger("get_atom_elements: detected app.net posting: ".print_r($res, true), LOGGER_DEBUG); - $res['title'] = ""; - $res['body'] = nl2br($res['body']); - } - - // removing the content of the title if its identically to the body - // This helps with auto generated titles e.g. from tumblr - if (title_is_body($res["title"], $res["body"])) - $res['title'] = ""; - if($res['plink']) $base_url = implode('/', array_slice(explode('/',$res['plink']),0,3)); else @@ -843,62 +832,6 @@ function get_atom_elements($feed, $item, $contact = array()) { $res['target'] .= '' . "\n"; } - // This is some experimental stuff. By now retweets are shown with "RT:" - // But: There is data so that the message could be shown similar to native retweets - // There is some better way to parse this array - but it didn't worked for me. - $child = $item->feed->data["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["feed"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["entry"][0]["child"]["http://activitystrea.ms/spec/1.0/"][object][0]["child"]; - if (is_array($child)) { - logger('get_atom_elements: Looking for status.net repeated message'); - - $message = $child["http://activitystrea.ms/spec/1.0/"]["object"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["content"][0]["data"]; - $orig_id = ostatus_convert_href($child["http://activitystrea.ms/spec/1.0/"]["object"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]["id"][0]["data"]); - $author = $child[SIMPLEPIE_NAMESPACE_ATOM_10]["author"][0]["child"][SIMPLEPIE_NAMESPACE_ATOM_10]; - $uri = $author["uri"][0]["data"]; - $name = $author["name"][0]["data"]; - $avatar = @array_shift($author["link"][2]["attribs"]); - $avatar = $avatar["href"]; - - if (($name != "") and ($uri != "") and ($avatar != "") and ($message != "")) { - logger('get_atom_elements: fixing sender of repeated message. '.$orig_id, LOGGER_DEBUG); - - if (!intval(get_config('system','wall-to-wall_share'))) { - $prefix = share_header($name, $uri, $avatar, "", "", $orig_link); - - $res["body"] = $prefix.html2bbcode($message)."[/share]"; - } else { - $res["owner-name"] = $res["author-name"]; - $res["owner-link"] = $res["author-link"]; - $res["owner-avatar"] = $res["author-avatar"]; - - $res["author-name"] = $name; - $res["author-link"] = $uri; - $res["author-avatar"] = $avatar; - - $res["body"] = html2bbcode($message); - } - } - } - - if (isset($contact["network"]) AND ($contact["network"] == NETWORK_FEED) AND $contact['fetch_further_information']) { - $preview = ""; - - // Handle enclosures and treat them as preview picture - if (isset($attach)) - foreach ($attach AS $attachment) - if ($attachment->type == "image/jpeg") - $preview = $attachment->link; - - $res["body"] = $res["title"].add_page_info($res['plink'], false, $preview, ($contact['fetch_further_information'] == 2), $contact['ffi_keyword_blacklist']); - $res["tag"] = add_page_keywords($res['plink'], false, $preview, ($contact['fetch_further_information'] == 2), $contact['ffi_keyword_blacklist']); - $res["title"] = ""; - $res["object-type"] = ACTIVITY_OBJ_BOOKMARK; - unset($res["attach"]); - } elseif (isset($contact["network"]) AND ($contact["network"] == NETWORK_OSTATUS)) - $res["body"] = add_page_info_to_body($res["body"]); - elseif (isset($contact["network"]) AND ($contact["network"] == NETWORK_FEED) AND strstr($res['plink'], ".app.net/")) { - $res["body"] = add_page_info_to_body($res["body"]); - } - $arr = array('feed' => $feed, 'item' => $item, 'result' => $res); call_hooks('parse_atom', $arr); @@ -3038,6 +2971,9 @@ function item_is_remote_self($contact, &$datarray) { } function local_delivery($importer,$data) { + + require_once('library/simplepie/simplepie.inc'); + $a = get_app(); logger(__function__, LOGGER_TRACE); diff --git a/include/onepoll.php b/include/onepoll.php index 516f1dfd4..c262e110f 100644 --- a/include/onepoll.php +++ b/include/onepoll.php @@ -27,7 +27,6 @@ function onepoll_run(&$argv, &$argc){ require_once('include/session.php'); require_once('include/datetime.php'); - require_once('library/simplepie/simplepie.inc'); require_once('include/items.php'); require_once('include/Contact.php'); require_once('include/email.php'); diff --git a/mod/dfrn_notify.php b/mod/dfrn_notify.php index fcc572654..4aa777b55 100644 --- a/mod/dfrn_notify.php +++ b/mod/dfrn_notify.php @@ -1,6 +1,5 @@ Date: Sat, 23 Jan 2016 01:07:51 +0100 Subject: [PATCH 04/18] Added documentation, completed the functions --- include/dfrn.php | 217 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 200 insertions(+), 17 deletions(-) diff --git a/include/dfrn.php b/include/dfrn.php index 775455b83..758e03398 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -1,13 +1,21 @@ formatOutput = true; - $root = dfrn_add_header($doc, $owner, "dfrn:owner"); + $root = dfrn_add_header($doc, $owner, "dfrn:owner", "", false); if(! count($items)) return trim($doc->saveXML()); @@ -20,9 +28,19 @@ function dfrn_entries($items,$owner) { return(trim($doc->saveXML())); } +/** + * @brief Adds the header elements for the DFRN protocol + * + * @param App $a + * @param string $dfrn_id + * @param string $owner_nick Owner nick name + * @param string $last_update Date of the last update + * @param int $direction + * + * @return string DFRN feed entries + */ function dfrn_feed(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) { - $sitefeed = ((strlen($owner_nick)) ? false : true); // not yet implemented, need to rewrite huge chunks of following logic $public_feed = (($dfrn_id) ? false : true); $starred = false; // not yet implemented, possible security issues @@ -173,7 +191,7 @@ function dfrn_feed(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) { if(isset($category)) $alternatelink .= "/category/".$category; - $root = dfrn_add_header($doc, $owner, "author", $alternatelink); + $root = dfrn_add_header($doc, $owner, "author", $alternatelink, true); // This hook can't work anymore // call_hooks('atom_feed', $atom); @@ -217,16 +235,130 @@ function dfrn_feed(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) { } /** - * @brief Adds the header elements for thr DFRN protocol + * @brief Create XML text for DFRN mail * - * We use the XML from OStatus as a base and are adding the DFRN parts to it. + * @param array $item message elements + * @param array $owner Owner record * - * @doc Class XML document - * @owner array Owner record - * - * @return Class XML root object + * @return string DFRN mail */ -function dfrn_add_header($doc, $owner, $authorelement, $alternatelink = "") { +function dfrn_mail($item, $owner) { + $doc = new DOMDocument('1.0', 'utf-8'); + $doc->formatOutput = true; + + $root = dfrn_add_header($doc, $owner, "dfrn:owner", "", false); + + $mail = $doc->createElement("dfrn:mail"); + $sender = $doc->createElement("dfrn:sender"); + + xml_add_element($doc, $sender, "dfrn:name", $owner['name']); + xml_add_element($doc, $sender, "dfrn:uri", $owner['url']); + xml_add_element($doc, $sender, "dfrn:avatar", $owner['thumb']); + + $mail->appendChild($sender); + + xml_add_element($doc, $mail, "dfrn:id", $item['uri']); + xml_add_element($doc, $mail, "dfrn:in-reply-to", $item['parent-uri']); + xml_add_element($doc, $mail, "dfrn:sentdate", datetime_convert('UTC', 'UTC', $item['created'] . '+00:00' , ATOM_TIME)); + xml_add_element($doc, $mail, "dfrn:subject", $item['title']); + xml_add_element($doc, $mail, "dfrn:content", $item['body']); + + $root->appendChild($mail); + + return(trim($doc->saveXML())); +} + +/** + * @brief Create XML text for DFRN suggestions + * + * @param array $item suggestion elements + * @param array $owner Owner record + * + * @return string DFRN suggestions + */ +function dfrn_fsuggest($item, $owner) { + $doc = new DOMDocument('1.0', 'utf-8'); + $doc->formatOutput = true; + + $root = dfrn_add_header($doc, $owner, "dfrn:owner", "", false); + + $suggest = $doc->createElement("dfrn:suggest"); + + xml_add_element($doc, $suggest, "dfrn:url", $item['url']); + xml_add_element($doc, $suggest, "dfrn:name", $item['name']); + xml_add_element($doc, $suggest, "dfrn:photo", $item['photo']); + xml_add_element($doc, $suggest, "dfrn:request", $item['request']); + xml_add_element($doc, $suggest, "dfrn:note", $item['note']); + + $root->appendChild($suggest); + + return(trim($doc->saveXML())); +} + +/** + * @brief Create XML text for DFRN relocations + * + * @param array $owner Owner record + * @param int $uid User ID + * + * @return string DFRN relocations + */ +function dfrn_relocate($owner, $uid) { + + $a = get_app(); + + /* get site pubkey. this could be a new installation with no site keys*/ + $pubkey = get_config('system','site_pubkey'); + if(! $pubkey) { + $res = new_keypair(1024); + set_config('system','site_prvkey', $res['prvkey']); + set_config('system','site_pubkey', $res['pubkey']); + } + + $rp = q("SELECT `resource-id` , `scale`, type FROM `photo` + WHERE `profile` = 1 AND `uid` = %d ORDER BY scale;", $uid); + $photos = array(); + $ext = Photo::supportedTypes(); + foreach($rp as $p){ + $photos[$p['scale']] = $a->get_baseurl().'/photo/'.$p['resource-id'].'-'.$p['scale'].'.'.$ext[$p['type']]; + } + unset($rp, $ext); + + $doc = new DOMDocument('1.0', 'utf-8'); + $doc->formatOutput = true; + + $root = dfrn_add_header($doc, $owner, "dfrn:owner", "", false); + + $relocate = $doc->createElement("dfrn:relocate"); + + xml_add_element($doc, $relocate, "dfrn:url", $owner['url']); + xml_add_element($doc, $relocate, "dfrn:name", $owner['name']); + xml_add_element($doc, $relocate, "dfrn:photo", $photos[4]); + xml_add_element($doc, $relocate, "dfrn:thumb", $photos[5]); + xml_add_element($doc, $relocate, "dfrn:micro", $photos[6]); + xml_add_element($doc, $relocate, "dfrn:request", $owner['request']); + xml_add_element($doc, $relocate, "dfrn:confirm", $owner['confirm']); + xml_add_element($doc, $relocate, "dfrn:notify", $owner['notify']); + xml_add_element($doc, $relocate, "dfrn:poll", $owner['poll']); + xml_add_element($doc, $relocate, "dfrn:sitepubkey", get_config('system','site_pubkey')); + + $root->appendChild($relocate); + + return(trim($doc->saveXML())); +} + +/** + * @brief Adds the header elements for the DFRN protocol + * + * @param object $doc XML document + * @param array $owner Owner record + * @param string $authorelement Element name for the author + * @param string $alternatelink link to profile or category + * @param bool $public Is it a header for public posts? + * + * @return object XML root object + */ +function dfrn_add_header($doc, $owner, $authorelement, $alternatelink = "", $public = false) { $a = get_app(); if ($alternatelink == "") @@ -259,14 +391,16 @@ function dfrn_add_header($doc, $owner, $authorelement, $alternatelink = "") { ostatus_hublinks($doc, $root); - $attributes = array("rel" => "salmon", "href" => $a->get_baseurl()."/salmon/".$owner["nick"]); - xml_add_element($doc, $root, "link", "", $attributes); + if ($public) { + $attributes = array("rel" => "salmon", "href" => $a->get_baseurl()."/salmon/".$owner["nick"]); + xml_add_element($doc, $root, "link", "", $attributes); - $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-replies", "href" => $a->get_baseurl()."/salmon/".$owner["nick"]); - xml_add_element($doc, $root, "link", "", $attributes); + $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-replies", "href" => $a->get_baseurl()."/salmon/".$owner["nick"]); + xml_add_element($doc, $root, "link", "", $attributes); - $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-mention", "href" => $a->get_baseurl()."/salmon/".$owner["nick"]); - xml_add_element($doc, $root, "link", "", $attributes); + $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-mention", "href" => $a->get_baseurl()."/salmon/".$owner["nick"]); + xml_add_element($doc, $root, "link", "", $attributes); + } if ($owner['page-flags'] == PAGE_COMMUNITY) xml_add_element($doc, $root, "dfrn:community", 1); @@ -279,6 +413,15 @@ function dfrn_add_header($doc, $owner, $authorelement, $alternatelink = "") { return $root; } +/** + * @brief Adds the author elements for the DFRN protocol + * + * @param object $doc XML document + * @param array $owner Owner record + * @param string $authorelement Element name for the author + * + * @return object XML author object + */ function dfrn_add_author($doc, $owner, $authorelement) { $a = get_app(); @@ -310,6 +453,16 @@ function dfrn_add_author($doc, $owner, $authorelement) { return $author; } +/** + * @brief Adds the author elements for the item entries of the DFRN protocol + * + * @param object $doc XML document + * @param string $element Element name for the author + * @param string $contact_url Link of the contact + * @param array $items Item elements + * + * @return object XML author object + */ function dfrn_add_entry_author($doc, $element, $contact_url, $item) { $a = get_app(); @@ -370,6 +523,15 @@ function dfrn_add_entry_author($doc, $element, $contact_url, $item) { return $author; } +/** + * @brief Adds the activity elements + * + * @param object $doc XML document + * @param string $element Element name for the activity + * @param string $activity activity value + * + * @return object XML activity object + */ function dfrn_create_activity($doc, $element, $activity) { if($activity) { @@ -408,6 +570,15 @@ function dfrn_create_activity($doc, $element, $activity) { return false; } +/** + * @brief Adds the attachments elements + * + * @param object $doc XML document + * @param object $root XML root + * @param array $item Item element + * + * @return object XML attachment object + */ function dfrn_get_attachment($doc, $root, $item) { $arr = explode('[/attach],',$item['attach']); if(count($arr)) { @@ -431,6 +602,18 @@ function dfrn_get_attachment($doc, $root, $item) { } } +/** + * @brief Adds the header elements for the DFRN protocol + * + * @param object $doc XML document + * @param string $type "text" or "html" + * @param array $item Item element + * @param array $owner Owner record + * @param bool $comment Trigger the sending of the "comment" element + * @param int $cid + * + * @return object XML entry object + */ function dfrn_entry($doc, $type, $item, $owner, $comment = false, $cid = 0) { $a = get_app(); From 444b417de0e6a71ed6057bf9836a2ab21fb0b770 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Sat, 23 Jan 2016 02:44:30 +0100 Subject: [PATCH 05/18] New routines are now enabled --- include/delivery.php | 54 +++++++++++++++++++++++++++++++++++++++++--- include/dfrn.php | 14 ++++++++---- include/ostatus.php | 6 ++++- mod/dfrn_poll.php | 10 ++++---- 4 files changed, 70 insertions(+), 14 deletions(-) diff --git a/include/delivery.php b/include/delivery.php index 0007b96ae..482a75949 100644 --- a/include/delivery.php +++ b/include/delivery.php @@ -5,6 +5,7 @@ require_once('include/html2plain.php'); require_once("include/Scrape.php"); require_once('include/diaspora.php'); require_once("include/ostatus.php"); +require_once("include/dfrn.php"); function delivery_run(&$argv, &$argc){ global $a, $db; @@ -278,6 +279,53 @@ function delivery_run(&$argv, &$argc){ case NETWORK_DFRN: logger('notifier: '.$target_item["guid"].' dfrndelivery: ' . $contact['name']); + if ($mail) { + $item["body"] = $body; + $atom = dfrn_mail($item, $owner); + } elseif ($fsuggest) { + $atom = dfrn_fsuggest($item, $owner); + // q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item['id']) + } elseif ($relocate) + $atom = dfrn_relocate($owner, $uid); + elseif($followup) { + $msgitems = array(); + foreach($items as $item) { // there is only one item + if(!$item['parent']) + continue; + if($item['id'] == $item_id) { + logger('followup: item: ' . print_r($item,true), LOGGER_DATA); + $msgitems[] = $item; + } + } + $atom = dfrn_entries($msgitems,$owner); + } else { + $msgitems = array(); + foreach($items as $item) { + if(!$item['parent']) + continue; + + // private emails may be in included in public conversations. Filter them. + if(($public_message) && $item['private']) + continue; + + $item_contact = get_item_contact($item,$icontacts); + if(!$item_contact) + continue; + + if($normal_mode) { + if($item_id == $item['id'] || $item['id'] == $item['parent']) { + $item["entry:comment-allow"] = true; + $item["entry:cid"] = (($top_level) ? $contact['id'] : 0); + $msgitems[] = $item; + } + } else { + $item["entry:comment-allow"] = true; + $msgitems[] = $item; + } + } + $atom = dfrn_entries($msgitems,$owner); + } +/* $feed_template = get_markup_template('atom_feed.tpl'); $mail_template = get_markup_template('atom_mail.tpl'); @@ -345,7 +393,7 @@ function delivery_run(&$argv, &$argc){ $sugg_template = get_markup_template('atom_relocate.tpl'); - /* get site pubkey. this could be a new installation with no site keys*/ + // get site pubkey. this could be a new installation with no site keys $pubkey = get_config('system','site_pubkey'); if(! $pubkey) { $res = new_keypair(1024); @@ -408,8 +456,8 @@ function delivery_run(&$argv, &$argc){ } $atom .= '' . "\r\n"; - - logger('notifier: '.$contact["url"].' '.$target_item["guid"].' entry: '.$atom, LOGGER_DEBUG); +*/ + logger('notifier entry: '.$contact["url"].' '.$target_item["guid"].' entry: '.$atom, LOGGER_DEBUG); logger('notifier: ' . $atom, LOGGER_DATA); $basepath = implode('/', array_slice(explode('/',$contact['url']),0,3)); diff --git a/include/dfrn.php b/include/dfrn.php index 758e03398..cf1adfa24 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -191,7 +191,12 @@ function dfrn_feed(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) { if(isset($category)) $alternatelink .= "/category/".$category; - $root = dfrn_add_header($doc, $owner, "author", $alternatelink, true); + if ($public_feed) + $author = "dfrn:owner"; + else + $author = "author"; + + $root = dfrn_add_header($doc, $owner, $author, $alternatelink, true); // This hook can't work anymore // call_hooks('atom_feed', $atom); @@ -622,14 +627,13 @@ function dfrn_entry($doc, $type, $item, $owner, $comment = false, $cid = 0) { if(!$item['parent']) return; - $entry = $doc->createElement("entry"); - if($item['deleted']) { $attributes = array("ref" => $item['uri'], "when" => datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)); - xml_add_element($doc, $entry, "at:deleted-entry", "", $attributes); - return $entry; + return xml_create_element($doc, "at:deleted-entry", "", $attributes); } + $entry = $doc->createElement("entry"); + if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid']) $body = fix_private_photos($item['body'],$owner['uid'],$item,$cid); else diff --git a/include/ostatus.php b/include/ostatus.php index b7799fa9d..b127d41e4 100644 --- a/include/ostatus.php +++ b/include/ostatus.php @@ -1121,7 +1121,7 @@ function get_reshared_guid($item) { return $guid; } -function xml_add_element($doc, $parent, $element, $value = "", $attributes = array()) { +function xml_create_element($doc, $element, $value = "", $attributes = array()) { $element = $doc->createElement($element, xmlify($value)); foreach ($attributes AS $key => $value) { @@ -1129,7 +1129,11 @@ function xml_add_element($doc, $parent, $element, $value = "", $attributes = arr $attribute->value = xmlify($value); $element->appendChild($attribute); } + return $element; +} +function xml_add_element($doc, $parent, $element, $value = "", $attributes = array()) { + $element = xml_create_element($doc, $element, $value, $attributes); $parent->appendChild($element); } diff --git a/mod/dfrn_poll.php b/mod/dfrn_poll.php index d6a07186a..e6ebc5d51 100644 --- a/mod/dfrn_poll.php +++ b/mod/dfrn_poll.php @@ -1,9 +1,7 @@ argv[1], $last_update, $direction); + //$o = get_feed_for($a,$dfrn_id, $a->argv[1], $last_update, $direction); + $o = dfrn_feed($a,$dfrn_id, $a->argv[1], $last_update, $direction); echo $o; killme(); From 2bb3c1aec897f5db242918ffb364820198ed217b Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Sat, 23 Jan 2016 13:18:18 +0100 Subject: [PATCH 06/18] DFRN: Mails had an empty body --- include/delivery.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/delivery.php b/include/delivery.php index 482a75949..c78a21340 100644 --- a/include/delivery.php +++ b/include/delivery.php @@ -280,7 +280,7 @@ function delivery_run(&$argv, &$argc){ logger('notifier: '.$target_item["guid"].' dfrndelivery: ' . $contact['name']); if ($mail) { - $item["body"] = $body; + $item['body'] = fix_private_photos($item['body'],$owner['uid'],null,$message[0]['contact-id']); $atom = dfrn_mail($item, $owner); } elseif ($fsuggest) { $atom = dfrn_fsuggest($item, $owner); From 44091aa631d484d2cab3d24220dd98110f1a372f Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Sun, 24 Jan 2016 00:11:16 +0100 Subject: [PATCH 07/18] Removed unused functions --- include/delivery.php | 2 +- include/items.php | 519 ------------------------------------------- include/text.php | 77 ------- 3 files changed, 1 insertion(+), 597 deletions(-) diff --git a/include/delivery.php b/include/delivery.php index c78a21340..957681ead 100644 --- a/include/delivery.php +++ b/include/delivery.php @@ -265,7 +265,7 @@ function delivery_run(&$argv, &$argc){ if(count($r)) $contact = $r[0]; - $hubxml = feed_hublinks(); + //$hubxml = feed_hublinks(); if($contact['self']) continue; diff --git a/include/items.php b/include/items.php index b8fa1dd81..6d3cd2b7c 100644 --- a/include/items.php +++ b/include/items.php @@ -19,300 +19,12 @@ require_once('mod/share.php'); require_once('library/defuse/php-encryption-1.2.1/Crypto.php'); - -function get_feed_for(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) { - - - $sitefeed = ((strlen($owner_nick)) ? false : true); // not yet implemented, need to rewrite huge chunks of following logic - $public_feed = (($dfrn_id) ? false : true); - $starred = false; // not yet implemented, possible security issues - $converse = false; - - if($public_feed && $a->argc > 2) { - for($x = 2; $x < $a->argc; $x++) { - if($a->argv[$x] == 'converse') - $converse = true; - if($a->argv[$x] == 'starred') - $starred = true; - if($a->argv[$x] === 'category' && $a->argc > ($x + 1) && strlen($a->argv[$x+1])) - $category = $a->argv[$x+1]; - } - } - - - - // default permissions - anonymous user - - $sql_extra = " AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = '' "; - - $r = q("SELECT `contact`.*, `user`.`uid` AS `user_uid`, `user`.`nickname`, `user`.`timezone`, `user`.`page-flags` - FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid` - WHERE `contact`.`self` = 1 AND `user`.`nickname` = '%s' LIMIT 1", - dbesc($owner_nick) - ); - - if(! count($r)) - killme(); - - $owner = $r[0]; - $owner_id = $owner['user_uid']; - $owner_nick = $owner['nickname']; - - $birthday = feed_birthday($owner_id,$owner['timezone']); - - $sql_post_table = ""; - $visibility = ""; - - if(! $public_feed) { - - $sql_extra = ''; - switch($direction) { - case (-1): - $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($dfrn_id)); - $my_id = $dfrn_id; - break; - case 0: - $sql_extra = sprintf(" AND `issued-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); - $my_id = '1:' . $dfrn_id; - break; - case 1: - $sql_extra = sprintf(" AND `dfrn-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); - $my_id = '0:' . $dfrn_id; - break; - default: - return false; - break; // NOTREACHED - } - - $r = q("SELECT * FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `contact`.`uid` = %d $sql_extra LIMIT 1", - intval($owner_id) - ); - - if(! count($r)) - killme(); - - $contact = $r[0]; - require_once('include/security.php'); - $groups = init_groups_visitor($contact['id']); - - if(count($groups)) { - for($x = 0; $x < count($groups); $x ++) - $groups[$x] = '<' . intval($groups[$x]) . '>' ; - $gs = implode('|', $groups); - } - else - $gs = '<<>>' ; // Impossible to match - - $sql_extra = sprintf(" - AND ( `allow_cid` = '' OR `allow_cid` REGEXP '<%d>' ) - AND ( `deny_cid` = '' OR NOT `deny_cid` REGEXP '<%d>' ) - AND ( `allow_gid` = '' OR `allow_gid` REGEXP '%s' ) - AND ( `deny_gid` = '' OR NOT `deny_gid` REGEXP '%s') - ", - intval($contact['id']), - intval($contact['id']), - dbesc($gs), - dbesc($gs) - ); - } - - if($public_feed) - $sort = 'DESC'; - else - $sort = 'ASC'; - - $date_field = "`changed`"; - $sql_order = "`item`.`parent` ".$sort.", `item`.`created` ASC"; - - if(! strlen($last_update)) - $last_update = 'now -30 days'; - - if(isset($category)) { - $sql_post_table = sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ", - dbesc(protect_sprintf($category)), intval(TERM_OBJ_POST), intval(TERM_CATEGORY), intval($owner_id)); - //$sql_extra .= file_tag_file_query('item',$category,'category'); - } - - if($public_feed) { - if(! $converse) - $sql_extra .= " AND `contact`.`self` = 1 "; - } - - $check_date = datetime_convert('UTC','UTC',$last_update,'Y-m-d H:i:s'); - - // AND ( `item`.`edited` > '%s' OR `item`.`changed` > '%s' ) - // dbesc($check_date), - - $r = q("SELECT STRAIGHT_JOIN `item`.*, `item`.`id` AS `item_id`, - `contact`.`name`, `contact`.`network`, `contact`.`photo`, `contact`.`url`, - `contact`.`name-date`, `contact`.`uri-date`, `contact`.`avatar-date`, - `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `contact-id`, `contact`.`uid` AS `contact-uid`, - `sign`.`signed_text`, `sign`.`signature`, `sign`.`signer` - FROM `item` $sql_post_table - INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0 - LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` - WHERE `item`.`uid` = %d AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`parent` != 0 - AND ((`item`.`wall` = 1) $visibility) AND `item`.$date_field > '%s' - $sql_extra - ORDER BY $sql_order LIMIT 0, 300", - intval($owner_id), - dbesc($check_date), - dbesc($sort) - ); - - // Will check further below if this actually returned results. - // We will provide an empty feed if that is the case. - - $items = $r; - - $feed_template = get_markup_template(($dfrn_id) ? 'atom_feed_dfrn.tpl' : 'atom_feed.tpl'); - - $atom = ''; - - $hubxml = feed_hublinks(); - - $salmon = feed_salmonlinks($owner_nick); - - $alternatelink = $owner['url']; - - if(isset($category)) - $alternatelink .= "/category/".$category; - - $atom .= replace_macros($feed_template, array( - '$version' => xmlify(FRIENDICA_VERSION), - '$feed_id' => xmlify($a->get_baseurl() . '/profile/' . $owner_nick), - '$feed_title' => xmlify($owner['name']), - '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', 'now' , ATOM_TIME)) , - '$hub' => $hubxml, - '$salmon' => $salmon, - '$alternatelink' => xmlify($alternatelink), - '$name' => xmlify($owner['name']), - '$profile_page' => xmlify($owner['url']), - '$photo' => xmlify($owner['photo']), - '$thumb' => xmlify($owner['thumb']), - '$picdate' => xmlify(datetime_convert('UTC','UTC',$owner['avatar-date'] . '+00:00' , ATOM_TIME)) , - '$uridate' => xmlify(datetime_convert('UTC','UTC',$owner['uri-date'] . '+00:00' , ATOM_TIME)) , - '$namdate' => xmlify(datetime_convert('UTC','UTC',$owner['name-date'] . '+00:00' , ATOM_TIME)) , - '$birthday' => ((strlen($birthday)) ? '' . xmlify($birthday) . '' : ''), - '$community' => (($owner['page-flags'] == PAGE_COMMUNITY) ? '1' : '') - )); - - call_hooks('atom_feed', $atom); - - if(! count($items)) { - - call_hooks('atom_feed_end', $atom); - - $atom .= '' . "\r\n"; - return $atom; - } - - foreach($items as $item) { - - // prevent private email from leaking. - if($item['network'] === NETWORK_MAIL) - continue; - - // public feeds get html, our own nodes use bbcode - - if($public_feed) { - $type = 'html'; - // catch any email that's in a public conversation and make sure it doesn't leak - if($item['private']) - continue; - } - else { - $type = 'text'; - } - - $atom .= atom_entry($item,$type,null,$owner,true); - } - - call_hooks('atom_feed_end', $atom); - - $atom .= '' . "\r\n"; - - return $atom; -} - - function construct_verb($item) { if($item['verb']) return $item['verb']; return ACTIVITY_POST; } -function construct_activity_object($item) { - - if($item['object']) { - $o = '' . "\r\n"; - $r = parse_xml_string($item['object'],false); - - - if(! $r) - return ''; - if($r->type) - $o .= '' . xmlify($r->type) . '' . "\r\n"; - if($r->id) - $o .= '' . xmlify($r->id) . '' . "\r\n"; - if($r->title) - $o .= '' . xmlify($r->title) . '' . "\r\n"; - if($r->link) { - if(substr($r->link,0,1) === '<') { - // patch up some facebook "like" activity objects that got stored incorrectly - // for a couple of months prior to 9-Jun-2011 and generated bad XML. - // we can probably remove this hack here and in the following function in a few months time. - if(strstr($r->link,'&') && (! strstr($r->link,'&'))) - $r->link = str_replace('&','&', $r->link); - $r->link = preg_replace('/\/','',$r->link); - $o .= $r->link; - } - else - $o .= '' . "\r\n"; - } - if($r->content) - $o .= '' . xmlify(bbcode($r->content)) . '' . "\r\n"; - $o .= '' . "\r\n"; - return $o; - } - - return ''; -} - -function construct_activity_target($item) { - - if($item['target']) { - $o = '' . "\r\n"; - $r = parse_xml_string($item['target'],false); - if(! $r) - return ''; - if($r->type) - $o .= '' . xmlify($r->type) . '' . "\r\n"; - if($r->id) - $o .= '' . xmlify($r->id) . '' . "\r\n"; - if($r->title) - $o .= '' . xmlify($r->title) . '' . "\r\n"; - if($r->link) { - if(substr($r->link,0,1) === '<') { - if(strstr($r->link,'&') && (! strstr($r->link,'&'))) - $r->link = str_replace('&','&', $r->link); - $r->link = preg_replace('/\/','',$r->link); - $o .= $r->link; - } - else - $o .= '' . "\r\n"; - } - if($r->content) - $o .= '' . xmlify(bbcode($r->content)) . '' . "\r\n"; - $o .= '' . "\r\n"; - return $o; - } - - return ''; -} - /* limit_body_size() * * The purpose of this function is to apply system message length limits to @@ -431,8 +143,6 @@ function title_is_body($title, $body) { return($title == $body); } - - function get_atom_elements($feed, $item, $contact = array()) { require_once('library/HTMLPurifier.auto.php'); @@ -4266,7 +3976,6 @@ function lose_sharer($importer,$contact,$datarray,$item) { } } - function subscribe_to_hub($url,$importer,$contact,$hubmode = 'subscribe') { $a = get_app(); @@ -4309,189 +4018,6 @@ function subscribe_to_hub($url,$importer,$contact,$hubmode = 'subscribe') { } - -function atom_author($tag,$name,$uri,$h,$w,$photo,$geo) { - $o = ''; - if(! $tag) - return $o; - $name = xmlify($name); - $uri = xmlify($uri); - $h = intval($h); - $w = intval($w); - $photo = xmlify($photo); - - - $o .= "<$tag>\r\n"; - $o .= "\t$name\r\n"; - $o .= "\t$uri\r\n"; - $o .= "\t".'' . "\r\n"; - $o .= "\t".'' . "\r\n"; - - if ($tag == "author") { - - if($geo) - $o .= ''.xmlify($geo).''."\r\n"; - - $r = q("SELECT `profile`.`locality`, `profile`.`region`, `profile`.`country-name`, - `profile`.`name`, `profile`.`pub_keywords`, `profile`.`about`, - `profile`.`homepage`,`contact`.`nick` FROM `profile` - INNER JOIN `contact` ON `contact`.`uid` = `profile`.`uid` - INNER JOIN `user` ON `user`.`uid` = `profile`.`uid` - WHERE `profile`.`is-default` AND `contact`.`self` AND - NOT `user`.`hidewall` AND `contact`.`nurl`='%s'", - dbesc(normalise_link($uri))); - if ($r) { - $location = ''; - if($r[0]['locality']) - $location .= $r[0]['locality']; - if($r[0]['region']) { - if($location) - $location .= ', '; - $location .= $r[0]['region']; - } - if($r[0]['country-name']) { - if($location) - $location .= ', '; - $location .= $r[0]['country-name']; - } - - $o .= "\t".xmlify($r[0]["nick"])."\r\n"; - $o .= "\t".xmlify($r[0]["name"])."\r\n"; - $o .= "\t".xmlify(bbcode($r[0]["about"]))."\r\n"; - $o .= "\t\r\n"; - $o .= "\t\t".xmlify($location)."\r\n"; - $o .= "\t\r\n"; - $o .= "\t\r\n"; - $o .= "\thomepage\r\n"; - $o .= "\t\t".xmlify($r[0]["homepage"])."\r\n"; - $o .= "\t\ttrue\r\n"; - $o .= "\t\r\n"; - } - } - - call_hooks('atom_author', $o); - - $o .= "\r\n"; - return $o; -} - -function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) { - - $a = get_app(); - - if(! $item['parent']) - return; - - if($item['deleted']) - return '' . "\r\n"; - - - if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid']) - $body = fix_private_photos($item['body'],$owner['uid'],$item,$cid); - else - $body = $item['body']; - - - $o = "\r\n\r\n\r\n"; - - if(is_array($author)) - $o .= atom_author('author',$author['name'],$author['url'],80,80,$author['thumb'], $item['coord']); - else - $o .= atom_author('author',(($item['author-name']) ? $item['author-name'] : $item['name']),(($item['author-link']) ? $item['author-link'] : $item['url']),80,80,(($item['author-avatar']) ? $item['author-avatar'] : $item['thumb']), $item['coord']); - if(strlen($item['owner-name'])) - $o .= atom_author('dfrn:owner',$item['owner-name'],$item['owner-link'],80,80,$item['owner-avatar'], $item['coord']); - - if(($item['parent'] != $item['id']) || ($item['parent-uri'] !== $item['uri']) || (($item['thr-parent'] !== '') && ($item['thr-parent'] !== $item['uri']))) { - $parent = q("SELECT `guid` FROM `item` WHERE `id` = %d", intval($item["parent"])); - $parent_item = (($item['thr-parent']) ? $item['thr-parent'] : $item['parent-uri']); - $o .= ''."\r\n"; - } - - $htmlbody = $body; - - if ($item['title'] != "") - $htmlbody = "[b]".$item['title']."[/b]\n\n".$htmlbody; - - $htmlbody = bbcode($htmlbody, false, false, 7); - - $o .= '' . xmlify($item['uri']) . '' . "\r\n"; - $o .= '' . xmlify($item['title']) . '' . "\r\n"; - $o .= '' . xmlify(datetime_convert('UTC','UTC',$item['created'] . '+00:00',ATOM_TIME)) . '' . "\r\n"; - $o .= '' . xmlify(datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)) . '' . "\r\n"; - $o .= '' . base64url_encode($body, true) . '' . "\r\n"; - $o .= '' . xmlify((($type === 'html') ? $htmlbody : $body)) . '' . "\r\n"; - $o .= ''."\r\n"; - - $o .= ''."\r\n"; - - if($comment) - $o .= '' . intval($item['last-child']) . '' . "\r\n"; - - if($item['location']) { - $o .= '' . xmlify($item['location']) . '' . "\r\n"; - $o .= '' . xmlify($item['location']) . '' . "\r\n"; - } - - if($item['coord']) - $o .= '' . xmlify($item['coord']) . '' . "\r\n"; - - if(($item['private']) || strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])) - $o .= '' . (($item['private']) ? $item['private'] : 1) . '' . "\r\n"; - - if($item['extid']) - $o .= '' . xmlify($item['extid']) . '' . "\r\n"; - if($item['bookmark']) - $o .= 'true' . "\r\n"; - - if($item['app']) - $o .= '' . "\r\n"; - - if($item['guid']) - $o .= '' . $item['guid'] . '' . "\r\n"; - - if($item['signed_text']) { - $sign = base64_encode(json_encode(array('signed_text' => $item['signed_text'],'signature' => $item['signature'],'signer' => $item['signer']))); - $o .= '' . xmlify($sign) . '' . "\r\n"; - } - - $verb = construct_verb($item); - $o .= '' . xmlify($verb) . '' . "\r\n"; - $actobj = construct_activity_object($item); - if(strlen($actobj)) - $o .= $actobj; - $actarg = construct_activity_target($item); - if(strlen($actarg)) - $o .= $actarg; - - $tags = item_getfeedtags($item); - if(count($tags)) { - foreach($tags as $t) - if (($type != 'html') OR ($t[0] != "@")) - $o .= '' . "\r\n"; - } - - /// @TODO - /// To support these elements, the API needs to be enhanced - /// $o .= ''."\r\n"; - /// $o .= "\t".''."\r\n"; - /// $o .= "\t".''."\r\n"; - - // Deactivated since it was meant only for OStatus - //$o .= item_get_attachment($item); - - $o .= item_getfeedattach($item); - - $mentioned = get_mentions($item); - if($mentioned) - $o .= $mentioned; - - call_hooks('atom_entry', $o); - - $o .= '' . "\r\n"; - - return $o; -} - function fix_private_photos($s, $uid, $item = null, $cid = 0) { if(get_config('system','disable_embedded')) @@ -4595,7 +4121,6 @@ function fix_private_photos($s, $uid, $item = null, $cid = 0) { return($new_body); } - function has_permissions($obj) { if(($obj['allow_cid'] != '') || ($obj['allow_gid'] != '') || ($obj['deny_cid'] != '') || ($obj['deny_gid'] != '')) return true; @@ -4656,50 +4181,6 @@ function item_getfeedtags($item) { return $ret; } -function item_get_attachment($item) { - $o = ""; - $siteinfo = get_attached_data($item["body"]); - - switch($siteinfo["type"]) { - case 'link': - $o = ''."\r\n"; - break; - case 'photo': - $imgdata = get_photo_info($siteinfo["image"]); - $o = ''."\r\n"; - break; - case 'video': - $o = ''."\r\n"; - break; - default: - break; - } - - return $o; -} - -function item_getfeedattach($item) { - $ret = ''; - $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) { - $ret .= '' . "\r\n"; - $o .= "\t\t" . '' . "\r\n"; - } - } - - if (!$item['private']) { - $o .= "\t\t".''."\r\n"; - $o .= "\t\t".''."\r\n"; - } - - return $o; -}} - if(! function_exists('contact_block')) { /** * Get html for contact block. @@ -1657,54 +1628,6 @@ function get_cats_and_terms($item) { return array($categories, $folders); } - - -if(! function_exists('feed_hublinks')) { -/** - * return atom link elements for all of our hubs - * @return string hub link xml elements - */ -function feed_hublinks() { - $a = get_app(); - $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 = z_root() . '/pubsubhubbub'; - $hubxml .= '' . "\n" ; - } - } - } - return $hubxml; -}} - - -if(! function_exists('feed_salmonlinks')) { -/** - * return atom link elements for salmon endpoints - * @param string $nick user nickname - * @return string salmon link xml elements - */ -function feed_salmonlinks($nick) { - - $a = get_app(); - - $salmon = '' . "\n" ; - - // old style links that status.net still needed as of 12/2010 - - $salmon .= ' ' . "\n" ; - $salmon .= ' ' . "\n" ; - return $salmon; -}} - if(! function_exists('get_plink')) { /** * get private link for item From 74ed37aa87417c6fa1bd0e04ab9981dc802916f7 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Sun, 24 Jan 2016 00:21:58 +0100 Subject: [PATCH 08/18] Some more removed code --- include/delivery.php | 135 +------------------------------------------ mod/dfrn_poll.php | 2 - 2 files changed, 1 insertion(+), 136 deletions(-) diff --git a/include/delivery.php b/include/delivery.php index 957681ead..d04600599 100644 --- a/include/delivery.php +++ b/include/delivery.php @@ -265,8 +265,6 @@ function delivery_run(&$argv, &$argc){ if(count($r)) $contact = $r[0]; - //$hubxml = feed_hublinks(); - if($contact['self']) continue; @@ -284,7 +282,7 @@ function delivery_run(&$argv, &$argc){ $atom = dfrn_mail($item, $owner); } elseif ($fsuggest) { $atom = dfrn_fsuggest($item, $owner); - // q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item['id']) + q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item['id'])); } elseif ($relocate) $atom = dfrn_relocate($owner, $uid); elseif($followup) { @@ -325,138 +323,7 @@ function delivery_run(&$argv, &$argc){ } $atom = dfrn_entries($msgitems,$owner); } -/* - $feed_template = get_markup_template('atom_feed.tpl'); - $mail_template = get_markup_template('atom_mail.tpl'); - $atom = ''; - - - $birthday = feed_birthday($owner['uid'],$owner['timezone']); - - if(strlen($birthday)) - $birthday = '' . xmlify($birthday) . ''; - - $atom .= replace_macros($feed_template, array( - '$version' => xmlify(FRIENDICA_VERSION), - '$feed_id' => xmlify($a->get_baseurl() . '/profile/' . $owner['nickname'] ), - '$feed_title' => xmlify($owner['name']), - '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', $updated . '+00:00' , ATOM_TIME)) , - '$hub' => $hubxml, - '$salmon' => '', // private feed, we don't use salmon here - '$name' => xmlify($owner['name']), - '$profile_page' => xmlify($owner['url']), - '$photo' => xmlify($owner['photo']), - '$thumb' => xmlify($owner['thumb']), - '$picdate' => xmlify(datetime_convert('UTC','UTC',$owner['avatar-date'] . '+00:00' , ATOM_TIME)) , - '$uridate' => xmlify(datetime_convert('UTC','UTC',$owner['uri-date'] . '+00:00' , ATOM_TIME)) , - '$namdate' => xmlify(datetime_convert('UTC','UTC',$owner['name-date'] . '+00:00' , ATOM_TIME)) , - '$birthday' => $birthday, - '$community' => (($owner['page-flags'] == PAGE_COMMUNITY) ? '1' : '') - )); - - if($mail) { - $public_message = false; // mail is not public - - $body = fix_private_photos($item['body'],$owner['uid'],null,$message[0]['contact-id']); - - $atom .= replace_macros($mail_template, array( - '$name' => xmlify($owner['name']), - '$profile_page' => xmlify($owner['url']), - '$thumb' => xmlify($owner['thumb']), - '$item_id' => xmlify($item['uri']), - '$subject' => xmlify($item['title']), - '$created' => xmlify(datetime_convert('UTC', 'UTC', $item['created'] . '+00:00' , ATOM_TIME)), - '$content' => xmlify($body), - '$parent_id' => xmlify($item['parent-uri']) - )); - } elseif($fsuggest) { - $public_message = false; // suggestions are not public - - $sugg_template = get_markup_template('atom_suggest.tpl'); - - $atom .= replace_macros($sugg_template, array( - '$name' => xmlify($item['name']), - '$url' => xmlify($item['url']), - '$photo' => xmlify($item['photo']), - '$request' => xmlify($item['request']), - '$note' => xmlify($item['note']) - )); - - // We don't need this any more - - q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1", - intval($item['id']) - ); - } elseif($relocate) { - $public_message = false; // suggestions are not public - - $sugg_template = get_markup_template('atom_relocate.tpl'); - - // get site pubkey. this could be a new installation with no site keys - $pubkey = get_config('system','site_pubkey'); - if(! $pubkey) { - $res = new_keypair(1024); - set_config('system','site_prvkey', $res['prvkey']); - set_config('system','site_pubkey', $res['pubkey']); - } - - $rp = q("SELECT `resource-id` , `scale`, type FROM `photo` - WHERE `profile` = 1 AND `uid` = %d ORDER BY scale;", $uid); - $photos = array(); - $ext = Photo::supportedTypes(); - foreach($rp as $p){ - $photos[$p['scale']] = $a->get_baseurl().'/photo/'.$p['resource-id'].'-'.$p['scale'].'.'.$ext[$p['type']]; - } - unset($rp, $ext); - - $atom .= replace_macros($sugg_template, array( - '$name' => xmlify($owner['name']), - '$photo' => xmlify($photos[4]), - '$thumb' => xmlify($photos[5]), - '$micro' => xmlify($photos[6]), - '$url' => xmlify($owner['url']), - '$request' => xmlify($owner['request']), - '$confirm' => xmlify($owner['confirm']), - '$notify' => xmlify($owner['notify']), - '$poll' => xmlify($owner['poll']), - '$sitepubkey' => xmlify(get_config('system','site_pubkey')), - //'$pubkey' => xmlify($owner['pubkey']), - //'$prvkey' => xmlify($owner['prvkey']), - )); - unset($photos); - } elseif($followup) { - foreach($items as $item) { // there is only one item - if(! $item['parent']) - continue; - if($item['id'] == $item_id) { - logger('followup: item: ' . print_r($item,true), LOGGER_DATA); - $atom .= atom_entry($item,'text',null,$owner,false); - } - } - } else { - foreach($items as $item) { - if(! $item['parent']) - continue; - - // private emails may be in included in public conversations. Filter them. - if(($public_message) && $item['private'] == 1) - continue; - - $item_contact = get_item_contact($item,$icontacts); - if(! $item_contact) - continue; - - if($normal_mode) { - if($item_id == $item['id'] || $item['id'] == $item['parent']) - $atom .= atom_entry($item,'text',null,$owner,true,(($top_level) ? $contact['id'] : 0)); - } else - $atom .= atom_entry($item,'text',null,$owner,true); - } - } - - $atom .= '' . "\r\n"; -*/ logger('notifier entry: '.$contact["url"].' '.$target_item["guid"].' entry: '.$atom, LOGGER_DEBUG); logger('notifier: ' . $atom, LOGGER_DATA); diff --git a/mod/dfrn_poll.php b/mod/dfrn_poll.php index e6ebc5d51..658a248c6 100644 --- a/mod/dfrn_poll.php +++ b/mod/dfrn_poll.php @@ -44,7 +44,6 @@ function dfrn_poll_init(&$a) { logger('dfrn_poll: public feed request from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . $user); header("Content-type: application/atom+xml"); - //echo get_feed_for($a, '', $user,$last_update); echo dfrn_feed($a, '', $user,$last_update); killme(); } @@ -372,7 +371,6 @@ function dfrn_poll_post(&$a) { } header("Content-type: application/atom+xml"); - //$o = get_feed_for($a,$dfrn_id, $a->argv[1], $last_update, $direction); $o = dfrn_feed($a,$dfrn_id, $a->argv[1], $last_update, $direction); echo $o; killme(); From f38f1806c1cfb2b0f3c6219c65711c3e2f6caa22 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Sun, 24 Jan 2016 08:22:09 +0100 Subject: [PATCH 09/18] We don't need these templates anymore --- view/templates/atom_feed.tpl | 31 ------------------------------- view/templates/atom_feed_dfrn.tpl | 31 ------------------------------- view/templates/atom_mail.tpl | 18 ------------------ view/templates/atom_relocate.tpl | 18 ------------------ view/templates/atom_suggest.tpl | 12 ------------ 5 files changed, 110 deletions(-) delete mode 100644 view/templates/atom_feed.tpl delete mode 100644 view/templates/atom_feed_dfrn.tpl delete mode 100644 view/templates/atom_mail.tpl delete mode 100644 view/templates/atom_relocate.tpl delete mode 100644 view/templates/atom_suggest.tpl diff --git a/view/templates/atom_feed.tpl b/view/templates/atom_feed.tpl deleted file mode 100644 index 7070f4c5e..000000000 --- a/view/templates/atom_feed.tpl +++ /dev/null @@ -1,31 +0,0 @@ - - - - - {{$feed_id}} - {{$feed_title}} - Friendica - - - {{$hub}} - {{$salmon}} - {{$community}} - - {{$feed_updated}} - - - {{$name}} - {{$profile_page}} - - - {{$birthday}} - diff --git a/view/templates/atom_feed_dfrn.tpl b/view/templates/atom_feed_dfrn.tpl deleted file mode 100644 index 2b1c16fb3..000000000 --- a/view/templates/atom_feed_dfrn.tpl +++ /dev/null @@ -1,31 +0,0 @@ - - - - - {{$feed_id}} - {{$feed_title}} - Friendica - - - {{$hub}} - {{$salmon}} - {{$community}} - - {{$feed_updated}} - - - {{$name}} - {{$profile_page}} - - - {{$birthday}} - diff --git a/view/templates/atom_mail.tpl b/view/templates/atom_mail.tpl deleted file mode 100644 index e18e47655..000000000 --- a/view/templates/atom_mail.tpl +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - {{$name}} - {{$profile_page}} - {{$thumb}} - - - {{$item_id}} - {{$parent_id}} - {{$created}} - {{$subject}} - {{$content}} - - - diff --git a/view/templates/atom_relocate.tpl b/view/templates/atom_relocate.tpl deleted file mode 100644 index e6418fcb2..000000000 --- a/view/templates/atom_relocate.tpl +++ /dev/null @@ -1,18 +0,0 @@ - - - - - {{$url}} - {{$name}} - {{$photo}} - {{$thumb}} - {{$micro}} - {{$request}} - {{$confirm}} - {{$notify}} - {{$poll}} - {{$sitepubkey}} - - - - diff --git a/view/templates/atom_suggest.tpl b/view/templates/atom_suggest.tpl deleted file mode 100644 index afc1d6629..000000000 --- a/view/templates/atom_suggest.tpl +++ /dev/null @@ -1,12 +0,0 @@ - - - - - {{$url}} - {{$name}} - {{$photo}} - {{$request}} - {{$note}} - - - From c1f2b3a55ec90d2cbaaa61ccd7dcf386ca52c6a5 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Sun, 24 Jan 2016 10:34:39 +0100 Subject: [PATCH 10/18] Improved documentation --- include/dfrn.php | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/include/dfrn.php b/include/dfrn.php index cf1adfa24..c7e338712 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -3,7 +3,9 @@ require_once('include/items.php'); require_once('include/ostatus.php'); /** - * @brief Adds the header elements for the DFRN protocol + * @brief Generates the atom entries for delivery.php + * + * This function is used whenever content is transmitted via DFRN. * * @param array $items Item elements * @param array $owner Owner record @@ -29,7 +31,9 @@ function dfrn_entries($items,$owner) { } /** - * @brief Adds the header elements for the DFRN protocol + * @brief Generate an atom feed for the given user + * + * This function is called when another server is pulling data from the user feed. * * @param App $a * @param string $dfrn_id @@ -240,7 +244,7 @@ function dfrn_feed(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) { } /** - * @brief Create XML text for DFRN mail + * @brief Create XML text for DFRN mails * * @param array $item message elements * @param array $owner Owner record @@ -274,7 +278,7 @@ function dfrn_mail($item, $owner) { } /** - * @brief Create XML text for DFRN suggestions + * @brief Create XML text for DFRN friend suggestions * * @param array $item suggestion elements * @param array $owner Owner record @@ -419,7 +423,7 @@ function dfrn_add_header($doc, $owner, $authorelement, $alternatelink = "", $pub } /** - * @brief Adds the author elements for the DFRN protocol + * @brief Adds the author element in the header for the DFRN protocol * * @param object $doc XML document * @param array $owner Owner record @@ -459,7 +463,7 @@ function dfrn_add_author($doc, $owner, $authorelement) { } /** - * @brief Adds the author elements for the item entries of the DFRN protocol + * @brief Adds the author elements in the "entry" elements of the DFRN protocol * * @param object $doc XML document * @param string $element Element name for the author @@ -576,7 +580,7 @@ function dfrn_create_activity($doc, $element, $activity) { } /** - * @brief Adds the attachments elements + * @brief Adds the elements for attachments * * @param object $doc XML document * @param object $root XML root @@ -608,7 +612,7 @@ function dfrn_get_attachment($doc, $root, $item) { } /** - * @brief Adds the header elements for the DFRN protocol + * @brief Adds the "entry" elements for the DFRN protocol * * @param object $doc XML document * @param string $type "text" or "html" From 937196d6ee3235fbfba6ff199fe9c8699d816b24 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Sun, 24 Jan 2016 14:30:57 +0100 Subject: [PATCH 11/18] Poco fields now moved to the header, function to create formatted location string --- include/Contact.php | 30 +++++++++++ include/dfrn.php | 107 ++++++++++++++++++++++++++----------- include/profile_update.php | 15 +----- mod/profiles.php | 18 +------ 4 files changed, 109 insertions(+), 61 deletions(-) diff --git a/include/Contact.php b/include/Contact.php index f80cb80e2..831a99c95 100644 --- a/include/Contact.php +++ b/include/Contact.php @@ -664,4 +664,34 @@ function posts_from_contact($a, $contact_id) { return $o; } + +/** + * @brief Returns a formatted location string from the given profile array + * + * @param array $profile Profile array (Generated from the "profile" table) + * + * @return string Location string + */ +function formatted_location($profile) { + $location = ''; + + if($profile['locality']) + $location .= $profile['locality']; + + if($profile['region'] AND ($profile['locality'] != $profile['region'])) { + if($location) + $location .= ', '; + + $location .= $profile['region']; + } + + if($profile['country-name']) { + if($location) + $location .= ', '; + + $location .= $profile['country-name']; + } + + return $location; +} ?> diff --git a/include/dfrn.php b/include/dfrn.php index c7e338712..feb535417 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -1,5 +1,6 @@ appendChild($author); return $root; @@ -431,7 +432,7 @@ function dfrn_add_header($doc, $owner, $authorelement, $alternatelink = "", $pub * * @return object XML author object */ -function dfrn_add_author($doc, $owner, $authorelement) { +function dfrn_add_author($doc, $owner, $authorelement, $public) { $a = get_app(); $author = $doc->createElement($authorelement); @@ -459,6 +460,77 @@ function dfrn_add_author($doc, $owner, $authorelement) { if ($birthday) xml_add_element($doc, $author, "dfrn:birthday", $birthday); + // The following fields will only be generated if this isn't for a public feed + if ($public) + return $author; + + // Only show contact details when we are allowed to + $r = q("SELECT `profile`.`about`, `profile`.`name`, `profile`.`homepage`, `user`.`nickname`, `user`.`timezone`, + `profile`.`locality`, `profile`.`region`, `profile`.`country-name`, `profile`.`pub_keywords`, `profile`.`dob` + FROM `profile` + INNER JOIN `user` ON `user`.`uid` = `profile`.`uid` + WHERE `profile`.`is-default` AND NOT `user`.`hidewall` AND `user`.`uid` = %d", + intval($owner['user_uid'])); + if ($r) { + $profile = $r[0]; + xml_add_element($doc, $author, "poco:displayName", $profile["name"]); + xml_add_element($doc, $author, "poco:updated", $namdate); + + if (trim($profile["dob"]) != "0000-00-00") + xml_add_element($doc, $author, "poco:birthday", "0000-".date("m-d", strtotime($profile["dob"]))); + + xml_add_element($doc, $author, "poco:note", $profile["about"]); + xml_add_element($doc, $author, "poco:preferredUsername", $profile["nickname"]); + + $savetz = date_default_timezone_get(); + date_default_timezone_set($profile["timezone"]); + xml_add_element($doc, $author, "poco:utcOffset", date("P")); + date_default_timezone_set($savetz); + + 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 (trim($profile["pub_keywords"]) != "") { + $keywords = explode(",", $profile["pub_keywords"]); + + foreach ($keywords AS $keyword) + xml_add_element($doc, $author, "poco:tags", trim($keyword)); + + } + + /// @todo When we are having the XMPP address in the profile we should propagate it here + $xmpp = ""; + if (trim($xmpp) != "") { + $ims = $doc->createElement("poco:ims"); + xml_add_element($doc, $ims, "poco:type", "xmpp"); + xml_add_element($doc, $ims, "poco:value", $xmpp); + xml_add_element($doc, $ims, "poco:primary", "true"); + $author->appendChild($ims); + } + + if (trim($profile["locality"].$profile["region"].$profile["country-name"]) != "") { + $element = $doc->createElement("poco:address"); + + xml_add_element($doc, $element, "poco:formatted", formatted_location($profile)); + + if (trim($profile["locality"]) != "") + xml_add_element($doc, $element, "poco:locality", $profile["locality"]); + + if (trim($profile["region"]) != "") + xml_add_element($doc, $element, "poco:region", $profile["region"]); + + if (trim($profile["country-name"]) != "") + xml_add_element($doc, $element, "poco:country", $profile["country-name"]); + + $author->appendChild($element); + } + } + return $author; } @@ -477,21 +549,13 @@ function dfrn_add_entry_author($doc, $element, $contact_url, $item) { $contact = get_contact_details_by_url($contact_url, $item["uid"]); - $r = q("SELECT `profile`.`about`, `profile`.`name`, `profile`.`homepage`, `contact`.`nick`, `contact`.`location` FROM `profile` - INNER JOIN `contact` ON `contact`.`uid` = `profile`.`uid` - INNER JOIN `user` ON `user`.`uid` = `profile`.`uid` - WHERE `contact`.`self` AND `profile`.`is-default` AND NOT `user`.`hidewall` AND `contact`.`nurl`='%s'", - dbesc(normalise_link($contact_url))); - if ($r) - $profile = $r[0]; - $author = $doc->createElement($element); xml_add_element($doc, $author, "name", $contact["name"]); xml_add_element($doc, $author, "uri", $contact["url"]); /// @Todo /// - Check real image type and image size - /// - Check which of these boths elements we really use + /// - Check which of these boths elements we should use $attributes = array( "rel" => "photo", "type" => "image/jpeg", @@ -508,27 +572,6 @@ function dfrn_add_entry_author($doc, $element, $contact_url, $item) { "href" => $contact["photo"]); xml_add_element($doc, $author, "link", "", $attributes); - // Only show contact details when it is a user from our system and we are allowed to - if ($profile) { - xml_add_element($doc, $author, "poco:preferredUsername", $profile["nick"]); - xml_add_element($doc, $author, "poco:displayName", $profile["name"]); - xml_add_element($doc, $author, "poco:note", $profile["about"]); - - if (trim($contact["location"]) != "") { - $element = $doc->createElement("poco:address"); - xml_add_element($doc, $element, "poco:formatted", $profile["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); - } - } - return $author; } diff --git a/include/profile_update.php b/include/profile_update.php index 0fcf3617f..7cc72cc86 100644 --- a/include/profile_update.php +++ b/include/profile_update.php @@ -3,6 +3,7 @@ require_once('include/datetime.php'); require_once('include/diaspora.php'); require_once('include/queue_fn.php'); +require_once('include/Contact.php'); function profile_change() { @@ -53,19 +54,7 @@ function profile_change() { $about = xmlify($profile['about']); require_once('include/bbcode.php'); $about = xmlify(strip_tags(bbcode($about))); - $location = ''; - if($profile['locality']) - $location .= $profile['locality']; - if($profile['region']) { - if($location) - $location .= ', '; - $location .= $profile['region']; - } - if($profile['country-name']) { - if($location) - $location .= ', '; - $location .= $profile['country-name']; - } + $location = formatted_location($profile); $location = xmlify($location); $tags = ''; if($profile['pub_keywords']) { diff --git a/mod/profiles.php b/mod/profiles.php index 3ba57c883..5c372de8e 100644 --- a/mod/profiles.php +++ b/mod/profiles.php @@ -1,5 +1,5 @@ $locality, "region" => $region, "country-name" => $country_name)); $r = q("UPDATE `contact` SET `about` = '%s', `location` = '%s', `keywords` = '%s', `gender` = '%s' WHERE `self` = 1 AND `uid` = %d", dbesc($about), From acd7e816ebb5ee0f721290f644a6c2718368c00a Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Mon, 25 Jan 2016 01:06:46 +0100 Subject: [PATCH 12/18] Added documentation --- include/dfrn.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/dfrn.php b/include/dfrn.php index feb535417..c6b7f5937 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -37,10 +37,10 @@ function dfrn_entries($items,$owner) { * This function is called when another server is pulling data from the user feed. * * @param App $a - * @param string $dfrn_id + * @param string $dfrn_id DFRN ID from the requesting party * @param string $owner_nick Owner nick name * @param string $last_update Date of the last update - * @param int $direction + * @param int $direction Can be -1, 0 or 1. * * @return string DFRN feed entries */ @@ -662,7 +662,7 @@ function dfrn_get_attachment($doc, $root, $item) { * @param array $item Item element * @param array $owner Owner record * @param bool $comment Trigger the sending of the "comment" element - * @param int $cid + * @param int $cid Contact ID of the recipient * * @return object XML entry object */ From ffd8f1234e828d89b0e735cb77e43559cd2e807f Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Mon, 25 Jan 2016 01:15:10 +0100 Subject: [PATCH 13/18] Some more documentation --- include/dfrn.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/dfrn.php b/include/dfrn.php index c6b7f5937..a6b09242d 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -720,6 +720,8 @@ function dfrn_entry($doc, $type, $item, $owner, $comment = false, $cid = 0) { xml_add_element($doc, $entry, "link", "", array("rel" => "alternate", "type" => "text/html", "href" => $a->get_baseurl()."/display/".$item["guid"])); + // "comment-allow" is some old fashioned stuff for old Friendica versions. + // It is included in the rewritten code for completeness if ($comment) xml_add_element($doc, $entry, "dfrn:comment-allow", intval($item['last-child'])); @@ -743,6 +745,8 @@ function dfrn_entry($doc, $type, $item, $owner, $comment = false, $cid = 0) { xml_add_element($doc, $entry, "dfrn:diaspora_guid", $item["guid"]); + // The signed text contains the content in Markdown, the sender handle and the signatur for the content + // It is needed for relayed comments to Diaspora. if($item['signed_text']) { $sign = base64_encode(json_encode(array('signed_text' => $item['signed_text'],'signature' => $item['signature'],'signer' => $item['signer']))); xml_add_element($doc, $entry, "dfrn:diaspora_signature", $sign); From 77c6020dc2205d701fdf609288868be19f8673e5 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Mon, 25 Jan 2016 10:38:38 +0100 Subject: [PATCH 14/18] Removed useless get_app function call --- include/dfrn.php | 1 - 1 file changed, 1 deletion(-) diff --git a/include/dfrn.php b/include/dfrn.php index a6b09242d..a951e11fc 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -545,7 +545,6 @@ function dfrn_add_author($doc, $owner, $authorelement, $public) { * @return object XML author object */ function dfrn_add_entry_author($doc, $element, $contact_url, $item) { - $a = get_app(); $contact = get_contact_details_by_url($contact_url, $item["uid"]); From 62de6be495214e4b12a92a1877711768f4a1d992 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Mon, 25 Jan 2016 15:20:58 +0100 Subject: [PATCH 15/18] Switched to static methods for DFRN --- boot.php | 8 + include/Contact.php | 4 +- include/delivery.php | 12 +- include/dfrn.php | 1598 ++++++++++++++++++++++++------------------ include/items.php | 236 ------- include/queue.php | 3 +- mod/dfrn_poll.php | 4 +- 7 files changed, 934 insertions(+), 931 deletions(-) diff --git a/boot.php b/boot.php index 2242ba476..955b89e56 100644 --- a/boot.php +++ b/boot.php @@ -530,6 +530,8 @@ class App { private $cached_profile_image; private $cached_profile_picdate; + private static $a; + /** * @brief App constructor. */ @@ -710,6 +712,8 @@ class App { } } + self::$a = $this; + } function get_basepath() { @@ -734,6 +738,10 @@ class App { function get_baseurl($ssl = false) { + // Is the function called statically? + if (!is_object($this)) + return(self::$a->get_baseurl($ssl)); + $scheme = $this->scheme; if((x($this->config,'system')) && (x($this->config['system'],'ssl_policy'))) { diff --git a/include/Contact.php b/include/Contact.php index 831a99c95..d9703d61e 100644 --- a/include/Contact.php +++ b/include/Contact.php @@ -132,8 +132,8 @@ function terminate_friendship($user,$self,$contact) { diaspora_unshare($user,$contact); } elseif($contact['network'] === NETWORK_DFRN) { - require_once('include/items.php'); - dfrn_deliver($user,$contact,'placeholder', 1); + require_once('include/dfrn.php'); + dfrn::deliver($user,$contact,'placeholder', 1); } } diff --git a/include/delivery.php b/include/delivery.php index d04600599..5ef942dd0 100644 --- a/include/delivery.php +++ b/include/delivery.php @@ -279,12 +279,12 @@ function delivery_run(&$argv, &$argc){ if ($mail) { $item['body'] = fix_private_photos($item['body'],$owner['uid'],null,$message[0]['contact-id']); - $atom = dfrn_mail($item, $owner); + $atom = dfrn::mail($item, $owner); } elseif ($fsuggest) { - $atom = dfrn_fsuggest($item, $owner); + $atom = dfrn::fsuggest($item, $owner); q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item['id'])); } elseif ($relocate) - $atom = dfrn_relocate($owner, $uid); + $atom = dfrn::relocate($owner, $uid); elseif($followup) { $msgitems = array(); foreach($items as $item) { // there is only one item @@ -295,7 +295,7 @@ function delivery_run(&$argv, &$argc){ $msgitems[] = $item; } } - $atom = dfrn_entries($msgitems,$owner); + $atom = dfrn::entries($msgitems,$owner); } else { $msgitems = array(); foreach($items as $item) { @@ -321,7 +321,7 @@ function delivery_run(&$argv, &$argc){ $msgitems[] = $item; } } - $atom = dfrn_entries($msgitems,$owner); + $atom = dfrn::entries($msgitems,$owner); } logger('notifier entry: '.$contact["url"].' '.$target_item["guid"].' entry: '.$atom, LOGGER_DEBUG); @@ -380,7 +380,7 @@ function delivery_run(&$argv, &$argc){ } if(! was_recently_delayed($contact['id'])) - $deliver_status = dfrn_deliver($owner,$contact,$atom); + $deliver_status = dfrn::deliver($owner,$contact,$atom); else $deliver_status = (-1); diff --git a/include/dfrn.php b/include/dfrn.php index a951e11fc..885e03a91 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -3,210 +3,240 @@ require_once('include/items.php'); require_once('include/Contact.php'); require_once('include/ostatus.php'); -/** - * @brief Generates the atom entries for delivery.php - * - * This function is used whenever content is transmitted via DFRN. - * - * @param array $items Item elements - * @param array $owner Owner record - * - * @return string DFRN entries - */ -function dfrn_entries($items,$owner) { +class dfrn { - $doc = new DOMDocument('1.0', 'utf-8'); - $doc->formatOutput = true; + /** + * @brief Generates the atom entries for delivery.php + * + * This function is used whenever content is transmitted via DFRN. + * + * @param array $items Item elements + * @param array $owner Owner record + * + * @return string DFRN entries + */ + function entries($items,$owner) { - $root = dfrn_add_header($doc, $owner, "dfrn:owner", "", false); + $doc = new DOMDocument('1.0', 'utf-8'); + $doc->formatOutput = true; - if(! count($items)) - return trim($doc->saveXML()); + $root = self::add_header($doc, $owner, "dfrn:owner", "", false); - foreach($items as $item) { - $entry = dfrn_entry($doc, "text", $item, $owner, $item["entry:comment-allow"], $item["entry:cid"]); - $root->appendChild($entry); - } + if(! count($items)) + return trim($doc->saveXML()); - return(trim($doc->saveXML())); -} - -/** - * @brief Generate an atom feed for the given user - * - * This function is called when another server is pulling data from the user feed. - * - * @param App $a - * @param string $dfrn_id DFRN ID from the requesting party - * @param string $owner_nick Owner nick name - * @param string $last_update Date of the last update - * @param int $direction Can be -1, 0 or 1. - * - * @return string DFRN feed entries - */ -function dfrn_feed(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) { - - $sitefeed = ((strlen($owner_nick)) ? false : true); // not yet implemented, need to rewrite huge chunks of following logic - $public_feed = (($dfrn_id) ? false : true); - $starred = false; // not yet implemented, possible security issues - $converse = false; - - if($public_feed && $a->argc > 2) { - for($x = 2; $x < $a->argc; $x++) { - if($a->argv[$x] == 'converse') - $converse = true; - if($a->argv[$x] == 'starred') - $starred = true; - if($a->argv[$x] === 'category' && $a->argc > ($x + 1) && strlen($a->argv[$x+1])) - $category = $a->argv[$x+1]; - } - } - - - - // default permissions - anonymous user - - $sql_extra = " AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = '' "; - - $r = q("SELECT `contact`.*, `user`.`uid` AS `user_uid`, `user`.`nickname`, `user`.`timezone`, `user`.`page-flags` - FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid` - WHERE `contact`.`self` = 1 AND `user`.`nickname` = '%s' LIMIT 1", - dbesc($owner_nick) - ); - - if(! count($r)) - killme(); - - $owner = $r[0]; - $owner_id = $owner['user_uid']; - $owner_nick = $owner['nickname']; - - $sql_post_table = ""; - $visibility = ""; - - if(! $public_feed) { - - $sql_extra = ''; - switch($direction) { - case (-1): - $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($dfrn_id)); - $my_id = $dfrn_id; - break; - case 0: - $sql_extra = sprintf(" AND `issued-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); - $my_id = '1:' . $dfrn_id; - break; - case 1: - $sql_extra = sprintf(" AND `dfrn-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); - $my_id = '0:' . $dfrn_id; - break; - default: - return false; - break; // NOTREACHED + foreach($items as $item) { + $entry = self::entry($doc, "text", $item, $owner, $item["entry:comment-allow"], $item["entry:cid"]); + $root->appendChild($entry); } - $r = q("SELECT * FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `contact`.`uid` = %d $sql_extra LIMIT 1", - intval($owner_id) + return(trim($doc->saveXML())); + } + + /** + * @brief Generate an atom feed for the given user + * + * This function is called when another server is pulling data from the user feed. + * + * @param string $dfrn_id DFRN ID from the requesting party + * @param string $owner_nick Owner nick name + * @param string $last_update Date of the last update + * @param int $direction Can be -1, 0 or 1. + * + * @return string DFRN feed entries + */ + function feed($dfrn_id, $owner_nick, $last_update, $direction = 0) { + + $a = get_app(); + + $sitefeed = ((strlen($owner_nick)) ? false : true); // not yet implemented, need to rewrite huge chunks of following logic + $public_feed = (($dfrn_id) ? false : true); + $starred = false; // not yet implemented, possible security issues + $converse = false; + + if($public_feed && $a->argc > 2) { + for($x = 2; $x < $a->argc; $x++) { + if($a->argv[$x] == 'converse') + $converse = true; + if($a->argv[$x] == 'starred') + $starred = true; + if($a->argv[$x] === 'category' && $a->argc > ($x + 1) && strlen($a->argv[$x+1])) + $category = $a->argv[$x+1]; + } + } + + + + // default permissions - anonymous user + + $sql_extra = " AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = '' "; + + $r = q("SELECT `contact`.*, `user`.`uid` AS `user_uid`, `user`.`nickname`, `user`.`timezone`, `user`.`page-flags` + FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid` + WHERE `contact`.`self` = 1 AND `user`.`nickname` = '%s' LIMIT 1", + dbesc($owner_nick) ); if(! count($r)) killme(); - $contact = $r[0]; - require_once('include/security.php'); - $groups = init_groups_visitor($contact['id']); + $owner = $r[0]; + $owner_id = $owner['user_uid']; + $owner_nick = $owner['nickname']; - if(count($groups)) { - for($x = 0; $x < count($groups); $x ++) - $groups[$x] = '<' . intval($groups[$x]) . '>' ; - $gs = implode('|', $groups); + $sql_post_table = ""; + $visibility = ""; + + if(! $public_feed) { + + $sql_extra = ''; + switch($direction) { + case (-1): + $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($dfrn_id)); + $my_id = $dfrn_id; + break; + case 0: + $sql_extra = sprintf(" AND `issued-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); + $my_id = '1:' . $dfrn_id; + break; + case 1: + $sql_extra = sprintf(" AND `dfrn-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id)); + $my_id = '0:' . $dfrn_id; + break; + default: + return false; + break; // NOTREACHED + } + + $r = q("SELECT * FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `contact`.`uid` = %d $sql_extra LIMIT 1", + intval($owner_id) + ); + + if(! count($r)) + killme(); + + $contact = $r[0]; + require_once('include/security.php'); + $groups = init_groups_visitor($contact['id']); + + if(count($groups)) { + for($x = 0; $x < count($groups); $x ++) + $groups[$x] = '<' . intval($groups[$x]) . '>' ; + $gs = implode('|', $groups); + } else + $gs = '<<>>' ; // Impossible to match + + $sql_extra = sprintf(" + AND ( `allow_cid` = '' OR `allow_cid` REGEXP '<%d>' ) + AND ( `deny_cid` = '' OR NOT `deny_cid` REGEXP '<%d>' ) + AND ( `allow_gid` = '' OR `allow_gid` REGEXP '%s' ) + AND ( `deny_gid` = '' OR NOT `deny_gid` REGEXP '%s') + ", + intval($contact['id']), + intval($contact['id']), + dbesc($gs), + dbesc($gs) + ); } + + if($public_feed) + $sort = 'DESC'; else - $gs = '<<>>' ; // Impossible to match + $sort = 'ASC'; - $sql_extra = sprintf(" - AND ( `allow_cid` = '' OR `allow_cid` REGEXP '<%d>' ) - AND ( `deny_cid` = '' OR NOT `deny_cid` REGEXP '<%d>' ) - AND ( `allow_gid` = '' OR `allow_gid` REGEXP '%s' ) - AND ( `deny_gid` = '' OR NOT `deny_gid` REGEXP '%s') - ", - intval($contact['id']), - intval($contact['id']), - dbesc($gs), - dbesc($gs) + $date_field = "`changed`"; + $sql_order = "`item`.`parent` ".$sort.", `item`.`created` ASC"; + + if(! strlen($last_update)) + $last_update = 'now -30 days'; + + if(isset($category)) { + $sql_post_table = sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ", + dbesc(protect_sprintf($category)), intval(TERM_OBJ_POST), intval(TERM_CATEGORY), intval($owner_id)); + //$sql_extra .= file_tag_file_query('item',$category,'category'); + } + + if($public_feed) { + if(! $converse) + $sql_extra .= " AND `contact`.`self` = 1 "; + } + + $check_date = datetime_convert('UTC','UTC',$last_update,'Y-m-d H:i:s'); + + // AND ( `item`.`edited` > '%s' OR `item`.`changed` > '%s' ) + // dbesc($check_date), + + $r = q("SELECT STRAIGHT_JOIN `item`.*, `item`.`id` AS `item_id`, + `contact`.`name`, `contact`.`network`, `contact`.`photo`, `contact`.`url`, + `contact`.`name-date`, `contact`.`uri-date`, `contact`.`avatar-date`, + `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, + `contact`.`id` AS `contact-id`, `contact`.`uid` AS `contact-uid`, + `sign`.`signed_text`, `sign`.`signature`, `sign`.`signer` + FROM `item` $sql_post_table + INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` + AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0 + LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` + WHERE `item`.`uid` = %d AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`parent` != 0 + AND ((`item`.`wall` = 1) $visibility) AND `item`.$date_field > '%s' + $sql_extra + ORDER BY $sql_order LIMIT 0, 300", + intval($owner_id), + dbesc($check_date), + dbesc($sort) ); - } - if($public_feed) - $sort = 'DESC'; - else - $sort = 'ASC'; + // Will check further below if this actually returned results. + // We will provide an empty feed if that is the case. - $date_field = "`changed`"; - $sql_order = "`item`.`parent` ".$sort.", `item`.`created` ASC"; + $items = $r; - if(! strlen($last_update)) - $last_update = 'now -30 days'; + $doc = new DOMDocument('1.0', 'utf-8'); + $doc->formatOutput = true; - if(isset($category)) { - $sql_post_table = sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ", - dbesc(protect_sprintf($category)), intval(TERM_OBJ_POST), intval(TERM_CATEGORY), intval($owner_id)); - //$sql_extra .= file_tag_file_query('item',$category,'category'); - } + $alternatelink = $owner['url']; - if($public_feed) { - if(! $converse) - $sql_extra .= " AND `contact`.`self` = 1 "; - } + if(isset($category)) + $alternatelink .= "/category/".$category; - $check_date = datetime_convert('UTC','UTC',$last_update,'Y-m-d H:i:s'); + if ($public_feed) + $author = "dfrn:owner"; + else + $author = "author"; - // AND ( `item`.`edited` > '%s' OR `item`.`changed` > '%s' ) - // dbesc($check_date), + $root = self::add_header($doc, $owner, $author, $alternatelink, true); - $r = q("SELECT STRAIGHT_JOIN `item`.*, `item`.`id` AS `item_id`, - `contact`.`name`, `contact`.`network`, `contact`.`photo`, `contact`.`url`, - `contact`.`name-date`, `contact`.`uri-date`, `contact`.`avatar-date`, - `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`, - `contact`.`id` AS `contact-id`, `contact`.`uid` AS `contact-uid`, - `sign`.`signed_text`, `sign`.`signature`, `sign`.`signer` - FROM `item` $sql_post_table - INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` - AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0 - LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` - WHERE `item`.`uid` = %d AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`parent` != 0 - AND ((`item`.`wall` = 1) $visibility) AND `item`.$date_field > '%s' - $sql_extra - ORDER BY $sql_order LIMIT 0, 300", - intval($owner_id), - dbesc($check_date), - dbesc($sort) - ); + // This hook can't work anymore + // call_hooks('atom_feed', $atom); - // Will check further below if this actually returned results. - // We will provide an empty feed if that is the case. + if(! count($items)) { + $atom = trim($doc->saveXML()); - $items = $r; + call_hooks('atom_feed_end', $atom); - $doc = new DOMDocument('1.0', 'utf-8'); - $doc->formatOutput = true; + return $atom; + } - $alternatelink = $owner['url']; + foreach($items as $item) { - if(isset($category)) - $alternatelink .= "/category/".$category; + // prevent private email from leaking. + if($item['network'] === NETWORK_MAIL) + continue; - if ($public_feed) - $author = "dfrn:owner"; - else - $author = "author"; + // public feeds get html, our own nodes use bbcode - $root = dfrn_add_header($doc, $owner, $author, $alternatelink, true); + if($public_feed) { + $type = 'html'; + // catch any email that's in a public conversation and make sure it doesn't leak + if($item['private']) + continue; + } else + $type = 'text'; - // This hook can't work anymore - // call_hooks('atom_feed', $atom); + $entry = self::entry($doc, $type, $item, $owner, true); + $root->appendChild($entry); + + } - if(! count($items)) { $atom = trim($doc->saveXML()); call_hooks('atom_feed_end', $atom); @@ -214,581 +244,781 @@ function dfrn_feed(&$a, $dfrn_id, $owner_nick, $last_update, $direction = 0) { return $atom; } - foreach($items as $item) { + /** + * @brief Create XML text for DFRN mails + * + * @param array $item message elements + * @param array $owner Owner record + * + * @return string DFRN mail + */ + function mail($item, $owner) { + $doc = new DOMDocument('1.0', 'utf-8'); + $doc->formatOutput = true; - // prevent private email from leaking. - if($item['network'] === NETWORK_MAIL) - continue; + $root = self::add_header($doc, $owner, "dfrn:owner", "", false); - // public feeds get html, our own nodes use bbcode + $mail = $doc->createElement("dfrn:mail"); + $sender = $doc->createElement("dfrn:sender"); - if($public_feed) { - $type = 'html'; - // catch any email that's in a public conversation and make sure it doesn't leak - if($item['private']) - continue; - } - else { - $type = 'text'; + xml_add_element($doc, $sender, "dfrn:name", $owner['name']); + xml_add_element($doc, $sender, "dfrn:uri", $owner['url']); + xml_add_element($doc, $sender, "dfrn:avatar", $owner['thumb']); + + $mail->appendChild($sender); + + xml_add_element($doc, $mail, "dfrn:id", $item['uri']); + xml_add_element($doc, $mail, "dfrn:in-reply-to", $item['parent-uri']); + xml_add_element($doc, $mail, "dfrn:sentdate", datetime_convert('UTC', 'UTC', $item['created'] . '+00:00' , ATOM_TIME)); + xml_add_element($doc, $mail, "dfrn:subject", $item['title']); + xml_add_element($doc, $mail, "dfrn:content", $item['body']); + + $root->appendChild($mail); + + return(trim($doc->saveXML())); + } + + /** + * @brief Create XML text for DFRN friend suggestions + * + * @param array $item suggestion elements + * @param array $owner Owner record + * + * @return string DFRN suggestions + */ + function fsuggest($item, $owner) { + $doc = new DOMDocument('1.0', 'utf-8'); + $doc->formatOutput = true; + + $root = self::add_header($doc, $owner, "dfrn:owner", "", false); + + $suggest = $doc->createElement("dfrn:suggest"); + + xml_add_element($doc, $suggest, "dfrn:url", $item['url']); + xml_add_element($doc, $suggest, "dfrn:name", $item['name']); + xml_add_element($doc, $suggest, "dfrn:photo", $item['photo']); + xml_add_element($doc, $suggest, "dfrn:request", $item['request']); + xml_add_element($doc, $suggest, "dfrn:note", $item['note']); + + $root->appendChild($suggest); + + return(trim($doc->saveXML())); + } + + /** + * @brief Create XML text for DFRN relocations + * + * @param array $owner Owner record + * @param int $uid User ID + * + * @return string DFRN relocations + */ + function relocate($owner, $uid) { + + /* get site pubkey. this could be a new installation with no site keys*/ + $pubkey = get_config('system','site_pubkey'); + if(! $pubkey) { + $res = new_keypair(1024); + set_config('system','site_prvkey', $res['prvkey']); + set_config('system','site_pubkey', $res['pubkey']); } - $entry = dfrn_entry($doc, $type, $item, $owner, true); - $root->appendChild($entry); + $rp = q("SELECT `resource-id` , `scale`, type FROM `photo` + WHERE `profile` = 1 AND `uid` = %d ORDER BY scale;", $uid); + $photos = array(); + $ext = Photo::supportedTypes(); + foreach($rp as $p) + $photos[$p['scale']] = app::get_baseurl().'/photo/'.$p['resource-id'].'-'.$p['scale'].'.'.$ext[$p['type']]; + + unset($rp, $ext); + + $doc = new DOMDocument('1.0', 'utf-8'); + $doc->formatOutput = true; + + $root = self::add_header($doc, $owner, "dfrn:owner", "", false); + + $relocate = $doc->createElement("dfrn:relocate"); + + xml_add_element($doc, $relocate, "dfrn:url", $owner['url']); + xml_add_element($doc, $relocate, "dfrn:name", $owner['name']); + xml_add_element($doc, $relocate, "dfrn:photo", $photos[4]); + xml_add_element($doc, $relocate, "dfrn:thumb", $photos[5]); + xml_add_element($doc, $relocate, "dfrn:micro", $photos[6]); + xml_add_element($doc, $relocate, "dfrn:request", $owner['request']); + xml_add_element($doc, $relocate, "dfrn:confirm", $owner['confirm']); + xml_add_element($doc, $relocate, "dfrn:notify", $owner['notify']); + xml_add_element($doc, $relocate, "dfrn:poll", $owner['poll']); + xml_add_element($doc, $relocate, "dfrn:sitepubkey", get_config('system','site_pubkey')); + + $root->appendChild($relocate); + + return(trim($doc->saveXML())); } - $atom = trim($doc->saveXML()); + /** + * @brief Adds the header elements for the DFRN protocol + * + * @param object $doc XML document + * @param array $owner Owner record + * @param string $authorelement Element name for the author + * @param string $alternatelink link to profile or category + * @param bool $public Is it a header for public posts? + * + * @return object XML root object + */ + private function add_header($doc, $owner, $authorelement, $alternatelink = "", $public = false) { - call_hooks('atom_feed_end', $atom); + if ($alternatelink == "") + $alternatelink = $owner['url']; - return $atom; -} + $root = $doc->createElementNS(NS_ATOM, 'feed'); + $doc->appendChild($root); -/** - * @brief Create XML text for DFRN mails - * - * @param array $item message elements - * @param array $owner Owner record - * - * @return string DFRN mail - */ -function dfrn_mail($item, $owner) { - $doc = new DOMDocument('1.0', 'utf-8'); - $doc->formatOutput = true; + $root->setAttribute("xmlns:thr", NS_THR); + $root->setAttribute("xmlns:at", "http://purl.org/atompub/tombstones/1.0"); + $root->setAttribute("xmlns:media", NS_MEDIA); + $root->setAttribute("xmlns:dfrn", "http://purl.org/macgirvin/dfrn/1.0"); + $root->setAttribute("xmlns:activity", NS_ACTIVITY); + $root->setAttribute("xmlns:georss", NS_GEORSS); + $root->setAttribute("xmlns:poco", NS_POCO); + $root->setAttribute("xmlns:ostatus", NS_OSTATUS); + $root->setAttribute("xmlns:statusnet", NS_STATUSNET); - $root = dfrn_add_header($doc, $owner, "dfrn:owner", "", false); + //xml_add_element($doc, $root, "id", app::get_baseurl()."/profile/".$owner["nick"]); + xml_add_element($doc, $root, "id", app::get_baseurl()."/profile/".$owner["nick"]); + xml_add_element($doc, $root, "title", $owner["name"]); - $mail = $doc->createElement("dfrn:mail"); - $sender = $doc->createElement("dfrn:sender"); + $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, $sender, "dfrn:name", $owner['name']); - xml_add_element($doc, $sender, "dfrn:uri", $owner['url']); - xml_add_element($doc, $sender, "dfrn:avatar", $owner['thumb']); - - $mail->appendChild($sender); - - xml_add_element($doc, $mail, "dfrn:id", $item['uri']); - xml_add_element($doc, $mail, "dfrn:in-reply-to", $item['parent-uri']); - xml_add_element($doc, $mail, "dfrn:sentdate", datetime_convert('UTC', 'UTC', $item['created'] . '+00:00' , ATOM_TIME)); - xml_add_element($doc, $mail, "dfrn:subject", $item['title']); - xml_add_element($doc, $mail, "dfrn:content", $item['body']); - - $root->appendChild($mail); - - return(trim($doc->saveXML())); -} - -/** - * @brief Create XML text for DFRN friend suggestions - * - * @param array $item suggestion elements - * @param array $owner Owner record - * - * @return string DFRN suggestions - */ -function dfrn_fsuggest($item, $owner) { - $doc = new DOMDocument('1.0', 'utf-8'); - $doc->formatOutput = true; - - $root = dfrn_add_header($doc, $owner, "dfrn:owner", "", false); - - $suggest = $doc->createElement("dfrn:suggest"); - - xml_add_element($doc, $suggest, "dfrn:url", $item['url']); - xml_add_element($doc, $suggest, "dfrn:name", $item['name']); - xml_add_element($doc, $suggest, "dfrn:photo", $item['photo']); - xml_add_element($doc, $suggest, "dfrn:request", $item['request']); - xml_add_element($doc, $suggest, "dfrn:note", $item['note']); - - $root->appendChild($suggest); - - return(trim($doc->saveXML())); -} - -/** - * @brief Create XML text for DFRN relocations - * - * @param array $owner Owner record - * @param int $uid User ID - * - * @return string DFRN relocations - */ -function dfrn_relocate($owner, $uid) { - - $a = get_app(); - - /* get site pubkey. this could be a new installation with no site keys*/ - $pubkey = get_config('system','site_pubkey'); - if(! $pubkey) { - $res = new_keypair(1024); - set_config('system','site_prvkey', $res['prvkey']); - set_config('system','site_pubkey', $res['pubkey']); - } - - $rp = q("SELECT `resource-id` , `scale`, type FROM `photo` - WHERE `profile` = 1 AND `uid` = %d ORDER BY scale;", $uid); - $photos = array(); - $ext = Photo::supportedTypes(); - foreach($rp as $p){ - $photos[$p['scale']] = $a->get_baseurl().'/photo/'.$p['resource-id'].'-'.$p['scale'].'.'.$ext[$p['type']]; - } - unset($rp, $ext); - - $doc = new DOMDocument('1.0', 'utf-8'); - $doc->formatOutput = true; - - $root = dfrn_add_header($doc, $owner, "dfrn:owner", "", false); - - $relocate = $doc->createElement("dfrn:relocate"); - - xml_add_element($doc, $relocate, "dfrn:url", $owner['url']); - xml_add_element($doc, $relocate, "dfrn:name", $owner['name']); - xml_add_element($doc, $relocate, "dfrn:photo", $photos[4]); - xml_add_element($doc, $relocate, "dfrn:thumb", $photos[5]); - xml_add_element($doc, $relocate, "dfrn:micro", $photos[6]); - xml_add_element($doc, $relocate, "dfrn:request", $owner['request']); - xml_add_element($doc, $relocate, "dfrn:confirm", $owner['confirm']); - xml_add_element($doc, $relocate, "dfrn:notify", $owner['notify']); - xml_add_element($doc, $relocate, "dfrn:poll", $owner['poll']); - xml_add_element($doc, $relocate, "dfrn:sitepubkey", get_config('system','site_pubkey')); - - $root->appendChild($relocate); - - return(trim($doc->saveXML())); -} - -/** - * @brief Adds the header elements for the DFRN protocol - * - * @param object $doc XML document - * @param array $owner Owner record - * @param string $authorelement Element name for the author - * @param string $alternatelink link to profile or category - * @param bool $public Is it a header for public posts? - * - * @return object XML root object - */ -function dfrn_add_header($doc, $owner, $authorelement, $alternatelink = "", $public = false) { - $a = get_app(); - - if ($alternatelink == "") - $alternatelink = $owner['url']; - - $root = $doc->createElementNS(NS_ATOM, 'feed'); - $doc->appendChild($root); - - $root->setAttribute("xmlns:thr", NS_THR); - $root->setAttribute("xmlns:at", "http://purl.org/atompub/tombstones/1.0"); - $root->setAttribute("xmlns:media", NS_MEDIA); - $root->setAttribute("xmlns:dfrn", "http://purl.org/macgirvin/dfrn/1.0"); - $root->setAttribute("xmlns:activity", NS_ACTIVITY); - $root->setAttribute("xmlns:georss", NS_GEORSS); - $root->setAttribute("xmlns:poco", NS_POCO); - $root->setAttribute("xmlns:ostatus", NS_OSTATUS); - $root->setAttribute("xmlns:statusnet", NS_STATUSNET); - - xml_add_element($doc, $root, "id", $a->get_baseurl()."/profile/".$owner["nick"]); - xml_add_element($doc, $root, "title", $owner["name"]); - - $attributes = array("uri" => "https://friendi.ca", "version" => FRIENDICA_VERSION."-".DB_UPDATE_VERSION); - xml_add_element($doc, $root, "generator", FRIENDICA_PLATFORM, $attributes); - - $attributes = array("rel" => "license", "href" => "http://creativecommons.org/licenses/by/3.0/"); - xml_add_element($doc, $root, "link", "", $attributes); - - $attributes = array("rel" => "alternate", "type" => "text/html", "href" => $alternatelink); - xml_add_element($doc, $root, "link", "", $attributes); - - ostatus_hublinks($doc, $root); - - if ($public) { - $attributes = array("rel" => "salmon", "href" => $a->get_baseurl()."/salmon/".$owner["nick"]); + $attributes = array("rel" => "license", "href" => "http://creativecommons.org/licenses/by/3.0/"); xml_add_element($doc, $root, "link", "", $attributes); - $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-replies", "href" => $a->get_baseurl()."/salmon/".$owner["nick"]); + $attributes = array("rel" => "alternate", "type" => "text/html", "href" => $alternatelink); xml_add_element($doc, $root, "link", "", $attributes); - $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-mention", "href" => $a->get_baseurl()."/salmon/".$owner["nick"]); - xml_add_element($doc, $root, "link", "", $attributes); + ostatus_hublinks($doc, $root); + + if ($public) { + $attributes = array("rel" => "salmon", "href" => app::get_baseurl()."/salmon/".$owner["nick"]); + xml_add_element($doc, $root, "link", "", $attributes); + + $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-replies", "href" => app::get_baseurl()."/salmon/".$owner["nick"]); + xml_add_element($doc, $root, "link", "", $attributes); + + $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-mention", "href" => app::get_baseurl()."/salmon/".$owner["nick"]); + xml_add_element($doc, $root, "link", "", $attributes); + } + + if ($owner['page-flags'] == PAGE_COMMUNITY) + xml_add_element($doc, $root, "dfrn:community", 1); + + xml_add_element($doc, $root, "updated", datetime_convert("UTC", "UTC", "now", ATOM_TIME)); + + $author = self::add_author($doc, $owner, $authorelement, $public); + $root->appendChild($author); + + return $root; } - if ($owner['page-flags'] == PAGE_COMMUNITY) - xml_add_element($doc, $root, "dfrn:community", 1); + /** + * @brief Adds the author element in the header for the DFRN protocol + * + * @param object $doc XML document + * @param array $owner Owner record + * @param string $authorelement Element name for the author + * + * @return object XML author object + */ + private function add_author($doc, $owner, $authorelement, $public) { - xml_add_element($doc, $root, "updated", datetime_convert("UTC", "UTC", "now", ATOM_TIME)); + $author = $doc->createElement($authorelement); - $author = dfrn_add_author($doc, $owner, $authorelement, $public); - $root->appendChild($author); + $namdate = datetime_convert('UTC', 'UTC', $owner['name-date'].'+00:00' , ATOM_TIME); + $uridate = datetime_convert('UTC', 'UTC', $owner['uri-date'].'+00:00', ATOM_TIME); + $picdate = datetime_convert('UTC', 'UTC', $owner['avatar-date'].'+00:00', ATOM_TIME); - return $root; -} + $attributes = array("dfrn:updated" => $namdate); + xml_add_element($doc, $author, "name", $owner["name"], $attributes); -/** - * @brief Adds the author element in the header for the DFRN protocol - * - * @param object $doc XML document - * @param array $owner Owner record - * @param string $authorelement Element name for the author - * - * @return object XML author object - */ -function dfrn_add_author($doc, $owner, $authorelement, $public) { - $a = get_app(); + $attributes = array("dfrn:updated" => $namdate); + xml_add_element($doc, $author, "uri", app::get_baseurl().'/profile/'.$owner["nickname"], $attributes); - $author = $doc->createElement($authorelement); + $attributes = array("rel" => "photo", "type" => "image/jpeg", "dfrn:updated" => $picdate, + "media:width" => 175, "media:height" => 175, "href" => $owner['photo']); + xml_add_element($doc, $author, "link", "", $attributes); - $namdate = datetime_convert('UTC', 'UTC', $owner['name-date'].'+00:00' , ATOM_TIME); - $uridate = datetime_convert('UTC', 'UTC', $owner['uri-date'].'+00:00', ATOM_TIME); - $picdate = datetime_convert('UTC', 'UTC', $owner['avatar-date'].'+00:00', ATOM_TIME); + $attributes = array("rel" => "avatar", "type" => "image/jpeg", "dfrn:updated" => $picdate, + "media:width" => 175, "media:height" => 175, "href" => $owner['photo']); + xml_add_element($doc, $author, "link", "", $attributes); - $attributes = array("dfrn:updated" => $namdate); - xml_add_element($doc, $author, "name", $owner["name"], $attributes); + $birthday = feed_birthday($owner['user_uid'], $owner['timezone']); - $attributes = array("dfrn:updated" => $namdate); - xml_add_element($doc, $author, "uri", $a->get_baseurl().'/profile/'.$owner["nickname"], $attributes); + if ($birthday) + xml_add_element($doc, $author, "dfrn:birthday", $birthday); - $attributes = array("rel" => "photo", "type" => "image/jpeg", "dfrn:updated" => $picdate, - "media:width" => 175, "media:height" => 175, "href" => $owner['photo']); - xml_add_element($doc, $author, "link", "", $attributes); + // The following fields will only be generated if this isn't for a public feed + if ($public) + return $author; - $attributes = array("rel" => "avatar", "type" => "image/jpeg", "dfrn:updated" => $picdate, - "media:width" => 175, "media:height" => 175, "href" => $owner['photo']); - xml_add_element($doc, $author, "link", "", $attributes); + // Only show contact details when we are allowed to + $r = q("SELECT `profile`.`about`, `profile`.`name`, `profile`.`homepage`, `user`.`nickname`, `user`.`timezone`, + `profile`.`locality`, `profile`.`region`, `profile`.`country-name`, `profile`.`pub_keywords`, `profile`.`dob` + FROM `profile` + INNER JOIN `user` ON `user`.`uid` = `profile`.`uid` + WHERE `profile`.`is-default` AND NOT `user`.`hidewall` AND `user`.`uid` = %d", + intval($owner['user_uid'])); + if ($r) { + $profile = $r[0]; + xml_add_element($doc, $author, "poco:displayName", $profile["name"]); + xml_add_element($doc, $author, "poco:updated", $namdate); - $birthday = feed_birthday($owner['user_uid'], $owner['timezone']); + if (trim($profile["dob"]) != "0000-00-00") + xml_add_element($doc, $author, "poco:birthday", "0000-".date("m-d", strtotime($profile["dob"]))); - if ($birthday) - xml_add_element($doc, $author, "dfrn:birthday", $birthday); + xml_add_element($doc, $author, "poco:note", $profile["about"]); + xml_add_element($doc, $author, "poco:preferredUsername", $profile["nickname"]); + + $savetz = date_default_timezone_get(); + date_default_timezone_set($profile["timezone"]); + xml_add_element($doc, $author, "poco:utcOffset", date("P")); + date_default_timezone_set($savetz); + + 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 (trim($profile["pub_keywords"]) != "") { + $keywords = explode(",", $profile["pub_keywords"]); + + foreach ($keywords AS $keyword) + xml_add_element($doc, $author, "poco:tags", trim($keyword)); + + } + + /// @todo When we are having the XMPP address in the profile we should propagate it here + $xmpp = ""; + if (trim($xmpp) != "") { + $ims = $doc->createElement("poco:ims"); + xml_add_element($doc, $ims, "poco:type", "xmpp"); + xml_add_element($doc, $ims, "poco:value", $xmpp); + xml_add_element($doc, $ims, "poco:primary", "true"); + $author->appendChild($ims); + } + + if (trim($profile["locality"].$profile["region"].$profile["country-name"]) != "") { + $element = $doc->createElement("poco:address"); + + xml_add_element($doc, $element, "poco:formatted", formatted_location($profile)); + + if (trim($profile["locality"]) != "") + xml_add_element($doc, $element, "poco:locality", $profile["locality"]); + + if (trim($profile["region"]) != "") + xml_add_element($doc, $element, "poco:region", $profile["region"]); + + if (trim($profile["country-name"]) != "") + xml_add_element($doc, $element, "poco:country", $profile["country-name"]); + + $author->appendChild($element); + } + } - // The following fields will only be generated if this isn't for a public feed - if ($public) return $author; + } - // Only show contact details when we are allowed to - $r = q("SELECT `profile`.`about`, `profile`.`name`, `profile`.`homepage`, `user`.`nickname`, `user`.`timezone`, - `profile`.`locality`, `profile`.`region`, `profile`.`country-name`, `profile`.`pub_keywords`, `profile`.`dob` - FROM `profile` - INNER JOIN `user` ON `user`.`uid` = `profile`.`uid` - WHERE `profile`.`is-default` AND NOT `user`.`hidewall` AND `user`.`uid` = %d", - intval($owner['user_uid'])); - if ($r) { - $profile = $r[0]; - xml_add_element($doc, $author, "poco:displayName", $profile["name"]); - xml_add_element($doc, $author, "poco:updated", $namdate); + /** + * @brief Adds the author elements in the "entry" elements of the DFRN protocol + * + * @param object $doc XML document + * @param string $element Element name for the author + * @param string $contact_url Link of the contact + * @param array $items Item elements + * + * @return object XML author object + */ + private function add_entry_author($doc, $element, $contact_url, $item) { - if (trim($profile["dob"]) != "0000-00-00") - xml_add_element($doc, $author, "poco:birthday", "0000-".date("m-d", strtotime($profile["dob"]))); + $contact = get_contact_details_by_url($contact_url, $item["uid"]); - xml_add_element($doc, $author, "poco:note", $profile["about"]); - xml_add_element($doc, $author, "poco:preferredUsername", $profile["nickname"]); + $author = $doc->createElement($element); + xml_add_element($doc, $author, "name", $contact["name"]); + xml_add_element($doc, $author, "uri", $contact["url"]); - $savetz = date_default_timezone_get(); - date_default_timezone_set($profile["timezone"]); - xml_add_element($doc, $author, "poco:utcOffset", date("P")); - date_default_timezone_set($savetz); + /// @Todo + /// - Check real image type and image size + /// - Check which of these boths elements we should use + $attributes = array( + "rel" => "photo", + "type" => "image/jpeg", + "media:width" => 80, + "media:height" => 80, + "href" => $contact["photo"]); + xml_add_element($doc, $author, "link", "", $attributes); - 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); + $attributes = array( + "rel" => "avatar", + "type" => "image/jpeg", + "media:width" => 80, + "media:height" => 80, + "href" => $contact["photo"]); + xml_add_element($doc, $author, "link", "", $attributes); + + return $author; + } + + /** + * @brief Adds the activity elements + * + * @param object $doc XML document + * @param string $element Element name for the activity + * @param string $activity activity value + * + * @return object XML activity object + */ + private function create_activity($doc, $element, $activity) { + + if($activity) { + $entry = $doc->createElement($element); + + $r = parse_xml_string($activity, false); + if(!$r) + return false; + if($r->type) + xml_add_element($doc, $entry, "activity:object-type", $r->type); + if($r->id) + xml_add_element($doc, $entry, "id", $r->id); + if($r->title) + xml_add_element($doc, $entry, "title", $r->title); + if($r->link) { + if(substr($r->link,0,1) === '<') { + if(strstr($r->link,'&') && (! strstr($r->link,'&'))) + $r->link = str_replace('&','&', $r->link); + + $r->link = preg_replace('/\/','',$r->link); + + $data = parse_xml_string($r->link, false); + foreach ($data->attributes() AS $parameter => $value) + $attributes[$parameter] = $value; + } else + $attributes = array("rel" => "alternate", "type" => "text/html", "href" => $r->link); + + xml_add_element($doc, $entry, "link", "", $attributes); + } + if($r->content) + xml_add_element($doc, $entry, "content", bbcode($r->content), array("type" => "html")); + + return $entry; } - if (trim($profile["pub_keywords"]) != "") { - $keywords = explode(",", $profile["pub_keywords"]); + return false; + } - foreach ($keywords AS $keyword) - xml_add_element($doc, $author, "poco:tags", trim($keyword)); + /** + * @brief Adds the elements for attachments + * + * @param object $doc XML document + * @param object $root XML root + * @param array $item Item element + * + * @return object XML attachment object + */ + private function get_attachment($doc, $root, $item) { + $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]); - /// @todo When we are having the XMPP address in the profile we should propagate it here - $xmpp = ""; - if (trim($xmpp) != "") { - $ims = $doc->createElement("poco:ims"); - xml_add_element($doc, $ims, "poco:type", "xmpp"); - xml_add_element($doc, $ims, "poco:value", $xmpp); - xml_add_element($doc, $ims, "poco:primary", "true"); - $author->appendChild($ims); - } + if(trim($matches[4]) != "") + $attributes["title"] = trim($matches[4]); - if (trim($profile["locality"].$profile["region"].$profile["country-name"]) != "") { - $element = $doc->createElement("poco:address"); - - xml_add_element($doc, $element, "poco:formatted", formatted_location($profile)); - - if (trim($profile["locality"]) != "") - xml_add_element($doc, $element, "poco:locality", $profile["locality"]); - - if (trim($profile["region"]) != "") - xml_add_element($doc, $element, "poco:region", $profile["region"]); - - if (trim($profile["country-name"]) != "") - xml_add_element($doc, $element, "poco:country", $profile["country-name"]); - - $author->appendChild($element); + xml_add_element($doc, $root, "link", "", $attributes); + } + } } } - return $author; -} + /** + * @brief Adds the "entry" elements for the DFRN protocol + * + * @param object $doc XML document + * @param string $type "text" or "html" + * @param array $item Item element + * @param array $owner Owner record + * @param bool $comment Trigger the sending of the "comment" element + * @param int $cid Contact ID of the recipient + * + * @return object XML entry object + */ + private function entry($doc, $type, $item, $owner, $comment = false, $cid = 0) { -/** - * @brief Adds the author elements in the "entry" elements of the DFRN protocol - * - * @param object $doc XML document - * @param string $element Element name for the author - * @param string $contact_url Link of the contact - * @param array $items Item elements - * - * @return object XML author object - */ -function dfrn_add_entry_author($doc, $element, $contact_url, $item) { + $mentioned = array(); - $contact = get_contact_details_by_url($contact_url, $item["uid"]); + if(!$item['parent']) + return; - $author = $doc->createElement($element); - xml_add_element($doc, $author, "name", $contact["name"]); - xml_add_element($doc, $author, "uri", $contact["url"]); - - /// @Todo - /// - Check real image type and image size - /// - Check which of these boths elements we should use - $attributes = array( - "rel" => "photo", - "type" => "image/jpeg", - "media:width" => 80, - "media:height" => 80, - "href" => $contact["photo"]); - xml_add_element($doc, $author, "link", "", $attributes); - - $attributes = array( - "rel" => "avatar", - "type" => "image/jpeg", - "media:width" => 80, - "media:height" => 80, - "href" => $contact["photo"]); - xml_add_element($doc, $author, "link", "", $attributes); - - return $author; -} - -/** - * @brief Adds the activity elements - * - * @param object $doc XML document - * @param string $element Element name for the activity - * @param string $activity activity value - * - * @return object XML activity object - */ -function dfrn_create_activity($doc, $element, $activity) { - - if($activity) { - $entry = $doc->createElement($element); - - $r = parse_xml_string($activity, false); - if(!$r) - return false; - if($r->type) - xml_add_element($doc, $entry, "activity:object-type", $r->type); - if($r->id) - xml_add_element($doc, $entry, "id", $r->id); - if($r->title) - xml_add_element($doc, $entry, "title", $r->title); - if($r->link) { - if(substr($r->link,0,1) === '<') { - if(strstr($r->link,'&') && (! strstr($r->link,'&'))) - $r->link = str_replace('&','&', $r->link); - - $r->link = preg_replace('/\/','',$r->link); - - $data = parse_xml_string($r->link, false); - foreach ($data->attributes() AS $parameter => $value) - $attributes[$parameter] = $value; - } else - $attributes = array("rel" => "alternate", "type" => "text/html", "href" => $r->link); - - xml_add_element($doc, $entry, "link", "", $attributes); + if($item['deleted']) { + $attributes = array("ref" => $item['uri'], "when" => datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)); + return xml_create_element($doc, "at:deleted-entry", "", $attributes); } - if($r->content) - xml_add_element($doc, $entry, "content", bbcode($r->content), array("type" => "html")); + + $entry = $doc->createElement("entry"); + + if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid']) + $body = fix_private_photos($item['body'],$owner['uid'],$item,$cid); + else + $body = $item['body']; + + if ($type == 'html') { + $htmlbody = $body; + + if ($item['title'] != "") + $htmlbody = "[b]".$item['title']."[/b]\n\n".$htmlbody; + + $htmlbody = bbcode($htmlbody, false, false, 7); + } + + $author = self::add_entry_author($doc, "author", $item["author-link"], $item); + $entry->appendChild($author); + + $dfrnowner = self::add_entry_author($doc, "dfrn:owner", $item["owner-link"], $item); + $entry->appendChild($dfrnowner); + + if(($item['parent'] != $item['id']) || ($item['parent-uri'] !== $item['uri']) || (($item['thr-parent'] !== '') && ($item['thr-parent'] !== $item['uri']))) { + $parent = q("SELECT `guid` FROM `item` WHERE `id` = %d", intval($item["parent"])); + $parent_item = (($item['thr-parent']) ? $item['thr-parent'] : $item['parent-uri']); + $attributes = array("ref" => $parent_item, "type" => "text/html", "href" => app::get_baseurl().'/display/'.$parent[0]['guid']); + xml_add_element($doc, $entry, "thr:in-reply-to", "", $attributes); + } + + xml_add_element($doc, $entry, "id", $item["uri"]); + xml_add_element($doc, $entry, "title", $item["title"]); + + xml_add_element($doc, $entry, "published", datetime_convert("UTC","UTC",$item["created"]."+00:00",ATOM_TIME)); + xml_add_element($doc, $entry, "updated", datetime_convert("UTC","UTC",$item["edited"]."+00:00",ATOM_TIME)); + + xml_add_element($doc, $entry, "dfrn:env", base64url_encode($body, true)); + xml_add_element($doc, $entry, "content", (($type === 'html') ? $htmlbody : $body), array("type" => $type)); + + xml_add_element($doc, $entry, "link", "", array("rel" => "alternate", "type" => "text/html", + "href" => app::get_baseurl()."/display/".$item["guid"])); + + // "comment-allow" is some old fashioned stuff for old Friendica versions. + // It is included in the rewritten code for completeness + if ($comment) + xml_add_element($doc, $entry, "dfrn:comment-allow", intval($item['last-child'])); + + if($item['location']) + xml_add_element($doc, $entry, "dfrn:location", $item['location']); + + if($item['coord']) + xml_add_element($doc, $entry, "georss:point", $item['coord']); + + if(($item['private']) || strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])) + xml_add_element($doc, $entry, "dfrn:private", (($item['private']) ? $item['private'] : 1)); + + if($item['extid']) + xml_add_element($doc, $entry, "dfrn:extid", $item['extid']); + + if($item['bookmark']) + xml_add_element($doc, $entry, "dfrn:bookmark", "true"); + + if($item['app']) + xml_add_element($doc, $entry, "statusnet:notice_info", "", array("local_id" => $item['id'], "source" => $item['app'])); + + xml_add_element($doc, $entry, "dfrn:diaspora_guid", $item["guid"]); + + // The signed text contains the content in Markdown, the sender handle and the signatur for the content + // It is needed for relayed comments to Diaspora. + if($item['signed_text']) { + $sign = base64_encode(json_encode(array('signed_text' => $item['signed_text'],'signature' => $item['signature'],'signer' => $item['signer']))); + xml_add_element($doc, $entry, "dfrn:diaspora_signature", $sign); + } + + xml_add_element($doc, $entry, "activity:verb", construct_verb($item)); + + $actobj = self::create_activity($doc, "activity:object", $item['object']); + if ($actobj) + $entry->appendChild($actobj); + + $actarg = self::create_activity($doc, "activity:target", $item['target']); + if ($actarg) + $entry->appendChild($actarg); + + $tags = item_getfeedtags($item); + + if(count($tags)) { + foreach($tags as $t) + if (($type != 'html') OR ($t[0] != "@")) + xml_add_element($doc, $entry, "category", "", array("scheme" => "X-DFRN:".$t[0].":".$t[1], "term" => $t[2])); + } + + if(count($tags)) + foreach($tags as $t) + if ($t[0] == "@") + $mentioned[$t[1]] = $t[1]; + + foreach ($mentioned AS $mention) { + $r = q("SELECT `forum`, `prv` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s'", + intval($owner["uid"]), + dbesc(normalise_link($mention))); + if ($r[0]["forum"] OR $r[0]["prv"]) + xml_add_element($doc, $entry, "link", "", array("rel" => "mentioned", + "ostatus:object-type" => ACTIVITY_OBJ_GROUP, + "href" => $mention)); + else + xml_add_element($doc, $entry, "link", "", array("rel" => "mentioned", + "ostatus:object-type" => ACTIVITY_OBJ_PERSON, + "href" => $mention)); + } + + self::get_attachment($doc, $entry, $item); return $entry; } - return false; -} + /** + * @brief Delivers the atom content to the contacts + * + * @param array $owner Owner record + * @param array $contactr Contact record of the receiver + * @param string $atom Content that will be transmitted + * @param bool $dissolve (to be documented) + * + * @return int Deliver status. -1 means an error. + */ + function deliver($owner,$contact,$atom, $dissolve = false) { -/** - * @brief Adds the elements for attachments - * - * @param object $doc XML document - * @param object $root XML root - * @param array $item Item element - * - * @return object XML attachment object - */ -function dfrn_get_attachment($doc, $root, $item) { - $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]); + $a = get_app(); - if(intval($matches[2])) - $attributes["length"] = intval($matches[2]); + $idtosend = $orig_id = (($contact['dfrn-id']) ? $contact['dfrn-id'] : $contact['issued-id']); - if(trim($matches[4]) != "") - $attributes["title"] = trim($matches[4]); + if($contact['duplex'] && $contact['dfrn-id']) + $idtosend = '0:' . $orig_id; + if($contact['duplex'] && $contact['issued-id']) + $idtosend = '1:' . $orig_id; - xml_add_element($doc, $root, "link", "", $attributes); + + $rino = get_config('system','rino_encrypt'); + $rino = intval($rino); + // use RINO1 if mcrypt isn't installed and RINO2 was selected + if ($rino==2 and !function_exists('mcrypt_create_iv')) $rino=1; + + logger("Local rino version: ". $rino, LOGGER_DEBUG); + + $ssl_val = intval(get_config('system','ssl_policy')); + $ssl_policy = ''; + + switch($ssl_val){ + case SSL_POLICY_FULL: + $ssl_policy = 'full'; + break; + case SSL_POLICY_SELFSIGN: + $ssl_policy = 'self'; + break; + case SSL_POLICY_NONE: + default: + $ssl_policy = 'none'; + break; + } + + $url = $contact['notify'] . '&dfrn_id=' . $idtosend . '&dfrn_version=' . DFRN_PROTOCOL_VERSION . (($rino) ? '&rino='.$rino : ''); + + logger('dfrn_deliver: ' . $url); + + $xml = fetch_url($url); + + $curl_stat = $a->get_curl_code(); + if(! $curl_stat) + return(-1); // timed out + + logger('dfrn_deliver: ' . $xml, LOGGER_DATA); + + if(! $xml) + return 3; + + if(strpos($xml,'status) != 0) || (! strlen($res->challenge)) || (! strlen($res->dfrn_id))) + return (($res->status) ? $res->status : 3); + + $postvars = array(); + $sent_dfrn_id = hex2bin((string) $res->dfrn_id); + $challenge = hex2bin((string) $res->challenge); + $perm = (($res->perm) ? $res->perm : null); + $dfrn_version = (float) (($res->dfrn_version) ? $res->dfrn_version : 2.0); + $rino_remote_version = intval($res->rino); + $page = (($owner['page-flags'] == PAGE_COMMUNITY) ? 1 : 0); + + logger("Remote rino version: ".$rino_remote_version." for ".$contact["url"], LOGGER_DEBUG); + + if($owner['page-flags'] == PAGE_PRVGROUP) + $page = 2; + + $final_dfrn_id = ''; + + if($perm) { + if((($perm == 'rw') && (! intval($contact['writable']))) + || (($perm == 'r') && (intval($contact['writable'])))) { + q("update contact set writable = %d where id = %d", + intval(($perm == 'rw') ? 1 : 0), + intval($contact['id']) + ); + $contact['writable'] = (string) 1 - intval($contact['writable']); } } + + if(($contact['duplex'] && strlen($contact['pubkey'])) + || ($owner['page-flags'] == PAGE_COMMUNITY && strlen($contact['pubkey'])) + || ($contact['rel'] == CONTACT_IS_SHARING && strlen($contact['pubkey']))) { + openssl_public_decrypt($sent_dfrn_id,$final_dfrn_id,$contact['pubkey']); + openssl_public_decrypt($challenge,$postvars['challenge'],$contact['pubkey']); + } else { + openssl_private_decrypt($sent_dfrn_id,$final_dfrn_id,$contact['prvkey']); + openssl_private_decrypt($challenge,$postvars['challenge'],$contact['prvkey']); + } + + $final_dfrn_id = substr($final_dfrn_id, 0, strpos($final_dfrn_id, '.')); + + if(strpos($final_dfrn_id,':') == 1) + $final_dfrn_id = substr($final_dfrn_id,2); + + if($final_dfrn_id != $orig_id) { + logger('dfrn_deliver: wrong dfrn_id.'); + // did not decode properly - cannot trust this site + return 3; + } + + $postvars['dfrn_id'] = $idtosend; + $postvars['dfrn_version'] = DFRN_PROTOCOL_VERSION; + if($dissolve) + $postvars['dissolve'] = '1'; + + + if((($contact['rel']) && ($contact['rel'] != CONTACT_IS_SHARING) && (! $contact['blocked'])) || ($owner['page-flags'] == PAGE_COMMUNITY)) { + $postvars['data'] = $atom; + $postvars['perm'] = 'rw'; + } else { + $postvars['data'] = str_replace('1','0',$atom); + $postvars['perm'] = 'r'; + } + + $postvars['ssl_policy'] = $ssl_policy; + + if($page) + $postvars['page'] = $page; + + + if($rino>0 && $rino_remote_version>0 && (! $dissolve)) { + logger('rino version: '. $rino_remote_version); + + switch($rino_remote_version) { + case 1: + // Deprecated rino version! + $key = substr(random_string(),0,16); + $data = aes_encrypt($postvars['data'],$key); + break; + case 2: + // RINO 2 based on php-encryption + try { + $key = Crypto::createNewRandomKey(); + } catch (CryptoTestFailed $ex) { + logger('Cannot safely create a key'); + return -1; + } catch (CannotPerformOperation $ex) { + logger('Cannot safely create a key'); + return -1; + } + try { + $data = Crypto::encrypt($postvars['data'], $key); + } catch (CryptoTestFailed $ex) { + logger('Cannot safely perform encryption'); + return -1; + } catch (CannotPerformOperation $ex) { + logger('Cannot safely perform encryption'); + return -1; + } + break; + default: + logger("rino: invalid requested verision '$rino_remote_version'"); + return -1; + } + + $postvars['rino'] = $rino_remote_version; + $postvars['data'] = bin2hex($data); + + #logger('rino: sent key = ' . $key, LOGGER_DEBUG); + + + if($dfrn_version >= 2.1) { + if(($contact['duplex'] && strlen($contact['pubkey'])) + || ($owner['page-flags'] == PAGE_COMMUNITY && strlen($contact['pubkey'])) + || ($contact['rel'] == CONTACT_IS_SHARING && strlen($contact['pubkey']))) + + openssl_public_encrypt($key,$postvars['key'],$contact['pubkey']); + else + openssl_private_encrypt($key,$postvars['key'],$contact['prvkey']); + + } else { + if(($contact['duplex'] && strlen($contact['prvkey'])) || ($owner['page-flags'] == PAGE_COMMUNITY)) + openssl_private_encrypt($key,$postvars['key'],$contact['prvkey']); + else + openssl_public_encrypt($key,$postvars['key'],$contact['pubkey']); + + } + + logger('md5 rawkey ' . md5($postvars['key'])); + + $postvars['key'] = bin2hex($postvars['key']); + } + + + logger('dfrn_deliver: ' . "SENDING: " . print_r($postvars,true), LOGGER_DATA); + + $xml = post_url($contact['notify'],$postvars); + + logger('dfrn_deliver: ' . "RECEIVED: " . $xml, LOGGER_DATA); + + $curl_stat = $a->get_curl_code(); + if((! $curl_stat) || (! strlen($xml))) + return(-1); // timed out + + if(($curl_stat == 503) && (stristr($a->get_curl_headers(),'retry-after'))) + return(-1); + + if(strpos($xml,'status; } } - -/** - * @brief Adds the "entry" elements for the DFRN protocol - * - * @param object $doc XML document - * @param string $type "text" or "html" - * @param array $item Item element - * @param array $owner Owner record - * @param bool $comment Trigger the sending of the "comment" element - * @param int $cid Contact ID of the recipient - * - * @return object XML entry object - */ -function dfrn_entry($doc, $type, $item, $owner, $comment = false, $cid = 0) { - $a = get_app(); - - $mentioned = array(); - - if(!$item['parent']) - return; - - if($item['deleted']) { - $attributes = array("ref" => $item['uri'], "when" => datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)); - return xml_create_element($doc, "at:deleted-entry", "", $attributes); - } - - $entry = $doc->createElement("entry"); - - if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid']) - $body = fix_private_photos($item['body'],$owner['uid'],$item,$cid); - else - $body = $item['body']; - - if ($type == 'html') { - $htmlbody = $body; - - if ($item['title'] != "") - $htmlbody = "[b]".$item['title']."[/b]\n\n".$htmlbody; - - $htmlbody = bbcode($htmlbody, false, false, 7); - } - - $author = dfrn_add_entry_author($doc, "author", $item["author-link"], $item); - $entry->appendChild($author); - - $dfrnowner = dfrn_add_entry_author($doc, "dfrn:owner", $item["owner-link"], $item); - $entry->appendChild($dfrnowner); - - if(($item['parent'] != $item['id']) || ($item['parent-uri'] !== $item['uri']) || (($item['thr-parent'] !== '') && ($item['thr-parent'] !== $item['uri']))) { - $parent = q("SELECT `guid` FROM `item` WHERE `id` = %d", intval($item["parent"])); - $parent_item = (($item['thr-parent']) ? $item['thr-parent'] : $item['parent-uri']); - $attributes = array("ref" => $parent_item, "type" => "text/html", "href" => $a->get_baseurl().'/display/'.$parent[0]['guid']); - xml_add_element($doc, $entry, "thr:in-reply-to", "", $attributes); - } - - xml_add_element($doc, $entry, "id", $item["uri"]); - xml_add_element($doc, $entry, "title", $item["title"]); - - xml_add_element($doc, $entry, "published", datetime_convert("UTC","UTC",$item["created"]."+00:00",ATOM_TIME)); - xml_add_element($doc, $entry, "updated", datetime_convert("UTC","UTC",$item["edited"]."+00:00",ATOM_TIME)); - - xml_add_element($doc, $entry, "dfrn:env", base64url_encode($body, true)); - xml_add_element($doc, $entry, "content", (($type === 'html') ? $htmlbody : $body), array("type" => $type)); - - xml_add_element($doc, $entry, "link", "", array("rel" => "alternate", "type" => "text/html", - "href" => $a->get_baseurl()."/display/".$item["guid"])); - - // "comment-allow" is some old fashioned stuff for old Friendica versions. - // It is included in the rewritten code for completeness - if ($comment) - xml_add_element($doc, $entry, "dfrn:comment-allow", intval($item['last-child'])); - - if($item['location']) - xml_add_element($doc, $entry, "dfrn:location", $item['location']); - - if($item['coord']) - xml_add_element($doc, $entry, "georss:point", $item['coord']); - - if(($item['private']) || strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])) - xml_add_element($doc, $entry, "dfrn:private", (($item['private']) ? $item['private'] : 1)); - - if($item['extid']) - xml_add_element($doc, $entry, "dfrn:extid", $item['extid']); - - if($item['bookmark']) - xml_add_element($doc, $entry, "dfrn:bookmark", "true"); - - if($item['app']) - xml_add_element($doc, $entry, "statusnet:notice_info", "", array("local_id" => $item['id'], "source" => $item['app'])); - - xml_add_element($doc, $entry, "dfrn:diaspora_guid", $item["guid"]); - - // The signed text contains the content in Markdown, the sender handle and the signatur for the content - // It is needed for relayed comments to Diaspora. - if($item['signed_text']) { - $sign = base64_encode(json_encode(array('signed_text' => $item['signed_text'],'signature' => $item['signature'],'signer' => $item['signer']))); - xml_add_element($doc, $entry, "dfrn:diaspora_signature", $sign); - } - - xml_add_element($doc, $entry, "activity:verb", construct_verb($item)); - - $actobj = dfrn_create_activity($doc, "activity:object", $item['object']); - if ($actobj) - $entry->appendChild($actobj); - - $actarg = dfrn_create_activity($doc, "activity:target", $item['target']); - if ($actarg) - $entry->appendChild($actarg); - - $tags = item_getfeedtags($item); - - if(count($tags)) { - foreach($tags as $t) - if (($type != 'html') OR ($t[0] != "@")) - xml_add_element($doc, $entry, "category", "", array("scheme" => "X-DFRN:".$t[0].":".$t[1], "term" => $t[2])); - } - - if(count($tags)) - foreach($tags as $t) - if ($t[0] == "@") - $mentioned[$t[1]] = $t[1]; - - foreach ($mentioned AS $mention) { - $r = q("SELECT `forum`, `prv` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s'", - intval($owner["uid"]), - dbesc(normalise_link($mention))); - if ($r[0]["forum"] OR $r[0]["prv"]) - xml_add_element($doc, $entry, "link", "", array("rel" => "mentioned", - "ostatus:object-type" => ACTIVITY_OBJ_GROUP, - "href" => $mention)); - else - xml_add_element($doc, $entry, "link", "", array("rel" => "mentioned", - "ostatus:object-type" => ACTIVITY_OBJ_PERSON, - "href" => $mention)); - } - - dfrn_get_attachment($doc, $entry, $item); - - return $entry; -} diff --git a/include/items.php b/include/items.php index 6d3cd2b7c..cf044d883 100644 --- a/include/items.php +++ b/include/items.php @@ -1696,245 +1696,9 @@ function tgroup_check($uid,$item) { if((! $community_page) && (! $prvgroup)) return false; - - return true; - } - - - - - -function dfrn_deliver($owner,$contact,$atom, $dissolve = false) { - - $a = get_app(); - - $idtosend = $orig_id = (($contact['dfrn-id']) ? $contact['dfrn-id'] : $contact['issued-id']); - - if($contact['duplex'] && $contact['dfrn-id']) - $idtosend = '0:' . $orig_id; - if($contact['duplex'] && $contact['issued-id']) - $idtosend = '1:' . $orig_id; - - - $rino = get_config('system','rino_encrypt'); - $rino = intval($rino); - // use RINO1 if mcrypt isn't installed and RINO2 was selected - if ($rino==2 and !function_exists('mcrypt_create_iv')) $rino=1; - - logger("Local rino version: ". $rino, LOGGER_DEBUG); - - $ssl_val = intval(get_config('system','ssl_policy')); - $ssl_policy = ''; - - switch($ssl_val){ - case SSL_POLICY_FULL: - $ssl_policy = 'full'; - break; - case SSL_POLICY_SELFSIGN: - $ssl_policy = 'self'; - break; - case SSL_POLICY_NONE: - default: - $ssl_policy = 'none'; - break; - } - - $url = $contact['notify'] . '&dfrn_id=' . $idtosend . '&dfrn_version=' . DFRN_PROTOCOL_VERSION . (($rino) ? '&rino='.$rino : ''); - - logger('dfrn_deliver: ' . $url); - - $xml = fetch_url($url); - - $curl_stat = $a->get_curl_code(); - if(! $curl_stat) - return(-1); // timed out - - logger('dfrn_deliver: ' . $xml, LOGGER_DATA); - - if(! $xml) - return 3; - - if(strpos($xml,'status) != 0) || (! strlen($res->challenge)) || (! strlen($res->dfrn_id))) - return (($res->status) ? $res->status : 3); - - $postvars = array(); - $sent_dfrn_id = hex2bin((string) $res->dfrn_id); - $challenge = hex2bin((string) $res->challenge); - $perm = (($res->perm) ? $res->perm : null); - $dfrn_version = (float) (($res->dfrn_version) ? $res->dfrn_version : 2.0); - $rino_remote_version = intval($res->rino); - $page = (($owner['page-flags'] == PAGE_COMMUNITY) ? 1 : 0); - - logger("Remote rino version: ".$rino_remote_version." for ".$contact["url"], LOGGER_DEBUG); - - if($owner['page-flags'] == PAGE_PRVGROUP) - $page = 2; - - $final_dfrn_id = ''; - - if($perm) { - if((($perm == 'rw') && (! intval($contact['writable']))) - || (($perm == 'r') && (intval($contact['writable'])))) { - q("update contact set writable = %d where id = %d", - intval(($perm == 'rw') ? 1 : 0), - intval($contact['id']) - ); - $contact['writable'] = (string) 1 - intval($contact['writable']); - } - } - - if(($contact['duplex'] && strlen($contact['pubkey'])) - || ($owner['page-flags'] == PAGE_COMMUNITY && strlen($contact['pubkey'])) - || ($contact['rel'] == CONTACT_IS_SHARING && strlen($contact['pubkey']))) { - openssl_public_decrypt($sent_dfrn_id,$final_dfrn_id,$contact['pubkey']); - openssl_public_decrypt($challenge,$postvars['challenge'],$contact['pubkey']); - } - else { - openssl_private_decrypt($sent_dfrn_id,$final_dfrn_id,$contact['prvkey']); - openssl_private_decrypt($challenge,$postvars['challenge'],$contact['prvkey']); - } - - $final_dfrn_id = substr($final_dfrn_id, 0, strpos($final_dfrn_id, '.')); - - if(strpos($final_dfrn_id,':') == 1) - $final_dfrn_id = substr($final_dfrn_id,2); - - if($final_dfrn_id != $orig_id) { - logger('dfrn_deliver: wrong dfrn_id.'); - // did not decode properly - cannot trust this site - return 3; - } - - $postvars['dfrn_id'] = $idtosend; - $postvars['dfrn_version'] = DFRN_PROTOCOL_VERSION; - if($dissolve) - $postvars['dissolve'] = '1'; - - - if((($contact['rel']) && ($contact['rel'] != CONTACT_IS_SHARING) && (! $contact['blocked'])) || ($owner['page-flags'] == PAGE_COMMUNITY)) { - $postvars['data'] = $atom; - $postvars['perm'] = 'rw'; - } - else { - $postvars['data'] = str_replace('1','0',$atom); - $postvars['perm'] = 'r'; - } - - $postvars['ssl_policy'] = $ssl_policy; - - if($page) - $postvars['page'] = $page; - - - if($rino>0 && $rino_remote_version>0 && (! $dissolve)) { - logger('rino version: '. $rino_remote_version); - - switch($rino_remote_version) { - case 1: - // Deprecated rino version! - $key = substr(random_string(),0,16); - $data = aes_encrypt($postvars['data'],$key); - break; - case 2: - // RINO 2 based on php-encryption - try { - $key = Crypto::createNewRandomKey(); - } catch (CryptoTestFailed $ex) { - logger('Cannot safely create a key'); - return -1; - } catch (CannotPerformOperation $ex) { - logger('Cannot safely create a key'); - return -1; - } - try { - $data = Crypto::encrypt($postvars['data'], $key); - } catch (CryptoTestFailed $ex) { - logger('Cannot safely perform encryption'); - return -1; - } catch (CannotPerformOperation $ex) { - logger('Cannot safely perform encryption'); - return -1; - } - break; - default: - logger("rino: invalid requested verision '$rino_remote_version'"); - return -1; - } - - $postvars['rino'] = $rino_remote_version; - $postvars['data'] = bin2hex($data); - - #logger('rino: sent key = ' . $key, LOGGER_DEBUG); - - - if($dfrn_version >= 2.1) { - if(($contact['duplex'] && strlen($contact['pubkey'])) - || ($owner['page-flags'] == PAGE_COMMUNITY && strlen($contact['pubkey'])) - || ($contact['rel'] == CONTACT_IS_SHARING && strlen($contact['pubkey']))) { - - openssl_public_encrypt($key,$postvars['key'],$contact['pubkey']); - } - else { - openssl_private_encrypt($key,$postvars['key'],$contact['prvkey']); - } - } - else { - if(($contact['duplex'] && strlen($contact['prvkey'])) || ($owner['page-flags'] == PAGE_COMMUNITY)) { - openssl_private_encrypt($key,$postvars['key'],$contact['prvkey']); - } - else { - openssl_public_encrypt($key,$postvars['key'],$contact['pubkey']); - } - } - - logger('md5 rawkey ' . md5($postvars['key'])); - - $postvars['key'] = bin2hex($postvars['key']); - } - - - logger('dfrn_deliver: ' . "SENDING: " . print_r($postvars,true), LOGGER_DATA); - - $xml = post_url($contact['notify'],$postvars); - - logger('dfrn_deliver: ' . "RECEIVED: " . $xml, LOGGER_DATA); - - $curl_stat = $a->get_curl_code(); - if((! $curl_stat) || (! strlen($xml))) - return(-1); // timed out - - if(($curl_stat == 503) && (stristr($a->get_curl_headers(),'retry-after'))) - return(-1); - - if(strpos($xml,'status; -} - - /* This function returns true if $update has an edited timestamp newer than $existing, i.e. $update contains new data which should override diff --git a/include/queue.php b/include/queue.php index f40768f0d..1525ca3ab 100644 --- a/include/queue.php +++ b/include/queue.php @@ -1,6 +1,7 @@ '); - $deliver_status = dfrn_deliver($owner,$contact,$data); + $deliver_status = dfrn::deliver($owner,$contact,$data); if($deliver_status == (-1)) { update_queue_time($q_item['id']); diff --git a/mod/dfrn_poll.php b/mod/dfrn_poll.php index 658a248c6..ab6637607 100644 --- a/mod/dfrn_poll.php +++ b/mod/dfrn_poll.php @@ -44,7 +44,7 @@ function dfrn_poll_init(&$a) { logger('dfrn_poll: public feed request from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . $user); header("Content-type: application/atom+xml"); - echo dfrn_feed($a, '', $user,$last_update); + echo dfrn::feed('', $user,$last_update); killme(); } @@ -371,7 +371,7 @@ function dfrn_poll_post(&$a) { } header("Content-type: application/atom+xml"); - $o = dfrn_feed($a,$dfrn_id, $a->argv[1], $last_update, $direction); + $o = dfrn::feed($dfrn_id, $a->argv[1], $last_update, $direction); echo $o; killme(); From 778d9250c699962a1f9907322756b81d24032fa3 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Mon, 25 Jan 2016 22:10:26 +0100 Subject: [PATCH 16/18] Still some more documentation --- include/dfrn.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/dfrn.php b/include/dfrn.php index 885e03a91..ee29e7347 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -1,8 +1,19 @@ Date: Tue, 26 Jan 2016 12:18:57 +0100 Subject: [PATCH 17/18] Some new fields for the protocol --- include/dfrn.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/dfrn.php b/include/dfrn.php index ee29e7347..ac67bf097 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -456,6 +456,9 @@ class dfrn { $attributes = array("dfrn:updated" => $namdate); xml_add_element($doc, $author, "uri", app::get_baseurl().'/profile/'.$owner["nickname"], $attributes); + $attributes = array("dfrn:updated" => $namdate); + xml_add_element($doc, $author, "dfrn:handle", $owner["addr"], $attributes); + $attributes = array("rel" => "photo", "type" => "image/jpeg", "dfrn:updated" => $picdate, "media:width" => 175, "media:height" => 175, "href" => $owner['photo']); xml_add_element($doc, $author, "link", "", $attributes); @@ -560,6 +563,7 @@ class dfrn { $author = $doc->createElement($element); xml_add_element($doc, $author, "name", $contact["name"]); xml_add_element($doc, $author, "uri", $contact["url"]); + xml_add_element($doc, $author, "dfrn:handle", $contact["addr"]); /// @Todo /// - Check real image type and image size @@ -711,7 +715,9 @@ class dfrn { if(($item['parent'] != $item['id']) || ($item['parent-uri'] !== $item['uri']) || (($item['thr-parent'] !== '') && ($item['thr-parent'] !== $item['uri']))) { $parent = q("SELECT `guid` FROM `item` WHERE `id` = %d", intval($item["parent"])); $parent_item = (($item['thr-parent']) ? $item['thr-parent'] : $item['parent-uri']); - $attributes = array("ref" => $parent_item, "type" => "text/html", "href" => app::get_baseurl().'/display/'.$parent[0]['guid']); + $attributes = array("ref" => $parent_item, "type" => "text/html", + "href" => app::get_baseurl().'/display/'.$parent[0]['guid'], + "dfrn:diaspora_guid" => $parent[0]['guid']); xml_add_element($doc, $entry, "thr:in-reply-to", "", $attributes); } From 45a5f63d35e7460e8de194ee778fba6d500deb77 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Wed, 27 Jan 2016 02:38:52 +0100 Subject: [PATCH 18/18] The object-type is now transmitted as well --- include/dfrn.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/dfrn.php b/include/dfrn.php index ac67bf097..2c8e8ce38 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -767,6 +767,13 @@ class dfrn { xml_add_element($doc, $entry, "activity:verb", construct_verb($item)); + if ($item['object-type'] != "") + xml_add_element($doc, $entry, "activity:object-type", $item['object-type']); + elseif ($item['id'] == $item['parent']) + xml_add_element($doc, $entry, "activity:object-type", ACTIVITY_OBJ_NOTE); + else + xml_add_element($doc, $entry, "activity:object-type", ACTIVITY_OBJ_COMMENT); + $actobj = self::create_activity($doc, "activity:object", $item['object']); if ($actobj) $entry->appendChild($actobj);