]> git.mxchange.org Git - friendica.git/blobdiff - src/Protocol/OStatus.php
Merge pull request #13161 from annando/bluesky-activities
[friendica.git] / src / Protocol / OStatus.php
index c8405d953576d9dfbd226cf23052e2750271dd68..ff8fc3cbea9af9cd5294583e8eba98a42a0c39be 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * @copyright Copyright (C) 2010-2022, the Friendica project
+ * @copyright Copyright (C) 2010-2023, the Friendica project
  *
  * @license GNU AGPL version 3 or any later version
  *
 
 namespace Friendica\Protocol;
 
-use DOMAttr;
 use DOMDocument;
 use DOMElement;
 use DOMXPath;
+use Friendica\App;
 use Friendica\Content\Text\BBCode;
 use Friendica\Content\Text\HTML;
 use Friendica\Core\Cache\Enum\Duration;
@@ -103,9 +103,9 @@ class OStatus
 */
                if ($aliaslink != '') {
                        $contact = DBA::selectFirst('contact', [], [
-                               "`uid` = ? AND `alias` = ? AND `network` != ? AND `rel` IN (?, ?)",
+                               "`uid` = ? AND `alias` = ? AND `rel` IN (?, ?)",
                                $importer['uid'],
-                               $aliaslink, Protocol::STATUSNET,
+                               $aliaslink,
                                Contact::SHARING, Contact::FRIEND,
                        ]);
                }
@@ -116,11 +116,10 @@ class OStatus
                        }
 
                        $contact = DBA::selectFirst('contact', [], [
-                               "`uid` = ? AND `nurl` IN (?, ?) AND `network` != ? AND `rel` IN (?, ?)",
+                               "`uid` = ? AND `nurl` IN (?, ?) AND `rel` IN (?, ?)",
                                $importer['uid'],
                                Strings::normaliseLink($author['author-link']),
                                Strings::normaliseLink($aliaslink),
-                               Protocol::STATUSNET,
                                Contact::SHARING,
                                Contact::FRIEND,
                        ]);
@@ -128,10 +127,9 @@ class OStatus
 
                if (!DBA::isResult($contact) && ($addr != '')) {
                        $contact = DBA::selectFirst('contact', [], [
-                               "`uid` = ? AND `addr` = ? AND `network` != ? AND `rel` IN (?, ?)",
+                               "`uid` = ? AND `addr` = ? AND `rel` IN (?, ?)",
                                $importer['uid'],
                                $addr,
-                               Protocol::STATUSNET,
                                Contact::SHARING,
                                Contact::FRIEND,
                        ]);
@@ -225,7 +223,7 @@ class OStatus
                        Contact::update($contact, ['id' => $contact['id']], $current);
 
                        if (!empty($author['author-avatar']) && ($author['author-avatar'] != $current['avatar'])) {
-                               Logger::info("Update profile picture for contact ".$contact["id"]);
+                               Logger::info('Update profile picture for contact ' . $contact['id']);
                                Contact::updateAvatar($contact['id'], $author['author-avatar']);
                        }
 
@@ -381,7 +379,7 @@ class OStatus
                                foreach ($hub_attributes as $hub_attribute) {
                                        if ($hub_attribute->name == 'href') {
                                                $hub = $hub_attribute->textContent;
-                                               Logger::info("Found hub ", ['hub' => $hub]);
+                                               Logger::info('Found hub ', ['hub' => $hub]);
                                        }
                                }
                        }
@@ -392,7 +390,7 @@ class OStatus
                $header['network'] = Protocol::OSTATUS;
                $header['wall'] = 0;
                $header['origin'] = 0;
-               $header['gravity'] = GRAVITY_COMMENT;
+               $header['gravity'] = Item::GRAVITY_COMMENT;
 
                if (!is_object($doc->firstChild) || empty($doc->firstChild->tagName)) {
                        return false;
@@ -459,7 +457,7 @@ class OStatus
 
                        if (in_array($item['verb'], [Activity::O_UNFAVOURITE, Activity::UNFAVORITE])) {
                                // Ignore "Unfavorite" message
-                               Logger::info("Ignore unfavorite message ", ['item' => $item]);
+                               Logger::info('Ignore unfavorite message ', ['item' => $item]);
                                continue;
                        }
 
@@ -473,13 +471,13 @@ class OStatus
 
                        if ($item['verb'] == Activity::JOIN) {
                                // ignore "Join" messages
-                               Logger::info("Ignore join message ", ['item' => $item]);
+                               Logger::info('Ignore join message ', ['item' => $item]);
                                continue;
                        }
 
                        if ($item['verb'] == 'http://mastodon.social/schema/1.0/block') {
                                // ignore mastodon "block" messages
-                               Logger::info("Ignore block message ", ['item' => $item]);
+                               Logger::info('Ignore block message ', ['item' => $item]);
                                continue;
                        }
 
@@ -496,17 +494,17 @@ class OStatus
 
                        if ($item['verb'] == Activity::FAVORITE) {
                                $orig_uri = $xpath->query('activity:object/atom:id', $entry)->item(0)->nodeValue;
-                               Logger::notice("Favorite", ['uri' => $orig_uri, 'item' => $item]);
+                               Logger::notice('Favorite', ['uri' => $orig_uri, 'item' => $item]);
 
-                               $item['verb'] = Activity::LIKE;
+                               $item['body'] = $item['verb'] = Activity::LIKE;
                                $item['thr-parent'] = $orig_uri;
-                               $item['gravity'] = GRAVITY_ACTIVITY;
+                               $item['gravity'] = Item::GRAVITY_ACTIVITY;
                                $item['object-type'] = Activity\ObjectType::NOTE;
                        }
 
                        // http://activitystrea.ms/schema/1.0/rsvp-yes
                        if (!in_array($item['verb'], [Activity::POST, Activity::LIKE, Activity::SHARE])) {
-                               Logger::info("Unhandled verb", ['verb' => $item['verb'], 'item' => $item]);
+                               Logger::info('Unhandled verb', ['verb' => $item['verb'], 'item' => $item]);
                        }
 
                        self::processPost($xpath, $entry, $item, $importer);
@@ -522,10 +520,10 @@ class OStatus
                                                $valid = !$uid || DI::pConfig()->get($uid, 'system', 'accept_only_sharer') != Item::COMPLETION_NONE;
 
                                                if ($valid) {
-                                                       Logger::info("Item with uri " . self::$itemlist[0]['uri'] . " will be imported due to the system settings.");
+                                                       Logger::info('Item with URI ' . self::$itemlist[0]['uri'] . ' will be imported due to the system settings.');
                                                }
                                        } else {
-                                               Logger::info("Item with uri " . self::$itemlist[0]['uri'] . " belongs to a contact (" . self::$itemlist[0]['contact-id'] . "). It will be imported.");
+                                               Logger::info('Item with URI ' . self::$itemlist[0]['uri'] . ' belongs to a contact (' . self::$itemlist[0]['contact-id'] . '). It will be imported.');
                                        }
 
                                        if ($valid && DI::pConfig()->get($uid, 'system', 'accept_only_sharer') != Item::COMPLETION_LIKE) {
@@ -538,7 +536,7 @@ class OStatus
                                                        }
                                                }
                                                if ($valid) {
-                                                       Logger::info("Item with URI " . self::$itemlist[0]['uri'] . " will be imported since the thread contains posts or shares.");
+                                                       Logger::info('Item with URI ' . self::$itemlist[0]['uri'] . ' will be imported since the thread contains posts or shares.');
                                                }
                                        }
                                } else {
@@ -557,12 +555,12 @@ class OStatus
                                        foreach (self::$itemlist as $item) {
                                                $found = Post::exists(['uid' => $importer['uid'], 'uri' => $item['uri']]);
                                                if ($found) {
-                                                       Logger::notice("Item with uri " . $item['uri'] . " for user " . $importer['uid'] . " already exists.");
+                                                       Logger::notice('Item with URI ' . $item['uri'] . ' for user ' . $importer['uid'] . ' already exists.');
                                                } elseif ($item['contact-id'] < 0) {
-                                                       Logger::notice("Item with uri " . $item['uri'] . " is from a blocked contact.");
+                                                       Logger::notice('Item with URI ' . $item['uri'] . ' is from a blocked contact.');
                                                } else {
                                                        $ret = Item::insert($item);
-                                                       Logger::info("Item with uri " . $item['uri'] . " for user " . $importer['uid'] . " stored. Return value: " . $ret);
+                                                       Logger::info('Item with URI ' . $item['uri'] . ' for user ' . $importer['uid'] . ' stored. Return value: ' . $ret);
                                                }
                                        }
                                }
@@ -617,16 +615,16 @@ class OStatus
 
                $item['created'] = XML::getFirstNodeValue($xpath, 'atom:published/text()', $entry);
                $item['edited'] = XML::getFirstNodeValue($xpath, 'atom:updated/text()', $entry);
-               $item['conversation-uri'] = XML::getFirstNodeValue($xpath, 'ostatus:conversation/text()', $entry);
+               $item['conversation'] = XML::getFirstNodeValue($xpath, 'ostatus:conversation/text()', $entry);
 
                $conv = $xpath->query('ostatus:conversation', $entry);
                if (is_object($conv->item(0))) {
                        foreach ($conv->item(0)->attributes as $attributes) {
                                if ($attributes->name == 'ref') {
-                                       $item['conversation-uri'] = $attributes->textContent;
+                                       $item['conversation'] = $attributes->textContent;
                                }
                                if ($attributes->name == 'href') {
-                                       $item['conversation-href'] = $attributes->textContent;
+                                       $item['conversation'] = $attributes->textContent;
                                }
                        }
                }
@@ -705,14 +703,6 @@ class OStatus
                        }
                }
 
-               if (($self != '') && empty($item['protocol'])) {
-                       self::fetchSelf($self, $item);
-               }
-
-               if (!empty($item['conversation-href'])) {
-                       self::fetchConversation($item['conversation-href'], $item['conversation-uri']);
-               }
-
                if (isset($item['thr-parent'])) {
                        if (!Post::exists(['uid' => $importer['uid'], 'uri' => $item['thr-parent']])) {
                                if ($related != '') {
@@ -723,197 +713,12 @@ class OStatus
                        }
                } else {
                        $item['thr-parent'] = $item['uri'];
-                       $item['gravity'] = GRAVITY_PARENT;
-               }
-
-               if (($item['author-link'] != '') && !empty($item['protocol'])) {
-                       $item = Conversation::insert($item);
+                       $item['gravity'] = Item::GRAVITY_PARENT;
                }
 
                self::$itemlist[] = $item;
        }
 
-       /**
-        * Fetch the conversation for posts
-        *
-        * @param string $conversation     The link to the conversation
-        * @param string $conversation_uri The conversation in "uri" format
-        * @return void
-        * @throws \Friendica\Network\HTTPException\InternalServerErrorException
-        */
-       private static function fetchConversation(string $conversation, string $conversation_uri)
-       {
-               // Ensure that we only store a conversation once in a process
-               if (isset(self::$conv_list[$conversation])) {
-                       return;
-               }
-
-               self::$conv_list[$conversation] = true;
-
-               $curlResult = DI::httpClient()->get($conversation, HttpClientAccept::ATOM_XML);
-
-               if (!$curlResult->isSuccess() || empty($curlResult->getBody())) {
-                       return;
-               }
-
-               $xml = '';
-
-               if ($curlResult->inHeader('Content-Type') &&
-                       in_array('application/atom+xml', $curlResult->getHeader('Content-Type'))) {
-                       $xml = $curlResult->getBody();
-               }
-
-               if ($xml == '') {
-                       $doc = new DOMDocument();
-                       if (!@$doc->loadHTML($curlResult->getBody())) {
-                               return;
-                       }
-                       $xpath = new DOMXPath($doc);
-
-                       $links = $xpath->query('//link');
-                       if ($links) {
-                               $file = '';
-                               foreach ($links as $link) {
-                                       $attribute = self::readAttributes($link);
-                                       if (($attribute['rel'] == 'alternate') && ($attribute['type'] == 'application/atom+xml')) {
-                                               $file = $attribute['href'];
-                                       }
-                               }
-                               if ($file != '') {
-                                       $conversation_atom = DI::httpClient()->get($attribute['href'], HttpClientAccept::ATOM_XML);
-
-                                       if ($conversation_atom->isSuccess()) {
-                                               $xml = $conversation_atom->getBody();
-                                       }
-                               }
-                       }
-               }
-
-               if ($xml == '') {
-                       return;
-               }
-
-               self::storeConversation($xml, $conversation, $conversation_uri);
-       }
-
-       /**
-        * Store a feed in several conversation entries
-        *
-        * @param string $xml              The feed
-        * @param string $conversation     conversation
-        * @param string $conversation_uri conversation uri
-        * @return void
-        * @throws \Exception
-        */
-       private static function storeConversation(string $xml, string $conversation = '', string $conversation_uri = '')
-       {
-               $doc = new DOMDocument();
-               @$doc->loadXML($xml);
-
-               $xpath = new DOMXPath($doc);
-               $xpath->registerNamespace('atom', ActivityNamespace::ATOM1);
-               $xpath->registerNamespace('thr', ActivityNamespace::THREAD);
-               $xpath->registerNamespace('ostatus', ActivityNamespace::OSTATUS);
-
-               $entries = $xpath->query('/atom:feed/atom:entry');
-
-               // Now store the entries
-               foreach ($entries as $entry) {
-                       $doc2 = new DOMDocument();
-                       $doc2->preserveWhiteSpace = false;
-                       $doc2->formatOutput = true;
-
-                       $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);
-
-                       $inreplyto = $xpath->query('thr:in-reply-to', $entry);
-                       if (is_object($inreplyto->item(0))) {
-                               foreach ($inreplyto->item(0)->attributes as $attributes) {
-                                       if ($attributes->name == 'ref') {
-                                               $conv_data['reply-to-uri'] = $attributes->textContent;
-                                       }
-                               }
-                       }
-
-                       $conv_data['conversation-uri'] = XML::getFirstNodeValue($xpath, 'ostatus:conversation/text()', $entry);
-
-                       $conv = $xpath->query('ostatus:conversation', $entry);
-                       if (is_object($conv->item(0))) {
-                               foreach ($conv->item(0)->attributes as $attributes) {
-                                       if ($attributes->name == 'ref') {
-                                               $conv_data['conversation-uri'] = $attributes->textContent;
-                                       }
-                                       if ($attributes->name == 'href') {
-                                               $conv_data['conversation-href'] = $attributes->textContent;
-                                       }
-                               }
-                       }
-
-                       if ($conversation != '') {
-                               $conv_data['conversation-uri'] = $conversation;
-                       }
-
-                       if ($conversation_uri != '') {
-                               $conv_data['conversation-uri'] = $conversation_uri;
-                       }
-
-                       $entry = $doc2->importNode($entry, true);
-
-                       $doc2->appendChild($entry);
-
-                       $conv_data['source'] = $doc2->saveXML();
-
-                       Logger::info('Store conversation data for uri '.$conv_data['uri']);
-                       Conversation::insert($conv_data);
-               }
-       }
-
-       /**
-        * Fetch the own post so that it can be stored later
-        *
-        * We want to store the original data for later processing.
-        * This function is meant for cases where we process a feed with multiple entries.
-        * In that case we need to fetch the single posts here.
-        *
-        * @param string $self The link to the self item
-        * @param array  $item The item array
-        * @return void
-        * @throws \Friendica\Network\HTTPException\InternalServerErrorException
-        */
-       private static function fetchSelf(string $self, array &$item)
-       {
-               $condition = ['item-uri' => $self, 'protocol' => [Conversation::PARCEL_DFRN,
-                       Conversation::PARCEL_DIASPORA_DFRN, Conversation::PARCEL_LOCAL_DFRN,
-                       Conversation::PARCEL_DIRECT, Conversation::PARCEL_SALMON]];
-               if (DBA::exists('conversation', $condition)) {
-                       Logger::info('Conversation '.$item['uri'].' is already stored.');
-                       return;
-               }
-
-               $curlResult = DI::httpClient()->get($self, HttpClientAccept::ATOM_XML);
-
-               if (!$curlResult->isSuccess()) {
-                       return;
-               }
-
-               // We reformat the XML to make it better readable
-               $doc = new DOMDocument();
-               $doc->loadXML($curlResult->getBody());
-               $doc->preserveWhiteSpace = false;
-               $doc->formatOutput = true;
-               $xml = $doc->saveXML();
-
-               $item['protocol'] = Conversation::PARCEL_SALMON;
-               $item['source'] = $xml;
-               $item['direction'] = Conversation::PULL;
-
-               Logger::info('Conversation '.$item['uri'].' is now fetched.');
-       }
-
        /**
         * Fetch related posts and processes them
         *
@@ -926,30 +731,6 @@ class OStatus
         */
        private static function fetchRelated(string $related, string $related_uri, array $importer)
        {
-               $condition = [
-                       'item-uri' => $related_uri,
-                       'protocol' => [
-                               Conversation::PARCEL_DFRN,
-                               Conversation::PARCEL_DIASPORA_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, Conversation::PULL)) {
-                               Logger::info('Got valid cached XML for URI '.$related_uri);
-                               return;
-                       }
-                       if ($conversation['protocol'] == Conversation::PARCEL_SALMON) {
-                               Logger::info('Delete invalid cached XML for URI '.$related_uri);
-                               DBA::delete('conversation', ['item-uri' => $related_uri]);
-                       }
-               }
-
                $stored = false;
                $curlResult = DI::httpClient()->get($related, HttpClientAccept::ATOM_XML);
 
@@ -1014,21 +795,11 @@ class OStatus
                        }
                }
 
-               // Finally we take the data that we fetched from "ostatus:conversation"
-               if ($xml == '') {
-                       $condition = ['item-uri' => $related_uri, 'protocol' => Conversation::PARCEL_SPLIT_CONVERSATION];
-                       $conversation = DBA::selectFirst('conversation', ['source'], $condition);
-                       if (DBA::isResult($conversation)) {
-                               $stored = true;
-                               Logger::info('Got cached XML from conversation for URI '.$related_uri);
-                               $xml = $conversation['source'];
-                       }
-               }
-
                if ($xml != '') {
+                       $hub = '';
                        self::process($xml, $importer, $contact, $hub, $stored, false, Conversation::PULL);
                } else {
-                       Logger::info("XML couldn't be fetched for URI: " . $related_uri . " - href: " . $related);
+                       Logger::info('XML could not be fetched for URI: ' . $related_uri . ' - href: ' . $related);
                }
                return;
        }
@@ -1131,10 +902,7 @@ class OStatus
 
                                        case 'ostatus:conversation':
                                                $link_data['conversation'] = $attribute['href'];
-                                               $item['conversation-href'] = $link_data['conversation'];
-                                               if (!isset($item['conversation-uri'])) {
-                                                       $item['conversation-uri'] = $item['conversation-href'];
-                                               }
+                                               $item['conversation'] = $link_data['conversation'];
                                                break;
 
                                        case 'enclosure':
@@ -1169,7 +937,7 @@ class OStatus
                                                break;
 
                                        default:
-                                               Logger::warning('Unsupported rel=' . $attribute['rel'] . ',href=' . $attribute['href'] . ',object-type=' . $attribute['object-type']);
+                                               Logger::notice('Unsupported rel=' . $attribute['rel'] . ', href=' . $attribute['href'] . ', object-type=' . $item['object-type']);
                                }
                        }
                }
@@ -1208,44 +976,6 @@ class OStatus
                }
        }
 
-       /**
-        * Cleans the body of a post if it contains picture links
-        *
-        * @param string $body The body
-        * @param integer $uriid URI id
-        * @return string The cleaned body
-        * @throws \Friendica\Network\HTTPException\InternalServerErrorException
-        */
-       public static function formatPicturePost(string $body, int $uriid): string
-       {
-               $siteinfo = BBCode::getAttachedData($body);
-
-               if (($siteinfo['type'] == 'photo') && (!empty($siteinfo['preview']) || !empty($siteinfo['image']))) {
-                       if (isset($siteinfo['preview'])) {
-                               $preview = $siteinfo['preview'];
-                       } else {
-                               $preview = $siteinfo['image'];
-                       }
-
-                       // Is it a remote picture? Then make a smaller preview here
-                       $preview = Post\Link::getByLink($uriid, $preview, Proxy::SIZE_SMALL);
-
-                       // Is it a local picture? Then make it smaller here
-                       $preview = str_replace(['-0.jpg', '-0.png'], ['-2.jpg', '-2.png'], $preview);
-                       $preview = str_replace(['-1.jpg', '-1.png'], ['-2.jpg', '-2.png'], $preview);
-
-                       if (isset($siteinfo['url'])) {
-                               $url = $siteinfo['url'];
-                       } else {
-                               $url = $siteinfo['image'];
-                       }
-
-                       $body = trim($siteinfo['text']) . " [url]" . $url . "[/url]\n[img]" . $preview . "[/img]";
-               }
-
-               return $body;
-       }
-
        /**
         * Adds the header elements to the XML document
         *
@@ -1253,10 +983,10 @@ class OStatus
         * @param array       $owner     Contact data of the poster
         * @param string      $filter    The related feed filter (activity, posts or comments)
         *
-        * @return DOMAttr Header root element
+        * @return DOMElement Header root element
         * @throws \Friendica\Network\HTTPException\InternalServerErrorException
         */
-       private static function addHeader(DOMDocument $doc, array $owner, string $filter): DOMAttr
+       private static function addHeader(DOMDocument $doc, array $owner, string $filter): DOMElement
        {
                $root = $doc->createElementNS(ActivityNamespace::ATOM1, 'feed');
                $doc->appendChild($root);
@@ -1292,9 +1022,9 @@ class OStatus
 
                $attributes = [
                        'uri' => 'https://friendi.ca',
-                       'version' => FRIENDICA_VERSION . '-' . DB_UPDATE_VERSION,
+                       'version' => App::VERSION . '-' . DB_UPDATE_VERSION,
                ];
-               XML::addElement($doc, $root, 'generator', FRIENDICA_PLATFORM, $attributes);
+               XML::addElement($doc, $root, 'generator', App::PLATFORM, $attributes);
                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')));
@@ -1333,11 +1063,11 @@ class OStatus
 
                if ($owner['contact-type'] == Contact::TYPE_COMMUNITY) {
                        $members = DBA::count('contact', [
-                               'uid' => $owner['uid'],
-                               'self' => false,
+                               'uid'     => $owner['uid'],
+                               'self'    => false,
                                'pending' => false,
                                'archive' => false,
-                               'hidden' => false,
+                               'hidden'  => false,
                                'blocked' => false,
                        ]);
                        XML::addElement($doc, $root, 'statusnet:group_info', '', ['member_count' => $members]);
@@ -1350,12 +1080,12 @@ class OStatus
         * Add the link to the push hubs to the XML document
         *
         * @param DOMDocument $doc  XML document
-        * @param addHubLink  $root XML root element where the hub links are added
+        * @param DOMElement  $root XML root element where the hub links are added
         * @param string      $nick Nickname
         * @return void
         * @throws \Friendica\Network\HTTPException\InternalServerErrorException
         */
-       public static function addHubLink(DOMDocument $doc, DOMAttr $root, string $nick)
+       public static function addHubLink(DOMDocument $doc, DOMElement $root, string $nick)
        {
                $h = DI::baseUrl() . '/pubsubhubbub/' . $nick;
                XML::addElement($doc, $root, 'link', '', ['href' => $h, 'rel' => 'hub']);
@@ -1365,59 +1095,14 @@ class OStatus
         * Adds attachment data to the XML document
         *
         * @param DOMDocument $doc  XML document
-        * @param DOMAttr     $root XML root element where the hub links are added
+        * @param DOMElement  $root XML root element where the hub links are added
         * @param array       $item Data of the item that is to be posted
         * @return void
         * @throws \Friendica\Network\HTTPException\InternalServerErrorException
         */
-       public static function getAttachment(DOMDocument $doc, DOMAttr $root, array $item)
+       public static function getAttachment(DOMDocument $doc, DOMElement $root, array $item)
        {
-               $siteinfo = BBCode::getAttachedData($item['body']);
-
-               switch ($siteinfo['type']) {
-                       case 'photo':
-                               if (!empty($siteinfo['image'])) {
-                                       $imgdata = Images::getInfoFromURLCached($siteinfo['image']);
-                                       if ($imgdata) {
-                                               $attributes = [
-                                                       'rel' => 'enclosure',
-                                                       'href' => $siteinfo['image'],
-                                                       'type' => $imgdata['mime'],
-                                                       'length' => intval($imgdata['size']),
-                                               ];
-                                               XML::addElement($doc, $root, 'link', '', $attributes);
-                                       }
-                               }
-                               break;
-                       case 'video':
-                               $attributes = [
-                                       'rel' => 'enclosure',
-                                       'href' => $siteinfo['url'],
-                                       'type' => 'text/html; charset=UTF-8',
-                                       'length' => '0',
-                                       'title' => ($siteinfo['title'] ?? '') ?: $siteinfo['url'],
-                               ];
-                               XML::addElement($doc, $root, 'link', '', $attributes);
-                               break;
-                       default:
-                               break;
-               }
-
-               if (!DI::config()->get('system', 'ostatus_not_attach_preview') && ($siteinfo['type'] != 'photo') && isset($siteinfo['image'])) {
-                       $imgdata = Images::getInfoFromURLCached($siteinfo['image']);
-                       if ($imgdata) {
-                               $attributes = [
-                                       'rel' => 'enclosure',
-                                       'href' => $siteinfo['image'],
-                                       'type' => $imgdata['mime'],
-                                       'length' => intval($imgdata['size']),
-                               ];
-
-                               XML::addElement($doc, $root, 'link', '', $attributes);
-                       }
-               }
-
-               foreach (Post\Media::getByURIId($item['uri-id'], [Post\Media::DOCUMENT, Post\Media::TORRENT, Post\Media::UNKNOWN]) as $attachment) {
+               foreach (Post\Media::getByURIId($item['uri-id'], [Post\Media::AUDIO, Post\Media::IMAGE, Post\Media::VIDEO, Post\Media::DOCUMENT, Post\Media::TORRENT]) as $attachment) {
                        $attributes = ['rel' => 'enclosure',
                                'href' => $attachment['url'],
                                'type' => $attachment['mimetype']];
@@ -1591,8 +1276,8 @@ class OStatus
         */
        private static function likeEntry(DOMDocument $doc, array $item, array $owner, bool $toplevel): DOMElement
        {
-               if (($item['gravity'] != GRAVITY_PARENT) && (Strings::normaliseLink($item['author-link']) != Strings::normaliseLink($owner['url']))) {
-                       Logger::info("OStatus entry is from author " . $owner['url'] . " - not from " . $item['author-link'] . ". Quitting.");
+               if (($item['gravity'] != Item::GRAVITY_PARENT) && (Strings::normaliseLink($item['author-link']) != Strings::normaliseLink($owner['url']))) {
+                       Logger::info('OStatus entry is from author ' . $owner['url'] . ' - not from ' . $item['author-link'] . '. Quitting.');
                }
 
                $entry = self::entryHeader($doc, $owner, $item, $toplevel);
@@ -1710,8 +1395,8 @@ class OStatus
                }
 
                $item['uri'] = $item['parent-uri'] = $item['thr-parent']
-                               = 'tag:' . DI::baseUrl()->getHostname().
-                               ','.date('Y-m-d').':'.$action.':'.$owner['uid'].
+                               = 'tag:' . DI::baseUrl()->getHost() .
+                                 ','.date('Y-m-d').':'.$action.':'.$owner['uid'].
                                ':person:'.$connect_id.':'.$item['created'];
 
                $item['body'] = sprintf($message, $owner['nick'], $contact['nick']);
@@ -1741,18 +1426,18 @@ class OStatus
         */
        private static function noteEntry(DOMDocument $doc, array $item, array $owner, bool $toplevel): DOMElement
        {
-               if (($item['gravity'] != GRAVITY_PARENT) && (Strings::normaliseLink($item['author-link']) != Strings::normaliseLink($owner['url']))) {
-                       Logger::info("OStatus entry is from author " . $owner['url'] . " - not from " . $item['author-link'] . ". Quitting.");
+               if (($item['gravity'] != Item::GRAVITY_PARENT) && (Strings::normaliseLink($item['author-link']) != Strings::normaliseLink($owner['url']))) {
+                       Logger::info('OStatus entry is from author ' . $owner['url'] . ' - not from ' . $item['author-link'] . '. Quitting.');
                }
 
                if (!$toplevel) {
                        if (!empty($item['title'])) {
                                $title = BBCode::convertForUriId($item['uri-id'], $item['title'], BBCode::OSTATUS);
                        } else {
-                               $title = sprintf("New note by %s", $owner['nick']);
+                               $title = sprintf('New note by %s', $owner['nick']);
                        }
                } else {
-                       $title = sprintf("New comment by %s", $owner['nick']);
+                       $title = sprintf('New comment by %s', $owner['nick']);
                }
 
                $entry = self::entryHeader($doc, $owner, $item, $toplevel);
@@ -1784,7 +1469,7 @@ class OStatus
 
                        if ($owner['contact-type'] == Contact::TYPE_COMMUNITY) {
                                $contact = Contact::getByURL($item['author-link']) ?: $owner;
-                               $contact['nickname'] = $contact['nickname'] ?? $contact['nick']; 
+                               $contact['nickname'] = $contact['nickname'] ?? $contact['nick'];
                                $author = self::addAuthor($doc, $contact, false);
                                $entry->appendChild($author);
                        }
@@ -1829,11 +1514,11 @@ class OStatus
                XML::addElement($doc, $entry, 'id', $item['uri']);
                XML::addElement($doc, $entry, 'title', html_entity_decode($title, ENT_QUOTES, 'UTF-8'));
 
-               $body = Post\Media::addAttachmentsToBody($item['uri-id'], $item['body']);
-               $body = self::formatPicturePost($body, $item['uri-id']);
+               $body = Post\Media::addAttachmentsToBody($item['uri-id'], DI::contentItem()->addSharedPost($item));
+               $body = Post\Media::addHTMLLinkToBody($item['uri-id'], $body);
 
                if (!empty($item['title'])) {
-                       $body = "[b]" . $item['title'] . "[/b]\n\n" . $body;
+                       $body = '[b]' . $item['title'] . "[/b]\n\n" . $body;
                }
 
                $body = BBCode::convertForUriId($item['uri-id'], $body, BBCode::OSTATUS);
@@ -1871,7 +1556,7 @@ class OStatus
        {
                $mentioned = [];
 
-               if ($item['gravity'] != GRAVITY_PARENT) {
+               if ($item['gravity'] != Item::GRAVITY_PARENT) {
                        $parent = Post::selectFirst(['guid', 'author-link', 'owner-link'], ['id' => $item['parent']]);
 
                        $thrparent = Post::selectFirst(['guid', 'author-link', 'owner-link', 'plink'], ['uid' => $owner['uid'], 'uri' => $item['thr-parent']]);
@@ -1902,19 +1587,7 @@ class OStatus
                }
 
                if (intval($item['parent']) > 0) {
-                       $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]);
-                               if (DBA::isResult($conversation)) {
-                                       if ($conversation['conversation-uri'] != '') {
-                                               $conversation_uri = $conversation['conversation-uri'];
-                                       }
-                                       if ($conversation['conversation-href'] != '') {
-                                               $conversation_href = $conversation['conversation-href'];
-                                       }
-                               }
-                       }
+                       $conversation_href = $conversation_uri = $item['conversation'];
 
                        XML::addElement($doc, $entry, 'link', '', ['rel' => 'ostatus:conversation', 'href' => $conversation_href]);
 
@@ -1945,14 +1618,14 @@ class OStatus
                        $contact = Contact::getByURL($mention, false, ['contact-type']);
                        if (!empty($contact) && ($contact['contact-type'] == Contact::TYPE_COMMUNITY)) {
                                XML::addElement($doc, $entry, 'link', '', [
-                                               'rel' => 'mentioned',
-                                               'ostatus:object-type' => Activity\ObjectType::GROUP,
-                                               'href' => $mention,
+                                       'rel' => 'mentioned',
+                                       'ostatus:object-type' => Activity\ObjectType::GROUP,
+                                       'href' => $mention,
                                ]);
                        } else {
                                XML::addElement($doc, $entry, 'link', '', [
-                                               'rel' => 'mentioned',
-                                               'ostatus:object-type' => Activity\ObjectType::PERSON,
+                                       'rel' => 'mentioned',
+                                       'ostatus:object-type' => Activity\ObjectType::PERSON,
                                                'href' => $mention,
                                ]);
                        }
@@ -2015,7 +1688,7 @@ class OStatus
         * cache or it is empty
         *
         * @param string  $owner_nick  Nickname of the feed owner
-        * @param string  $last_update Date of the last update
+        * @param string  $last_update Date of the last update (in "Y-m-d H:i:s" format)
         * @param integer $max_items   Number of maximum items to fetch
         * @param string  $filter      Feed items filter (activity, posts or comments)
         * @param boolean $nocache     Wether to bypass caching
@@ -2036,7 +1709,7 @@ class OStatus
 
                $previous_created = $last_update;
 
-               // Don't cache when the last item was posted less then 15 minutes ago (Cache duration)
+               // Don't cache when the last item was posted less than 15 minutes ago (Cache duration)
                if ((time() - strtotime($owner['last-item'])) < 15*60) {
                        $result = DI::cache()->get($cachekey);
                        if (!$nocache && !is_null($result)) {