X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=include%2Fdfrn.php;h=40149eec2b7dc78bb27896a223bfe456ba37de41;hb=c105a67cd9cb0669c492cb20d1153fac1c001b56;hp=c2b599ce249ec12cb01b7a3d76f3f47b04411e1d;hpb=32a8a28b2c28642059be7b9770002882946c5470;p=friendica.git diff --git a/include/dfrn.php b/include/dfrn.php index c2b599ce24..40149eec2b 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -8,6 +8,7 @@ */ use Friendica\App; +use Friendica\Core\System; require_once("include/Contact.php"); require_once("include/ostatus.php"); @@ -288,10 +289,17 @@ class dfrn { * @brief Generate an atom entry for a given item id * * @param int $item_id The item id + * @param boolean $conversation Show the conversation. If false show the single post. * * @return string DFRN feed entry */ - public static function itemFeed($item_id) { + public static function itemFeed($item_id, $conversation = false) { + if ($conversation) { + $condition = '`item`.`parent`'; + } else { + $condition = '`item`.`id`'; + } + $r = q("SELECT `item`.*, `item`.`id` AS `item_id`, `contact`.`name`, `contact`.`network`, `contact`.`photo`, `contact`.`url`, `contact`.`name-date`, `contact`.`uri-date`, `contact`.`avatar-date`, @@ -301,8 +309,9 @@ class dfrn { STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND (NOT `contact`.`blocked` OR `contact`.`pending`) LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` - WHERE `item`.`id` = %d AND `item`.`visible` AND NOT `item`.`moderated` AND `item`.`parent` != 0 - AND `item`.`wall` AND NOT `item`.`private`", + WHERE %s = %d AND `item`.`visible` AND NOT `item`.`moderated` AND `item`.`parent` != 0 + AND NOT `item`.`private`", + $condition, intval($item_id) ); @@ -310,6 +319,7 @@ class dfrn { killme(); } + $items = $r; $item = $r[0]; $r = q("SELECT `contact`.*, `user`.`nickname`, `user`.`timezone`, `user`.`page-flags`, `user`.`account-type` @@ -326,15 +336,31 @@ class dfrn { $doc = new DOMDocument('1.0', 'utf-8'); $doc->formatOutput = true; + $type = 'html'; - $alternatelink = $owner['url']; + if ($conversation) { + $root = $doc->createElementNS(NAMESPACE_ATOM1, 'feed'); + $doc->appendChild($root); - $root = self::add_header($doc, $owner, 'dfrn:owner', $alternatelink, true); + $root->setAttribute("xmlns:thr", NAMESPACE_THREAD); + $root->setAttribute("xmlns:at", NAMESPACE_TOMB); + $root->setAttribute("xmlns:media", NAMESPACE_MEDIA); + $root->setAttribute("xmlns:dfrn", NAMESPACE_DFRN); + $root->setAttribute("xmlns:activity", NAMESPACE_ACTIVITY); + $root->setAttribute("xmlns:georss", NAMESPACE_GEORSS); + $root->setAttribute("xmlns:poco", NAMESPACE_POCO); + $root->setAttribute("xmlns:ostatus", NAMESPACE_OSTATUS); + $root->setAttribute("xmlns:statusnet", NAMESPACE_STATUSNET); - $type = 'html'; + //$root = self::add_header($doc, $owner, "dfrn:owner", "", false); - $entry = self::entry($doc, $type, $item, $owner, true); - $root->appendChild($entry); + foreach ($items as $item) { + $entry = self::entry($doc, $type, $item, $owner, true, 0); + $root->appendChild($entry); + } + } else { + $root = self::entry($doc, $type, $item, $owner, true, 0, true); + } $atom = trim($doc->saveXML()); return $atom; @@ -428,7 +454,7 @@ class dfrn { $ext = Photo::supportedTypes(); foreach ($rp as $p) { - $photos[$p['scale']] = App::get_baseurl().'/photo/'.$p['resource-id'].'-'.$p['scale'].'.'.$ext[$p['type']]; + $photos[$p['scale']] = System::baseUrl().'/photo/'.$p['resource-id'].'-'.$p['scale'].'.'.$ext[$p['type']]; } unset($rp, $ext); @@ -489,7 +515,7 @@ class dfrn { $root->setAttribute("xmlns:ostatus", NAMESPACE_OSTATUS); $root->setAttribute("xmlns:statusnet", NAMESPACE_STATUSNET); - xml::add_element($doc, $root, "id", App::get_baseurl()."/profile/".$owner["nick"]); + xml::add_element($doc, $root, "id", System::baseUrl()."/profile/".$owner["nick"]); xml::add_element($doc, $root, "title", $owner["name"]); $attributes = array("uri" => "https://friendi.ca", "version" => FRIENDICA_VERSION."-".DB_UPDATE_VERSION); @@ -506,13 +532,13 @@ class dfrn { // DFRN itself doesn't uses this. But maybe someone else wants to subscribe to the public feed. ostatus::hublinks($doc, $root, $owner["nick"]); - $attributes = array("rel" => "salmon", "href" => App::get_baseurl()."/salmon/".$owner["nick"]); + $attributes = array("rel" => "salmon", "href" => System::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"]); + $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-replies", "href" => System::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"]); + $attributes = array("rel" => "http://salmon-protocol.org/ns/salmon-mention", "href" => System::baseUrl()."/salmon/".$owner["nick"]); xml::add_element($doc, $root, "link", "", $attributes); } @@ -569,7 +595,7 @@ class dfrn { } xml::add_element($doc, $author, "name", $owner["name"], $attributes); - xml::add_element($doc, $author, "uri", App::get_baseurl().'/profile/'.$owner["nickname"], $attributes); + xml::add_element($doc, $author, "uri", System::baseUrl().'/profile/'.$owner["nickname"], $attributes); xml::add_element($doc, $author, "dfrn:handle", $owner["addr"], $attributes); $attributes = array("rel" => "photo", "type" => "image/jpeg", @@ -822,11 +848,12 @@ class dfrn { * @param array $owner Owner record * @param bool $comment Trigger the sending of the "comment" element * @param int $cid Contact ID of the recipient + * @param bool $single If set, the entry is created as an XML document with a single "entry" element * * @return object XML entry object * @todo Add type-hints */ - private static function entry($doc, $type, $item, $owner, $comment = false, $cid = 0) { + private static function entry($doc, $type, $item, $owner, $comment = false, $cid = 0, $single = false) { $mentioned = array(); @@ -839,7 +866,22 @@ class dfrn { return xml::create_element($doc, "at:deleted-entry", "", $attributes); } - $entry = $doc->createElement("entry"); + if (!$single) { + $entry = $doc->createElement("entry"); + } else { + $entry = $doc->createElementNS(NAMESPACE_ATOM1, 'entry'); + $doc->appendChild($entry); + + $entry->setAttribute("xmlns:thr", NAMESPACE_THREAD); + $entry->setAttribute("xmlns:at", NAMESPACE_TOMB); + $entry->setAttribute("xmlns:media", NAMESPACE_MEDIA); + $entry->setAttribute("xmlns:dfrn", NAMESPACE_DFRN); + $entry->setAttribute("xmlns:activity", NAMESPACE_ACTIVITY); + $entry->setAttribute("xmlns:georss", NAMESPACE_GEORSS); + $entry->setAttribute("xmlns:poco", NAMESPACE_POCO); + $entry->setAttribute("xmlns:ostatus", NAMESPACE_OSTATUS); + $entry->setAttribute("xmlns:statusnet", NAMESPACE_STATUSNET); + } if ($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid']) { $body = fix_private_photos($item['body'],$owner['uid'],$item,$cid); @@ -867,16 +909,16 @@ class dfrn { $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']); + $parent = q("SELECT `guid`,`plink` FROM `item` WHERE `uri` = '%s' AND `uid` = %d", dbesc($parent_item), intval($item['uid'])); $attributes = array("ref" => $parent_item, "type" => "text/html", - "href" => App::get_baseurl().'/display/'.$parent[0]['guid'], + "href" => $parent[0]['plink'], "dfrn:diaspora_guid" => $parent[0]['guid']); xml::add_element($doc, $entry, "thr:in-reply-to", "", $attributes); } // Add conversation data. This is used for OStatus - $conversation_href = App::get_baseurl()."/display/".$owner["nick"]."/".$item["parent"]; + $conversation_href = System::baseUrl()."/display/".$owner["nick"]."/".$item["parent"]; $conversation_uri = $conversation_href; if (isset($parent_item)) { @@ -912,7 +954,7 @@ class dfrn { // We save this value in "plink". Maybe we should read it from there as well? xml::add_element($doc, $entry, "link", "", array("rel" => "alternate", "type" => "text/html", - "href" => App::get_baseurl()."/display/".$item["guid"])); + "href" => System::baseUrl()."/display/".$item["guid"])); // "comment-allow" is some old fashioned stuff for old Friendica versions. // It is included in the rewritten code for completeness @@ -1655,9 +1697,7 @@ class dfrn { $msg["seen"] = 0; $msg["replied"] = 0; - dbm::esc_array($msg, true); - - $r = dbq("INSERT INTO `mail` (`".implode("`, `", array_keys($msg))."`) VALUES (".implode(", ", array_values($msg)).")"); + dba::insert('mail', $msg); // send notifications. /// @TODO Arange this mess @@ -1797,7 +1837,7 @@ class dfrn { "to_email" => $importer["email"], "uid" => $importer["importer_uid"], "item" => $suggest, - "link" => App::get_baseurl()."/notifications/intros", + "link" => System::baseUrl()."/notifications/intros", "source_name" => $importer["name"], "source_link" => $importer["url"], "source_photo" => $importer["photo"], @@ -1947,6 +1987,81 @@ class dfrn { return true; } + /** + * @brief Check and possibly rewrite a post if it was a dedicated forum post + * + * @param array $item the new item record + * + * @return boolean Was the post be rewritten? + */ + private static function rewriteDedicatedForumPost($item) { + $fields = array('author-link', 'allow_cid', 'contact-id', 'private', 'wall', 'id', 'parent'); + $condition = array('uri' => $item['uri'], 'uid' => $item['uid']); + $existing = dba::select('item', $fields, $condition, array('limit' => 1)); + if (!dbm::is_result($existing)) { + return false; + } + + // Only rewrite if the former post was a private starting post + if (!$existing['wall'] || !$existing['private'] || ($existing['id'] != $existing['parent'])) { + return false; + } + + // Is the post only directed to a single forum? + if ($existing['allow_cid'] != '<'.$item['contact-id'].'>') { + return false; + } + + $fields = array('id'); + $condition = array('uid' => $item['uid'], 'self' => true); + $self = dba::select('contact', $fields, $condition, array('limit' => 1)); + if (!dbm::is_result($self)) { + return false; + } + + // is the original item created by the "self" user. + if ($self['id'] != $existing['contact-id']) { + return false; + } + + $fields = array('forum', 'prv'); + $condition = array('id' => $item['contact-id']); + $contact = dba::select('contact', $fields, $condition, array('limit' => 1)); + if (!dbm::is_result($contact)) { + return false; + } + + // Is the post from a forum? + if (!$contact['forum'] && !$contact['prv']) { + return false; + } + + /// @todo There is an ugly downside of this whole rewrite process: These items loose the ability to be edited by the user. + logger('Item '.$item['uri'].' will be rewritten.', LOGGER_DEBUG); + + $item = store_conversation($item); + unset($fields['dsprsig']); + + // Rewrite to a public post if it comes from a public forum + if ($contact['forum']) { + $item['allow_cid'] = ''; + $item['allow_gid'] = ''; + $item['deny_cid'] = ''; + $item['deny_gid'] = ''; + $item['private'] = false; + } + + $item['wall'] = false; + + $item["owner-id"] = get_contact($item["owner-link"], 0); + + $condition = array('uri' => $item["uri"], 'uid' => $item["uid"]); + dba::update('item', $item, $condition); + + add_shadow_thread($existing['id']); + return true; + } + /** * @brief Updates an item * @@ -1966,15 +2081,15 @@ class dfrn { return false; } - $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` IN (0, %d)", - dbesc($item["title"]), - dbesc($item["body"]), - dbesc($item["tag"]), - dbesc(datetime_convert("UTC","UTC",$item["edited"])), - dbesc(datetime_convert()), - dbesc($item["uri"]), - intval($importer["importer_uid"]) - ); + if (!self::rewriteDedicatedForumPost($item)) { + $fields = array('title' => $item["title"], 'body' => $item["body"], + 'tag' => $item["tag"], 'changed' => datetime_convert(), + 'edited' => datetime_convert("UTC", "UTC", $item["edited"])); + + $condition = array("`uri` = ? AND `uid` IN (0, ?)", $item["uri"], $importer["importer_uid"]); + dba::update('item', $fields, $condition); + } + create_tags_from_itemuri($item["uri"], $importer["importer_uid"]); update_thread_uri($item["uri"], $importer["importer_uid"]); @@ -2103,7 +2218,7 @@ class dfrn { } } - if ($Blink && link_compare($Blink, App::get_baseurl() . "/profile/" . $importer["nickname"])) { + if ($Blink && link_compare($Blink, System::baseUrl() . "/profile/" . $importer["nickname"])) { // send a notification notification(array( @@ -2114,7 +2229,7 @@ class dfrn { "to_email" => $importer["email"], "uid" => $importer["importer_uid"], "item" => $item, - "link" => App::get_baseurl()."/display/".urlencode(get_item_guid($posted_id)), + "link" => System::baseUrl()."/display/".urlencode(get_item_guid($posted_id)), "source_name" => stripslashes($item["author-name"]), "source_link" => $item["author-link"], "source_photo" => ((link_compare($item["author-link"],$importer["url"])) @@ -2817,13 +2932,6 @@ class dfrn { return 400; } - if ($importer["readonly"]) { - // We aren't receiving stuff from this person. But we will quietly ignore them - // rather than a blatant "go away" message. - logger('ignoring contact '.$importer["id"]); - return 403; - } - $doc = new DOMDocument(); @$doc->loadXML($xml); @@ -2866,11 +2974,7 @@ class dfrn { $accounttype = intval($xpath->evaluate("/atom:feed/dfrn:account_type/text()", $context)->item(0)->nodeValue); if ($accounttype != $importer["contact-type"]) { - /// @TODO this way is the norm or putting ); at the end of the line? - q("UPDATE `contact` SET `contact-type` = %d WHERE `id` = %d", - intval($accounttype), - intval($importer["id"]) - ); + dba::update('contact', array('contact-type' => $accounttype), array('id' => $importer["id"])); } } @@ -2879,10 +2983,21 @@ class dfrn { $forum = intval($xpath->evaluate("/atom:feed/dfrn:community/text()", $context)->item(0)->nodeValue); if ($forum != $importer["forum"]) { - q("UPDATE `contact` SET `forum` = %d WHERE `forum` != %d AND `id` = %d", - intval($forum), intval($forum), - intval($importer["id"]) - ); + $condition = array('`forum` != ? AND `id` = ?', $forum, $importer["id"]); + dba::update('contact', array('forum' => $forum), $condition); + } + + // We are processing relocations even if we are ignoring a contact + $relocations = $xpath->query("/atom:feed/dfrn:relocate"); + foreach ($relocations AS $relocation) { + self::process_relocation($xpath, $relocation, $importer); + } + + if ($importer["readonly"]) { + // We aren't receiving stuff from this person. But we will quietly ignore them + // rather than a blatant "go away" message. + logger('ignoring contact '.$importer["id"]); + return 403; } $mails = $xpath->query("/atom:feed/dfrn:mail"); @@ -2895,11 +3010,6 @@ class dfrn { self::process_suggestion($xpath, $suggestion, $importer); } - $relocations = $xpath->query("/atom:feed/dfrn:relocate"); - foreach ($relocations AS $relocation) { - self::process_relocation($xpath, $relocation, $importer); - } - $deletions = $xpath->query("/atom:feed/at:deleted-entry"); foreach ($deletions AS $deletion) { self::process_deletion($xpath, $deletion, $importer);