]> git.mxchange.org Git - friendica.git/blobdiff - src/Protocol/OStatus.php
Avoid proxyfying images that are removed or replaced later
[friendica.git] / src / Protocol / OStatus.php
index c00c029cd4b722a0f2769eb6d9141f6345f647f2..1019d34cc79f6eb5d84880007099cddfb5728036 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * @copyright Copyright (C) 2020, Friendica
+ * @copyright Copyright (C) 2010-2021, the Friendica project
  *
  * @license GNU AGPL version 3 or any later version
  *
@@ -23,7 +23,6 @@ namespace Friendica\Protocol;
 
 use DOMDocument;
 use DOMXPath;
-use Friendica\Content\PageInfo;
 use Friendica\Content\Text\BBCode;
 use Friendica\Content\Text\HTML;
 use Friendica\Core\Cache\Duration;
@@ -36,6 +35,7 @@ use Friendica\Model\Contact;
 use Friendica\Model\Conversation;
 use Friendica\Model\Item;
 use Friendica\Model\ItemURI;
+use Friendica\Model\Post;
 use Friendica\Model\Tag;
 use Friendica\Model\User;
 use Friendica\Network\Probe;
@@ -45,9 +45,6 @@ use Friendica\Util\Proxy as ProxyUtils;
 use Friendica\Util\Strings;
 use Friendica\Util\XML;
 
-require_once 'mod/share.php';
-require_once 'include/api.php';
-
 /**
  * This class contain functions for the OStatus protocol
  */
@@ -219,7 +216,7 @@ class OStatus
                        }
 
                        // Ensure that we are having this contact (with uid=0)
-                       $cid = Contact::getIdForURL($aliaslink, 0, false);
+                       $cid = Contact::getIdForURL($aliaslink);
 
                        if ($cid) {
                                $fields = ['url', 'nurl', 'name', 'nick', 'alias', 'about', 'location'];
@@ -314,7 +311,7 @@ class OStatus
         */
        public static function import($xml, array $importer, array &$contact, &$hub)
        {
-               self::process($xml, $importer, $contact, $hub);
+               self::process($xml, $importer, $contact, $hub, false, true, Conversation::PUSH);
        }
 
        /**
@@ -331,7 +328,7 @@ class OStatus
         * @throws \Friendica\Network\HTTPException\InternalServerErrorException
         * @throws \ImagickException
         */
-       private static function process($xml, array $importer, array &$contact = null, &$hub, $stored = false, $initialize = true)
+       private static function process($xml, array $importer, array &$contact = null, &$hub, $stored = false, $initialize = true, $direction = Conversation::UNKNOWN)
        {
                if ($initialize) {
                        self::$itemlist = [];
@@ -399,6 +396,7 @@ class OStatus
 
                        $header["protocol"] = Conversation::PARCEL_SALMON;
                        $header["source"] = $xml2;
+                       $header["direction"] = $direction;
                } elseif (!$initialize) {
                        return false;
                }
@@ -446,7 +444,7 @@ class OStatus
                        }
 
                        // Deletions come with the same uri, so we check for duplicates after processing deletions
-                       if (Item::exists(['uid' => $importer["uid"], 'uri' => $item["uri"]])) {
+                       if (Post::exists(['uid' => $importer["uid"], 'uri' => $item["uri"]])) {
                                Logger::log('Post with URI '.$item["uri"].' already existed for user '.$importer["uid"].'.', Logger::DEBUG);
                                continue;
                        } else {
@@ -481,7 +479,7 @@ class OStatus
                                Logger::log("Favorite ".$orig_uri." ".print_r($item, true));
 
                                $item["verb"] = Activity::LIKE;
-                               $item["parent-uri"] = $orig_uri;
+                               $item["thr-parent"] = $orig_uri;
                                $item["gravity"] = GRAVITY_ACTIVITY;
                                $item["object-type"] = Activity\ObjectType::NOTE;
                        }
@@ -494,7 +492,7 @@ class OStatus
                        self::processPost($xpath, $entry, $item, $importer);
 
                        if ($initialize && (count(self::$itemlist) > 0)) {
-                               if (self::$itemlist[0]['uri'] == self::$itemlist[0]['parent-uri']) {
+                               if (self::$itemlist[0]['uri'] == self::$itemlist[0]['thr-parent']) {
                                        // We will import it everytime, when it is started by our contacts
                                        $valid = Contact::isSharingByURL(self::$itemlist[0]['author-link'], self::$itemlist[0]['uid']);
 
@@ -521,11 +519,7 @@ class OStatus
                                                }
                                        }
                                } else {
-                                       // But we will only import complete threads
-                                       $valid = Item::exists(['uid' => $importer["uid"], 'uri' => self::$itemlist[0]['parent-uri']]);
-                                       if ($valid) {
-                                               Logger::log("Item with uri ".self::$itemlist[0]["uri"]." belongs to parent ".self::$itemlist[0]['parent-uri']." of user ".$importer["uid"].". It will be imported.", Logger::DEBUG);
-                                       }
+                                       $valid = true;
                                }
 
                                if ($valid) {
@@ -538,7 +532,7 @@ class OStatus
                                                }
                                        }
                                        foreach (self::$itemlist as $item) {
-                                               $found = Item::exists(['uid' => $importer["uid"], 'uri' => $item["uri"]]);
+                                               $found = Post::exists(['uid' => $importer["uid"], 'uri' => $item["uri"]]);
                                                if ($found) {
                                                        Logger::log("Item with uri ".$item["uri"]." for user ".$importer["uid"]." already exists.", Logger::DEBUG);
                                                } elseif ($item['contact-id'] < 0) {
@@ -566,7 +560,7 @@ class OStatus
        private static function deleteNotice(array $item)
        {
                $condition = ['uid' => $item['uid'], 'author-id' => $item['author-id'], 'uri' => $item['uri']];
-               if (!Item::exists($condition)) {
+               if (!Post::exists($condition)) {
                        Logger::log('Item from '.$item['author-link'].' with uri '.$item['uri'].' for user '.$item['uid']." wasn't found. We don't delete it.");
                        return;
                }
@@ -620,7 +614,7 @@ class OStatus
                if (is_object($inreplyto->item(0))) {
                        foreach ($inreplyto->item(0)->attributes as $attributes) {
                                if ($attributes->name == "ref") {
-                                       $item["parent-uri"] = $attributes->textContent;
+                                       $item["thr-parent"] = $attributes->textContent;
                                }
                                if ($attributes->name == "href") {
                                        $related = $attributes->textContent;
@@ -678,11 +672,6 @@ class OStatus
 
                $item["body"] .= $add_body;
 
-               // Only add additional data when there is no picture in the post
-               if (!strstr($item["body"], '[/img]')) {
-                       $item["body"] = PageInfo::searchAndAppendToBody($item["body"]);
-               }
-
                Tag::storeFromBody($item['uri-id'], $item['body']);
 
                // Mastodon Content Warning
@@ -701,16 +690,16 @@ class OStatus
                        self::fetchConversation($item['conversation-href'], $item['conversation-uri']);
                }
 
-               if (isset($item["parent-uri"])) {
-                       if (!Item::exists(['uid' => $importer["uid"], 'uri' => $item['parent-uri']])) {
+               if (isset($item["thr-parent"])) {
+                       if (!Post::exists(['uid' => $importer["uid"], 'uri' => $item['thr-parent']])) {
                                if ($related != '') {
-                                       self::fetchRelated($related, $item["parent-uri"], $importer);
+                                       self::fetchRelated($related, $item["thr-parent"], $importer);
                                }
                        } else {
                                Logger::log('Reply with URI '.$item["uri"].' already existed for user '.$importer["uid"].'.', Logger::DEBUG);
                        }
                } else {
-                       $item["parent-uri"] = $item["uri"];
+                       $item["thr-parent"] = $item["uri"];
                        $item["gravity"] = GRAVITY_PARENT;
                }
 
@@ -738,9 +727,9 @@ class OStatus
 
                self::$conv_list[$conversation] = true;
 
-               $curlResult = DI::httpRequest()->get($conversation, false, ['accept_content' => 'application/atom+xml, text/html']);
+               $curlResult = DI::httpRequest()->get($conversation, ['accept_content' => 'application/atom+xml, text/html']);
 
-               if (!$curlResult->isSuccess()) {
+               if (!$curlResult->isSuccess() || empty($curlResult->getBody())) {
                        return;
                }
 
@@ -813,6 +802,7 @@ class OStatus
                        $conv_data = [];
 
                        $conv_data['protocol'] = Conversation::PARCEL_SPLIT_CONVERSATION;
+                       $conv_data['direction'] = Conversation::PULL;
                        $conv_data['network'] = Protocol::OSTATUS;
                        $conv_data['uri'] = XML::getFirstNodeValue($xpath, 'atom:id/text()', $entry);
 
@@ -853,12 +843,6 @@ class OStatus
 
                        $conv_data['source'] = $doc2->saveXML();
 
-                       $condition = ['item-uri' => $conv_data['uri'],'protocol' => Conversation::PARCEL_FEED];
-                       if (DBA::exists('conversation', $condition)) {
-                               Logger::log('Delete deprecated entry for URI '.$conv_data['uri'], Logger::DEBUG);
-                               DBA::delete('conversation', ['item-uri' => $conv_data['uri']]);
-                       }
-
                        Logger::log('Store conversation data for uri '.$conv_data['uri'], Logger::DEBUG);
                        Conversation::insert($conv_data);
                }
@@ -878,7 +862,9 @@ class OStatus
         */
        private static function fetchSelf($self, array &$item)
        {
-               $condition = ['`item-uri` = ? AND `protocol` IN (?, ?)', $self, Conversation::PARCEL_DFRN, Conversation::PARCEL_SALMON];
+               $condition = ['item-uri' => $self, 'protocol' => [Conversation::PARCEL_DFRN,
+                       Conversation::PARCEL_DIASPORA_DFRN, Conversation::PARCEL_LEGACY_DFRN,
+                       Conversation::PARCEL_LOCAL_DFRN, Conversation::PARCEL_DIRECT, Conversation::PARCEL_SALMON]];
                if (DBA::exists('conversation', $condition)) {
                        Logger::log('Conversation '.$item['uri'].' is already stored.', Logger::DEBUG);
                        return;
@@ -899,6 +885,7 @@ class OStatus
 
                $item["protocol"] = Conversation::PARCEL_SALMON;
                $item["source"] = $xml;
+               $item["direction"] = Conversation::PULL;
 
                Logger::log('Conversation '.$item['uri'].' is now fetched.', Logger::DEBUG);
        }
@@ -915,12 +902,14 @@ class OStatus
         */
        private static function fetchRelated($related, $related_uri, $importer)
        {
-               $condition = ['`item-uri` = ? AND `protocol` IN (?, ?)', $related_uri, Conversation::PARCEL_DFRN, Conversation::PARCEL_SALMON];
+               $condition = ['item-uri' => $related_uri, 'protocol' => [Conversation::PARCEL_DFRN,
+                       Conversation::PARCEL_DIASPORA_DFRN, Conversation::PARCEL_LEGACY_DFRN,
+                       Conversation::PARCEL_LOCAL_DFRN, Conversation::PARCEL_DIRECT, Conversation::PARCEL_SALMON]];
                $conversation = DBA::selectFirst('conversation', ['source', 'protocol'], $condition);
                if (DBA::isResult($conversation)) {
                        $stored = true;
                        $xml = $conversation['source'];
-                       if (self::process($xml, $importer, $contact, $hub, $stored, false)) {
+                       if (self::process($xml, $importer, $contact, $hub, $stored, false, Conversation::PULL)) {
                                Logger::log('Got valid cached XML for URI '.$related_uri, Logger::DEBUG);
                                return;
                        }
@@ -931,9 +920,9 @@ class OStatus
                }
 
                $stored = false;
-               $curlResult = DI::httpRequest()->get($related, false, ['accept_content' => 'application/atom+xml, text/html']);
+               $curlResult = DI::httpRequest()->get($related, ['accept_content' => 'application/atom+xml, text/html']);
 
-               if (!$curlResult->isSuccess()) {
+               if (!$curlResult->isSuccess() || empty($curlResult->getBody())) {
                        return;
                }
 
@@ -1005,7 +994,7 @@ class OStatus
                }
 
                if ($xml != '') {
-                       self::process($xml, $importer, $contact, $hub, $stored, false);
+                       self::process($xml, $importer, $contact, $hub, $stored, false, Conversation::PULL);
                } else {
                        Logger::log("XML couldn't be fetched for URI: ".$related_uri." - href: ".$related, Logger::DEBUG);
                }
@@ -1073,7 +1062,7 @@ class OStatus
                if (is_object($inreplyto->item(0))) {
                        foreach ($inreplyto->item(0)->attributes as $attributes) {
                                if ($attributes->name == "ref") {
-                                       $item["parent-uri"] = $attributes->textContent;
+                                       $item["thr-parent"] = $attributes->textContent;
                                }
                        }
                }
@@ -1103,7 +1092,9 @@ class OStatus
                                                if (($item["object-type"] == Activity\ObjectType::QUESTION)
                                                        || ($item["object-type"] == Activity\ObjectType::EVENT)
                                                ) {
-                                                       $item["body"] .= "\n" . PageInfo::getFooterFromUrl($attribute['href']);
+                                                       Post\Media::insert(['uri-id' => $item['uri-id'], 'type' => Post\Media::UNKNOWN,
+                                                               'url' => $attribute['href'], 'mimetype' => $attribute['type'] ?? null,
+                                                               'size' => $attribute['length'] ?? null, 'description' => $attribute['title'] ?? null]);
                                                }
                                                break;
                                        case "ostatus:conversation":
@@ -1118,25 +1109,21 @@ class OStatus
                                                if ($filetype == 'image') {
                                                        $link_data['add_body'] .= "\n[img]".$attribute['href'].'[/img]';
                                                } else {
-                                                       if (!empty($item["attach"])) {
-                                                               $item["attach"] .= ',';
-                                                       } else {
-                                                               $item["attach"] = '';
-                                                       }
-                                                       if (!isset($attribute['length'])) {
-                                                               $attribute['length'] = "0";
-                                                       }
-                                                       $item["attach"] .= '[attach]href="'.$attribute['href'].'" length="'.$attribute['length'].'" type="'.$attribute['type'].'" title="'.($attribute['title'] ?? '') .'"[/attach]';
+                                                       Post\Media::insert(['uri-id' => $item['uri-id'], 'type' => Post\Media::DOCUMENT,
+                                                               'url' => $attribute['href'], 'mimetype' => $attribute['type'],
+                                                               'size' => $attribute['length'] ?? null, 'description' => $attribute['title'] ?? null]);
                                                }
                                                break;
                                        case "related":
                                                if ($item["object-type"] != Activity\ObjectType::BOOKMARK) {
-                                                       if (!isset($item["parent-uri"])) {
-                                                               $item["parent-uri"] = $attribute['href'];
+                                                       if (!isset($item["thr-parent"])) {
+                                                               $item["thr-parent"] = $attribute['href'];
                                                        }
                                                        $link_data['related'] = $attribute['href'];
                                                } else {
-                                                       $item["body"] .= "\n" . PageInfo::getFooterFromUrl($attribute['href']);
+                                                       Post\Media::insert(['uri-id' => $item['uri-id'], 'type' => Post\Media::UNKNOWN,
+                                                               'url' => $attribute['href'], 'mimetype' => $attribute['type'] ?? null,
+                                                               'size' => $attribute['length'] ?? null, 'description' => $attribute['title'] ?? null]);
                                                }
                                                break;
                                        case "self":
@@ -1220,7 +1207,7 @@ class OStatus
                        }
 
                        // Is it a remote picture? Then make a smaller preview here
-                       $preview = ProxyUtils::proxifyUrl($preview, false, ProxyUtils::SIZE_SMALL);
+                       $preview = ProxyUtils::proxifyUrl($preview, ProxyUtils::SIZE_SMALL);
 
                        // Is it a local picture? Then make it smaller here
                        $preview = str_replace(["-0.jpg", "-0.png"], ["-2.jpg", "-2.png"], $preview);
@@ -1285,7 +1272,7 @@ class OStatus
                XML::addElement($doc, $root, "id", DI::baseUrl() . "/profile/" . $owner["nick"]);
                XML::addElement($doc, $root, "title", $title);
                XML::addElement($doc, $root, "subtitle", sprintf("Updates from %s on %s", $owner["name"], DI::config()->get('config', 'sitename')));
-               XML::addElement($doc, $root, "logo", $owner["photo"]);
+               XML::addElement($doc, $root, "logo", Contact::getAvatarUrlForId($owner['id'], ProxyUtils::SIZE_SMALL, $owner['updated']));
                XML::addElement($doc, $root, "updated", DateTimeFormat::utcNow(DateTimeFormat::ATOM));
 
                $author = self::addAuthor($doc, $owner, true);
@@ -1390,25 +1377,19 @@ class OStatus
                        }
                }
 
-               $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 = ["rel" => "enclosure",
-                                                       "href" => $matches[1],
-                                                       "type" => $matches[3]];
+               foreach (Post\Media::getByURIId($item['uri-id'], [Post\Media::DOCUMENT, Post\Media::TORRENT, Post\Media::UNKNOWN]) as $attachment) {
+                       $attributes = ['rel' => 'enclosure',
+                               'href' => $attachment['url'],
+                               'type' => $attachment['mimetype']];
 
-                                       if (intval($matches[2])) {
-                                               $attributes["length"] = intval($matches[2]);
-                                       }
-                                       if (trim($matches[4]) != "") {
-                                               $attributes["title"] = trim($matches[4]);
-                                       }
-                                       XML::addElement($doc, $root, "link", "", $attributes);
-                               }
+                       if (!empty($attachment['size'])) {
+                               $attributes['length'] = intval($attachment['size']);
                        }
+                       if (!empty($attachment['description'])) {
+                               $attributes['title'] = $attachment['description'];
+                       }
+
+                       XML::addElement($doc, $root, 'link', '', $attributes);
                }
        }
 
@@ -1446,18 +1427,18 @@ class OStatus
                $attributes = [
                                "rel" => "avatar",
                                "type" => "image/jpeg", // To-Do?
-                               "media:width" => 300,
-                               "media:height" => 300,
-                               "href" => $owner["photo"]];
+                               "media:width" => ProxyUtils::PIXEL_SMALL,
+                               "media:height" => ProxyUtils::PIXEL_SMALL,
+                               "href" => Contact::getAvatarUrlForId($owner['id'], ProxyUtils::SIZE_SMALL, $owner['updated'])];
                XML::addElement($doc, $author, "link", "", $attributes);
 
                if (isset($owner["thumb"])) {
                        $attributes = [
                                        "rel" => "avatar",
                                        "type" => "image/jpeg", // To-Do?
-                                       "media:width" => 80,
-                                       "media:height" => 80,
-                                       "href" => $owner["thumb"]];
+                                       "media:width" => ProxyUtils::PIXEL_THUMB,
+                                       "media:height" => ProxyUtils::PIXEL_THUMB,
+                                       "href" => Contact::getAvatarUrlForId($owner['id'], ProxyUtils::SIZE_THUMB, $owner['updated'])];
                        XML::addElement($doc, $author, "link", "", $attributes);
                }
 
@@ -1610,7 +1591,7 @@ class OStatus
 
                $condition = ['uid' => $owner["uid"], 'guid' => $repeated_guid, 'private' => [Item::PUBLIC, Item::UNLISTED],
                        'network' => [Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS]];
-               $repeated_item = Item::selectFirst([], $condition);
+               $repeated_item = Post::selectFirst([], $condition);
                if (!DBA::isResult($repeated_item)) {
                        return false;
                }
@@ -1676,7 +1657,7 @@ class OStatus
                $verb = ActivityNamespace::ACTIVITY_SCHEMA . "favorite";
                self::entryContent($doc, $entry, $item, $owner, "Favorite", $verb, false);
 
-               $parent = Item::selectFirst([], ['uri' => $item["thr-parent"], 'uid' => $item["uid"]]);
+               $parent = Post::selectFirst([], ['uri' => $item["thr-parent"], 'uid' => $item["uid"]]);
                if (DBA::isResult($parent)) {
                        $as_object = $doc->createElement("activity:object");
 
@@ -1904,7 +1885,8 @@ class OStatus
                XML::addElement($doc, $entry, "id", $item["uri"]);
                XML::addElement($doc, $entry, "title", html_entity_decode($title, ENT_QUOTES, 'UTF-8'));
 
-               $body = self::formatPicturePost($item['body']);
+               $body = Post\Media::addAttachmentsToBody($item['uri-id'], $item['body']);
+               $body = self::formatPicturePost($body);
 
                if (!empty($item['title'])) {
                        $body = "[b]".$item['title']."[/b]\n\n".$body;
@@ -1944,10 +1926,9 @@ class OStatus
                $mentioned = [];
 
                if ($item['gravity'] != GRAVITY_PARENT) {
-                       $parent = Item::selectFirst(['guid', 'author-link', 'owner-link'], ['id' => $item['parent']]);
-                       $parent_item = (($item['thr-parent']) ? $item['thr-parent'] : $item['parent-uri']);
+                       $parent = Post::selectFirst(['guid', 'author-link', 'owner-link'], ['id' => $item['parent']]);
 
-                       $thrparent = Item::selectFirst(['guid', 'author-link', 'owner-link', 'plink'], ['uid' => $owner["uid"], 'uri' => $parent_item]);
+                       $thrparent = Post::selectFirst(['guid', 'author-link', 'owner-link', 'plink'], ['uid' => $owner["uid"], 'uri' => $item['thr-parent']]);
 
                        if (DBA::isResult($thrparent)) {
                                $mentioned[$thrparent["author-link"]] = $thrparent["author-link"];
@@ -1960,7 +1941,7 @@ class OStatus
                        }
 
                        $attributes = [
-                                       "ref" => $parent_item,
+                                       "ref" => $item['thr-parent'],
                                        "href" => $parent_plink];
                        XML::addElement($doc, $entry, "thr:in-reply-to", "", $attributes);
 
@@ -1971,7 +1952,7 @@ class OStatus
                }
 
                if (intval($item['parent']) > 0) {
-                       $conversation_href = $conversation_uri = str_replace('/objects/', '/context/', $item['parent-uri']);
+                       $conversation_href = $conversation_uri = str_replace('/objects/', '/context/', $item['thr-parent']);
 
                        if (isset($parent_item)) {
                                $conversation = DBA::selectFirst('conversation', ['conversation-uri', 'conversation-href'], ['item-uri' => $parent_item]);
@@ -2122,7 +2103,7 @@ class OStatus
                }
 
                $check_date = DateTimeFormat::utc($last_update);
-               $authorid = Contact::getIdForURL($owner["url"], 0, false);
+               $authorid = Contact::getIdForURL($owner["url"]);
 
                $condition = ["`uid` = ? AND `received` > ? AND NOT `deleted`
                        AND `private` != ? AND `visible` AND `wall` AND `parent-network` IN (?, ?)",
@@ -2142,12 +2123,12 @@ class OStatus
                $params = ['order' => ['received' => true], 'limit' => $max_items];
 
                if ($filter === 'posts') {
-                       $ret = Item::selectThread([], $condition, $params);
+                       $ret = Post::selectThread([], $condition, $params);
                } else {
-                       $ret = Item::select([], $condition, $params);
+                       $ret = Post::select([], $condition, $params);
                }
 
-               $items = Item::inArray($ret);
+               $items = Post::toArray($ret);
 
                $doc = new DOMDocument('1.0', 'utf-8');
                $doc->formatOutput = true;