]> git.mxchange.org Git - friendica.git/blobdiff - src/Protocol/ActivityPub/Transmitter.php
Merge pull request #10372 from annando/forum-handling
[friendica.git] / src / Protocol / ActivityPub / Transmitter.php
index 5fc27015ba8580883b45bd35bced11cc60401a38..76bc295d1c4f814d34f1f64a8effdad56c7eb3b1 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
  *
@@ -33,6 +33,7 @@ use Friendica\DI;
 use Friendica\Model\APContact;
 use Friendica\Model\Contact;
 use Friendica\Model\Conversation;
+use Friendica\Model\GServer;
 use Friendica\Model\Item;
 use Friendica\Model\ItemURI;
 use Friendica\Model\Profile;
@@ -42,6 +43,7 @@ use Friendica\Model\Tag;
 use Friendica\Model\User;
 use Friendica\Protocol\Activity;
 use Friendica\Protocol\ActivityPub;
+use Friendica\Protocol\Relay;
 use Friendica\Util\DateTimeFormat;
 use Friendica\Util\HTTPSignature;
 use Friendica\Util\JsonLD;
@@ -50,9 +52,6 @@ use Friendica\Util\Map;
 use Friendica\Util\Network;
 use Friendica\Util\XML;
 
-require_once 'include/api.php';
-require_once 'mod/share.php';
-
 /**
  * ActivityPub Transmitter Protocol class
  *
@@ -70,16 +69,41 @@ class Transmitter
        public static function addRelayServerInboxes(array $inboxes = [])
        {
                $contacts = DBA::select('apcontact', ['inbox'],
-                       ["`type` = ? AND `url` IN (SELECT `url` FROM `contact` WHERE `uid` = ? AND `rel` IN (?, ?))",
-                               'Application', 0, Contact::FOLLOWER, Contact::FRIEND]);
+                       ["`type` = ? AND `url` IN (SELECT `url` FROM `contact` WHERE `uid` = ? AND `rel` = ?)",
+                               'Application', 0, Contact::FRIEND]);
                while ($contact = DBA::fetch($contacts)) {
-                       $inboxes[] = $contact['inbox'];
+                       $inboxes[$contact['inbox']] = $contact['inbox'];
                }
                DBA::close($contacts);
 
                return $inboxes;
        }
 
+       /**
+        * Add relay servers to the list of inboxes
+        *
+        * @param array $inboxes
+        * @return array inboxes with added relay servers
+        */
+       public static function addRelayServerInboxesForItem(int $item_id, array $inboxes = [])
+       {
+               $item = Post::selectFirst(['uid'], ['id' => $item_id]);
+               if (empty($item)) {
+                       return $inboxes;
+               }
+
+               $relays = Relay::getList($item_id, [], [Protocol::ACTIVITYPUB]);
+               if (empty($relays)) {
+                       return $inboxes;
+               }
+
+               foreach ($relays as $relay) {
+                       $contact = Contact::getByURLForUser($relay['url'], $item['uid'], false, ['id']);
+                       $inboxes[$relay['batch']][] = $contact['id'] ?? 0;
+               }
+               return $inboxes;
+       }
+
        /**
         * Subscribe to a relay
         *
@@ -96,8 +120,7 @@ class Transmitter
                $activity_id = ActivityPub\Transmitter::activityIDFromContact($contact['id']);
                $success = ActivityPub\Transmitter::sendActivity('Follow', $url, 0, $activity_id);
                if ($success) {
-                       $rel = $contact['rel'] == Contact::SHARING ? Contact::FRIEND : Contact::FOLLOWER;
-                       DBA::update('contact', ['rel' => $rel], ['id' => $contact['id']]);
+                       DBA::update('contact', ['rel' => Contact::FRIEND], ['id' => $contact['id']]);
                }
 
                return $success;
@@ -119,8 +142,7 @@ class Transmitter
 
                $success = self::sendContactUndo($url, $contact['id'], 0);
                if ($success || $force) {
-                       $rel = $contact['rel'] == Contact::FRIEND ? Contact::SHARING : Contact::NOTHING;
-                       DBA::update('contact', ['rel' => $rel], ['id' => $contact['id']]);
+                       DBA::update('contact', ['rel' => Contact::NOTHING], ['id' => $contact['id']]);
                }
 
                return $success;
@@ -236,9 +258,9 @@ class Transmitter
                $condition = array_merge($condition,
                        ['author-id' => $public_contact,
                        'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT],
-                       'deleted' => false, 'visible' => true, 'moderated' => false]);
+                       'deleted' => false, 'visible' => true]);
 
-               $count = DBA::count('item', $condition);
+               $count = Post::count($condition);
 
                $data = ['@context' => ActivityPub::CONTEXT];
                $data['id'] = DI::baseUrl() . '/outbox/' . $owner['nickname'];
@@ -253,8 +275,8 @@ class Transmitter
 
                        $condition['parent-network'] = Protocol::NATIVE_SUPPORT;
 
-                       $items = Item::select(['id'], $condition, ['limit' => [($page - 1) * 20, 20], 'order' => ['created' => true]]);
-                       while ($item = Item::fetch($items)) {
+                       $items = Post::select(['id'], $condition, ['limit' => [($page - 1) * 20, 20], 'order' => ['created' => true]]);
+                       while ($item = Post::fetch($items)) {
                                $activity = self::createActivityFromItem($item['id'], true);
                                $activity['type'] = $activity['type'] == 'Update' ? 'Create' : $activity['type'];
 
@@ -263,6 +285,7 @@ class Transmitter
                                        $list[] = $activity['object'];
                                }
                        }
+                       DBA::close($items);
 
                        if (!empty($list)) {
                                $data['next'] = DI::baseUrl() . '/outbox/' . $owner['nickname'] . '?page=' . ($page + 1);
@@ -410,7 +433,12 @@ class Transmitter
                $activity = json_decode($conversation['source'], true);
 
                $actor = JsonLD::fetchElement($activity, 'actor', 'id');
-               $profile = APContact::getByURL($actor);
+               if (!empty($actor)) {
+                       $permissions['to'][] = $actor;
+                       $profile = APContact::getByURL($actor);
+               } else {
+                       $profile = [];
+               }
 
                $item_profile = APContact::getByURL($item['author-link']);
                $exclude[] = $item['author-link'];
@@ -419,8 +447,6 @@ class Transmitter
                        $exclude[] = $item['owner-link'];
                }
 
-               $permissions['to'][] = $actor;
-
                foreach (['to', 'cc', 'bto', 'bcc'] as $element) {
                        if (empty($activity[$element])) {
                                continue;
@@ -444,6 +470,21 @@ class Transmitter
                return $permissions;
        }
 
+       /**
+        * Check if the given item id is from ActivityPub
+        *
+        * @param integer $item_id
+        * @return boolean "true" if the post is from ActivityPub
+        */
+       private static function isAPPost(int $item_id)
+       {
+               if (empty($item_id)) {
+                       return false;
+               }
+
+               return Post::exists(['id' => $item_id, 'network' => Protocol::ACTIVITYPUB]);
+       }
+
        /**
         * Creates an array of permissions from an item thread
         *
@@ -476,7 +517,7 @@ class Transmitter
                        $always_bcc = true;
                }
 
-               if (self::isAnnounce($item) || DI::config()->get('debug', 'total_ap_delivery')) {
+               if (self::isAnnounce($item) || DI::config()->get('debug', 'total_ap_delivery') || self::isAPPost($last_id)) {
                        // Will be activated in a later step
                        $networks = Protocol::FEDERATED;
                } else {
@@ -492,6 +533,8 @@ class Transmitter
                        $actor_profile = APContact::getByURL($item['author-link']);
                }
 
+               $exclusive = false;
+
                $terms = Tag::getByURIId($item['uri-id'], [Tag::MENTION, Tag::IMPLICIT_MENTION, Tag::EXCLUSIVE_MENTION]);
 
                if ($item['private'] != Item::PRIVATE) {
@@ -516,6 +559,9 @@ class Transmitter
                        foreach ($terms as $term) {
                                $profile = APContact::getByURL($term['url'], false);
                                if (!empty($profile)) {
+                                       if ($term['type'] == Tag::EXCLUSIVE_MENTION) {
+                                               $exclusive = true;
+                                       }
                                        $data['to'][] = $profile['url'];
                                }
                        }
@@ -525,8 +571,8 @@ class Transmitter
                        foreach ($terms as $term) {
                                $cid = Contact::getIdForURL($term['url'], $item['uid']);
                                if (!empty($cid) && in_array($cid, $receiver_list)) {
-                                       $contact = DBA::selectFirst('contact', ['url', 'network', 'protocol'], ['id' => $cid]);
-                                       if (!DBA::isResult($contact) || (!in_array($contact['network'], $networks) && ($contact['protocol'] != Protocol::ACTIVITYPUB))) {
+                                       $contact = DBA::selectFirst('contact', ['url', 'network', 'protocol', 'gsid'], ['id' => $cid, 'network' => Protocol::FEDERATED]);
+                                       if (!DBA::isResult($contact) || !self::isAPContact($contact, $networks)) {
                                                continue;
                                        }
 
@@ -537,8 +583,8 @@ class Transmitter
                        }
 
                        foreach ($receiver_list as $receiver) {
-                               $contact = DBA::selectFirst('contact', ['url', 'hidden', 'network', 'protocol'], ['id' => $receiver]);
-                               if (!DBA::isResult($contact) || (!in_array($contact['network'], $networks) && ($contact['protocol'] != Protocol::ACTIVITYPUB))) {
+                               $contact = DBA::selectFirst('contact', ['url', 'hidden', 'network', 'protocol', 'gsid'], ['id' => $receiver, 'network' => Protocol::FEDERATED]);
+                               if (!DBA::isResult($contact) || !self::isAPContact($contact, $networks)) {
                                        continue;
                                }
 
@@ -553,8 +599,8 @@ class Transmitter
                }
 
                if (!empty($item['parent'])) {
-                       $parents = Item::select(['id', 'author-link', 'owner-link', 'gravity', 'uri'], ['parent' => $item['parent']]);
-                       while ($parent = Item::fetch($parents)) {
+                       $parents = Post::select(['id', 'author-link', 'owner-link', 'gravity', 'uri'], ['parent' => $item['parent']]);
+                       while ($parent = Post::fetch($parents)) {
                                if ($parent['gravity'] == GRAVITY_PARENT) {
                                        $profile = APContact::getByURL($parent['owner-link'], false);
                                        if (!empty($profile)) {
@@ -571,7 +617,7 @@ class Transmitter
                                                                        $data['cc'][] = $actor_profile['followers'];
                                                                }
                                                        }
-                                               } else {
+                                               } elseif (!$exclusive) {
                                                        // Public thread parent post always are directed to the followers
                                                        if (($item['private'] != Item::PRIVATE) && !$forum_mode) {
                                                                $data['cc'][] = $actor_profile['followers'];
@@ -645,22 +691,40 @@ class Transmitter
         *
         * @return boolean "true" if inbox is archived
         */
-       private static function archivedInbox($url)
+       public static function archivedInbox($url)
        {
                return DBA::exists('inbox-status', ['url' => $url, 'archive' => true]);
        }
 
+       /**
+        * Check if a given contact should be delivered via AP
+        *
+        * @param array $contact 
+        * @param array $networks 
+        * @return bool 
+        * @throws Exception 
+        */
+       private static function isAPContact(array $contact, array $networks)
+       {
+               if (in_array($contact['network'], $networks) || ($contact['protocol'] == Protocol::ACTIVITYPUB)) {
+                       return true;
+               }
+
+               return GServer::getProtocol($contact['gsid'] ?? 0) == Post\DeliveryData::ACTIVITYPUB;
+       }
+
        /**
         * Fetches a list of inboxes of followers of a given user
         *
         * @param integer $uid      User ID
         * @param boolean $personal fetch personal inboxes
+        * @param boolean $all_ap   Retrieve all AP enabled inboxes
         *
         * @return array of follower inboxes
         * @throws \Friendica\Network\HTTPException\InternalServerErrorException
         * @throws \ImagickException
         */
-       public static function fetchTargetInboxesforUser($uid, $personal = false)
+       public static function fetchTargetInboxesforUser($uid, $personal = false, bool $all_ap = false)
        {
                $inboxes = [];
 
@@ -673,7 +737,7 @@ class Transmitter
                        }
                }
 
-               if (DI::config()->get('debug', 'total_ap_delivery')) {
+               if (DI::config()->get('debug', 'total_ap_delivery') || $all_ap) {
                        // Will be activated in a later step
                        $networks = Protocol::FEDERATED;
                } else {
@@ -681,23 +745,19 @@ class Transmitter
                        $networks = [Protocol::ACTIVITYPUB, Protocol::OSTATUS];
                }
 
-               $condition = ['uid' => $uid, 'archive' => false, 'pending' => false, 'blocked' => false];
+               $condition = ['uid' => $uid, 'archive' => false, 'pending' => false, 'blocked' => false, 'network' => Protocol::FEDERATED];
 
                if (!empty($uid)) {
                        $condition['rel'] = [Contact::FOLLOWER, Contact::FRIEND];
                }
 
-               $contacts = DBA::select('contact', ['url', 'network', 'protocol'], $condition);
+               $contacts = DBA::select('contact', ['id', 'url', 'network', 'protocol', 'gsid'], $condition);
                while ($contact = DBA::fetch($contacts)) {
-                       if (Contact::isLocal($contact['url'])) {
+                       if (!self::isAPContact($contact, $networks)) {
                                continue;
                        }
 
-                       if (!in_array($contact['network'], $networks) && ($contact['protocol'] != Protocol::ACTIVITYPUB)) {
-                               continue;
-                       }
-
-                       if ($isforum && ($contact['dfrn'] == Protocol::DFRN)) {
+                       if ($isforum && ($contact['network'] == Protocol::DFRN)) {
                                continue;
                        }
 
@@ -707,13 +767,13 @@ class Transmitter
 
                        $profile = APContact::getByURL($contact['url'], false);
                        if (!empty($profile)) {
-                               if (empty($profile['sharedinbox']) || $personal) {
+                               if (empty($profile['sharedinbox']) || $personal || Contact::isLocal($contact['url'])) {
                                        $target = $profile['inbox'];
                                } else {
                                        $target = $profile['sharedinbox'];
                                }
                                if (!self::archivedInbox($target)) {
-                                       $inboxes[$target] = $target;
+                                       $inboxes[$target][] = $contact['id'];
                                }
                        }
                }
@@ -768,21 +828,19 @@ class Transmitter
                                }
 
                                if ($item_profile && ($receiver == $item_profile['followers']) && ($uid == $profile_uid)) {
-                                       $inboxes = array_merge($inboxes, self::fetchTargetInboxesforUser($uid, $personal));
+                                       $inboxes = array_merge($inboxes, self::fetchTargetInboxesforUser($uid, $personal, self::isAPPost($last_id)));
                                } else {
-                                       if (Contact::isLocal($receiver)) {
-                                               continue;
-                                       }
-
                                        $profile = APContact::getByURL($receiver, false);
                                        if (!empty($profile)) {
-                                               if (empty($profile['sharedinbox']) || $personal || $blindcopy) {
+                                               $contact = Contact::getByURLForUser($receiver, $uid, false, ['id']);
+
+                                               if (empty($profile['sharedinbox']) || $personal || $blindcopy || Contact::isLocal($receiver)) {
                                                        $target = $profile['inbox'];
                                                } else {
                                                        $target = $profile['sharedinbox'];
                                                }
                                                if (!self::archivedInbox($target)) {
-                                                       $inboxes[$target] = $target;
+                                                       $inboxes[$target][] = $contact['id'] ?? 0;
                                                }
                                        }
                                }
@@ -800,38 +858,41 @@ class Transmitter
         * @return array
         * @throws \Exception
         */
-       public static function ItemArrayFromMail($mail_id)
+       public static function ItemArrayFromMail($mail_id, $use_title = false)
        {
                $mail = DBA::selectFirst('mail', [], ['id' => $mail_id]);
                if (!DBA::isResult($mail)) {
                        return [];
                }
 
-               $mail['uri-id'] = ItemURI::insert(['uri' => $mail['uri'], 'guid' => $mail['guid']]);
-
-               $reply = DBA::selectFirst('mail', ['uri'], ['parent-uri' => $mail['parent-uri'], 'reply' => false]);
+               $reply = DBA::selectFirst('mail', ['uri', 'uri-id', 'from-url'], ['parent-uri' => $mail['parent-uri'], 'reply' => false]);
 
                // Making the post more compatible for Mastodon by:
                // - Making it a note and not an article (no title)
                // - Moving the title into the "summary" field that is used as a "content warning"
-               $mail['body'] = '[abstract]' . $mail['title'] . "[/abstract]\n" . $mail['body'];
-               $mail['title'] = '';
 
-               $mail['author-link'] = $mail['owner-link'] = $mail['from-url'];
-               $mail['allow_cid'] = '<'.$mail['contact-id'].'>';
-               $mail['allow_gid'] = '';
-               $mail['deny_cid'] = '';
-               $mail['deny_gid'] = '';
-               $mail['private'] = true;
-               $mail['deleted'] = false;
-               $mail['edited'] = $mail['created'];
-               $mail['plink'] = $mail['uri'];
-               $mail['thr-parent'] = $reply['uri'];
-               $mail['gravity'] = ($mail['reply'] ? GRAVITY_COMMENT: GRAVITY_PARENT);
-
-               $mail['event-type'] = '';
-
-               $mail['parent'] = 0;
+               if (!$use_title) {
+                       $mail['body']         = '[abstract]' . $mail['title'] . "[/abstract]\n" . $mail['body'];
+                       $mail['title']        = '';
+               }
+
+               $mail['author-link']      = $mail['owner-link'] = $mail['from-url'];
+               $mail['owner-id']         = $mail['author-id'];
+               $mail['allow_cid']        = '<'.$mail['contact-id'].'>';
+               $mail['allow_gid']        = '';
+               $mail['deny_cid']         = '';
+               $mail['deny_gid']         = '';
+               $mail['private']          = Item::PRIVATE;
+               $mail['deleted']          = false;
+               $mail['edited']           = $mail['created'];
+               $mail['plink']            = DI::baseUrl() . '/message/' . $mail['id'];
+               $mail['parent-uri']       = $reply['uri'];
+               $mail['parent-uri-id']    = $reply['uri-id'];
+               $mail['parent-author-id'] = Contact::getIdForURL($reply['from-url'], 0, false);
+               $mail['gravity']          = ($mail['reply'] ? GRAVITY_COMMENT: GRAVITY_PARENT);
+               $mail['event-type']       = '';
+               $mail['language']         = '';
+               $mail['parent']           = 0;
 
                return $mail;
        }
@@ -978,25 +1039,25 @@ class Transmitter
         * @param integer $item_id
         * @param boolean $object_mode Is the activity item is used inside another object?
         *
-        * @return array of activity
+        * @return false|array
         * @throws \Exception
         */
-       public static function createActivityFromItem($item_id, $object_mode = false)
+       public static function createActivityFromItem(int $item_id, bool $object_mode = false)
        {
                Logger::info('Fetching activity', ['item' => $item_id]);
-               $item = Item::selectFirst([], ['id' => $item_id, 'parent-network' => Protocol::NATIVE_SUPPORT]);
+               $item = Post::selectFirst(Item::DELIVER_FIELDLIST, ['id' => $item_id, 'parent-network' => Protocol::NATIVE_SUPPORT]);
                if (!DBA::isResult($item)) {
                        return false;
                }
 
                // In case of a forum post ensure to return the original post if author and forum are on the same machine
-               if (!empty($item['forum_mode'])) {
+               if (($item['gravity'] == GRAVITY_PARENT) && !empty($item['forum_mode'])) {
                        $author = Contact::getById($item['author-id'], ['nurl']);
                        if (!empty($author['nurl'])) {
                                $self = Contact::selectFirst(['uid'], ['nurl' => $author['nurl'], 'self' => true]);
                                if (!empty($self['uid'])) {
-                                       $forum_item = Item::selectFirst([], ['uri-id' => $item['uri-id'], 'uid' => $self['uid']]);
-                                       if (DBA::isResult($item)) {
+                                       $forum_item = Post::selectFirst(Item::DELIVER_FIELDLIST, ['uri-id' => $item['uri-id'], 'uid' => $self['uid']]);
+                                       if (DBA::isResult($forum_item)) {
                                                $item = $forum_item; 
                                        }
                                }
@@ -1008,10 +1069,10 @@ class Transmitter
                        return false;
                }
 
-               if (empty($type)) {
+               if (!$item['deleted']) {
                        $condition = ['item-uri' => $item['uri'], 'protocol' => Conversation::PARCEL_ACTIVITYPUB];
                        $conversation = DBA::selectFirst('conversation', ['source'], $condition);
-                       if (DBA::isResult($conversation)) {
+                       if (!$item['origin'] && DBA::isResult($conversation)) {
                                $data = json_decode($conversation['source'], true);
                                if (!empty($data['type'])) {
                                        if (in_array($data['type'], ['Create', 'Update'])) {
@@ -1031,10 +1092,10 @@ class Transmitter
                                        }
                                }
                        }
-
-                       $type = self::getTypeOfItem($item);
                }
 
+               $type = self::getTypeOfItem($item);
+
                if (!$object_mode) {
                        $data = ['@context' => $context ?? ActivityPub::CONTEXT];
 
@@ -1047,7 +1108,9 @@ class Transmitter
                        $data = [];
                }
 
-               if (($item['gravity'] == GRAVITY_ACTIVITY) && ($type != 'Undo')) {
+               if ($type == 'Delete') {
+                       $data['id'] = Item::newURI($item['uid'], $item['guid']) . '/' . $type;;
+               } elseif (($item['gravity'] == GRAVITY_ACTIVITY) && ($type != 'Undo')) {
                        $data['id'] = $item['uri'];
                } else {
                        $data['id'] = $item['uri'] . '/' . $type;
@@ -1197,53 +1260,60 @@ class Transmitter
        {
                $attachments = [];
 
-               // Currently deactivated, since it creates side effects on Mastodon and Pleroma.
-               // It will be reactivated, once this cleared.
-               /*
-               $attach_data = BBCode::getAttachmentData($item['body']);
-               if (!empty($attach_data['url'])) {
-                       $attachment = ['type' => 'Page',
-                               'mediaType' => 'text/html',
-                               'url' => $attach_data['url']];
-
-                       if (!empty($attach_data['title'])) {
-                               $attachment['name'] = $attach_data['title'];
-                       }
-
-                       if (!empty($attach_data['description'])) {
-                               $attachment['summary'] = $attach_data['description'];
+               $uriids = [$item['uri-id']];
+               $shared = BBCode::fetchShareAttributes($item['body']);
+               if (!empty($shared['guid'])) {
+                       $shared_item = Post::selectFirst(['uri-id'], ['guid' => $shared['guid']]);
+                       if (!empty($shared_item['uri-id'])) {
+                               $uriids[] = $shared_item['uri-id'];
                        }
+               }
 
-                       if (!empty($attach_data['image'])) {
-                               $imgdata = Images::getInfoFromURLCached($attach_data['image']);
-                               if ($imgdata) {
-                                       $attachment['icon'] = ['type' => 'Image',
-                                               'mediaType' => $imgdata['mime'],
-                                               'width' => $imgdata[0],
-                                               'height' => $imgdata[1],
-                                               'url' => $attach_data['image']];
+               $urls = [];
+               foreach ($uriids as $uriid) {
+                       foreach (Post\Media::getByURIId($uriid, [Post\Media::DOCUMENT, Post\Media::TORRENT]) as $attachment) {
+                               if (in_array($attachment['url'], $urls)) {
+                                       continue;
                                }
-                       }
+                               $urls[] = $attachment['url'];
 
-                       $attachments[] = $attachment;
-               }
-               */
-               foreach (Post\Media::getByURIId($item['uri-id'], [Post\Media::DOCUMENT, Post\Media::TORRENT, Post\Media::UNKNOWN]) as $attachment) {
-                       $attachments[] = ['type' => 'Document',
-                               'mediaType' => $attachment['mimetype'],
-                               'url' => $attachment['url'],
-                               'name' => $attachment['description']];
+                               $attachments[] = ['type' => 'Document',
+                                       'mediaType' => $attachment['mimetype'],
+                                       'url' => $attachment['url'],
+                                       'name' => $attachment['description']];
+                       }
                }
 
                if ($type != 'Note') {
                        return $attachments;
                }
 
-               foreach (Post\Media::getByURIId($item['uri-id'], [Post\Media::AUDIO, Post\Media::IMAGE, Post\Media::VIDEO]) as $attachment) {
-                       $attachments[] = ['type' => 'Document',
-                               'mediaType' => $attachment['mimetype'],
-                               'url' => $attachment['url'],
-                               'name' => $attachment['description']];
+               foreach ($uriids as $uriid) {
+                       foreach (Post\Media::getByURIId($uriid, [Post\Media::AUDIO, Post\Media::IMAGE, Post\Media::VIDEO]) as $attachment) {
+                               if (in_array($attachment['url'], $urls)) {
+                                       continue;
+                               }
+                               $urls[] = $attachment['url'];
+
+                               $attachments[] = ['type' => 'Document',
+                                       'mediaType' => $attachment['mimetype'],
+                                       'url' => $attachment['url'],
+                                       'name' => $attachment['description']];
+                       }
+                       // Currently deactivated, since it creates side effects on Mastodon and Pleroma.
+                       // It will be activated, once this cleared.
+                       /*
+                       foreach (Post\Media::getByURIId($uriid, [Post\Media::HTML]) as $attachment) {
+                               if (in_array($attachment['url'], $urls)) {
+                                       continue;
+                               }
+                               $urls[] = $attachment['url'];
+
+                               $attachments[] = ['type' => 'Page',
+                                       'mediaType' => $attachment['mimetype'],
+                                       'url' => $attachment['url'],
+                                       'name' => $attachment['description']];
+                       }*/
                }
 
                return $attachments;
@@ -1267,7 +1337,28 @@ class Transmitter
                        return $match[0];
                }
 
-               return '[url=' . ($data['alias'] ?: $data['url']) . ']@' . $data['nick'] . '[/url]';
+               return '[url=' . $data['url'] . ']@' . $data['nick'] . '[/url]';
+       }
+
+       /**
+        * Callback function to replace a Friendica style mention in a mention for a summary
+        *
+        * @param array $match Matching values for the callback
+        * @return string Replaced mention
+        * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+        */
+       private static function mentionAddrCallback($match)
+       {
+               if (empty($match[1])) {
+                       return '';
+               }
+
+               $data = Contact::getByURL($match[1], false, ['addr']);
+               if (empty($data['addr'])) {
+                       return $match[0];
+               }
+
+               return '@' . $data['addr'];
        }
 
        /**
@@ -1345,7 +1436,7 @@ class Transmitter
         * @return array with the event data
         * @throws \Friendica\Network\HTTPException\InternalServerErrorException
         */
-       public static function createEvent($item)
+       private static function createEvent($item)
        {
                $event = [];
                $event['name'] = $item['event-summary'];
@@ -1361,6 +1452,8 @@ class Transmitter
                        $event['location'] = self::createLocation($item);
                }
 
+               $event['dfrn:adjust'] = (bool)$item['event-adjust'];
+
                return $event;
        }
 
@@ -1429,10 +1522,21 @@ class Transmitter
 
                if ($type == 'Note') {
                        $body = $item['raw-body'] ?? self::removePictures($body);
-               } elseif (($type == 'Article') && empty($data['summary'])) {
-                       $data['summary'] = BBCode::toPlaintext(Plaintext::shorten(self::removePictures($body), 1000));
                }
 
+               /**
+                * @todo Improve the automated summary
+                * This part is currently deactivated. The automated summary seems to be more
+                * confusing than helping. But possibly we will find a better way.
+                * So the code is left here for now as a reminder
+                * 
+                * } elseif (($type == 'Article') && empty($data['summary'])) {
+                *              $regexp = "/[@!]\[url\=([^\[\]]*)\].*?\[\/url\]/ism";
+                *              $summary = preg_replace_callback($regexp, ['self', 'mentionAddrCallback'], $body);
+                *              $data['summary'] = BBCode::toPlaintext(Plaintext::shorten(self::removePictures($summary), 1000));
+                * }
+                */
+
                if (empty($item['uid']) || !Feature::isEnabled($item['uid'], 'explicit_mentions')) {
                        $body = self::prependMentions($body, $item['uri-id'], $item['author-link']);
                }
@@ -1455,7 +1559,7 @@ class Transmitter
                        $richbody = preg_replace_callback($regexp, ['self', 'mentionCallback'], $item['body']);
                        $richbody = BBCode::removeAttachment($richbody);
 
-                       $data['contentMap'][$language] = BBCode::convert($richbody, false);
+                       $data['contentMap'][$language] = BBCode::convert($richbody, false, BBCode::EXTERNAL);
                }
 
                $data['source'] = ['content' => $item['body'], 'mediaType' => "text/bbcode"];
@@ -1586,7 +1690,7 @@ class Transmitter
                        return [];
                }
 
-               $reshared_item = Item::selectFirst([], ['guid' => $reshared['guid']]);
+               $reshared_item = Post::selectFirst(Item::DELIVER_FIELDLIST, ['guid' => $reshared['guid']]);
                if (!DBA::isResult($reshared_item)) {
                        return [];
                }
@@ -1845,7 +1949,7 @@ class Transmitter
 
                $condition = ['verb' => Activity::FOLLOW, 'uid' => 0, 'parent-uri' => $object,
                        'author-id' => Contact::getPublicIdByUserId($uid)];
-               if (Item::exists($condition)) {
+               if (Post::exists($condition)) {
                        Logger::log('Follow for ' . $object . ' for user ' . $uid . ' does already exist.', Logger::DEBUG);
                        return false;
                }