+ $data = ['to' => [], 'cc' => []];
+
+ $data = array_merge($data, self::fetchPermissionBlockFromConversation($item));
+
+ $actor_profile = APContact::getByURL($item['author-link']);
+
+ $terms = Term::tagArrayFromItemId($item['id'], TERM_MENTION);
+
+ $contacts[$item['author-link']] = $item['author-link'];
+
+ if (!$item['private']) {
+ $data['to'][] = self::PUBLIC_COLLECTION;
+ if (!empty($actor_profile['followers'])) {
+ $data['cc'][] = $actor_profile['followers'];
+ }
+
+ foreach ($terms as $term) {
+ $profile = APContact::getByURL($term['url'], false);
+ if (!empty($profile) && empty($contacts[$profile['url']])) {
+ $data['cc'][] = $profile['url'];
+ $contacts[$profile['url']] = $profile['url'];
+ }
+ }
+ } else {
+ $receiver_list = Item::enumeratePermissions($item);
+
+ $mentioned = [];
+
+ foreach ($terms as $term) {
+ $cid = Contact::getIdForURL($term['url'], $item['uid']);
+ if (!empty($cid) && in_array($cid, $receiver_list)) {
+ $contact = DBA::selectFirst('contact', ['url'], ['id' => $cid, 'network' => Protocol::ACTIVITYPUB]);
+ $data['to'][] = $contact['url'];
+ $contacts[$contact['url']] = $contact['url'];
+ }
+ }
+
+ foreach ($receiver_list as $receiver) {
+ $contact = DBA::selectFirst('contact', ['url'], ['id' => $receiver, 'network' => Protocol::ACTIVITYPUB]);
+ if (empty($contacts[$contact['url']])) {
+ $data['cc'][] = $contact['url'];
+ $contacts[$contact['url']] = $contact['url'];
+ }
+ }
+ }
+
+ $parents = Item::select(['id', 'author-link', 'owner-link', 'gravity'], ['parent' => $item['parent']]);
+ while ($parent = Item::fetch($parents)) {
+ // Don't include data from future posts
+ if ($parent['id'] >= $item['id']) {
+ continue;
+ }
+
+ $profile = APContact::getByURL($parent['author-link'], false);
+ if (!empty($profile) && empty($contacts[$profile['url']])) {
+ $data['cc'][] = $profile['url'];
+ $contacts[$profile['url']] = $profile['url'];
+ }
+
+ if ($item['gravity'] != GRAVITY_PARENT) {
+ continue;
+ }
+
+ $profile = APContact::getByURL($parent['owner-link'], false);
+ if (!empty($profile) && empty($contacts[$profile['url']])) {
+ $data['cc'][] = $profile['url'];
+ $contacts[$profile['url']] = $profile['url'];
+ }
+ }
+ DBA::close($parents);
+
+ if (empty($data['to'])) {
+ $data['to'] = $data['cc'];
+ $data['cc'] = [];
+ }
+
+ return $data;
+ }
+
+ /**
+ * @brief Fetches a list of inboxes of followers of a given user
+ *
+ * @param integer $uid User ID
+ *
+ * @return array of follower inboxes
+ */
+ public static function fetchTargetInboxesforUser($uid)
+ {
+ $inboxes = [];
+
+ $condition = ['uid' => $uid, 'network' => Protocol::ACTIVITYPUB, 'archive' => false, 'pending' => false];
+
+ if (!empty($uid)) {
+ $condition['rel'] = [Contact::FOLLOWER, Contact::FRIEND];
+ }
+
+ $contacts = DBA::select('contact', ['notify', 'batch'], $condition);
+ while ($contact = DBA::fetch($contacts)) {
+ $contact = defaults($contact, 'batch', $contact['notify']);
+ $inboxes[$contact] = $contact;
+ }
+ DBA::close($contacts);
+
+ return $inboxes;
+ }
+
+ /**
+ * @brief Fetches an array of inboxes for the given item and user
+ *
+ * @param array $item
+ * @param integer $uid User ID
+ *
+ * @return array with inboxes
+ */
+ public static function fetchTargetInboxes($item, $uid)
+ {
+ $permissions = self::createPermissionBlockForItem($item);
+ if (empty($permissions)) {
+ return [];
+ }
+
+ $inboxes = [];
+
+ if ($item['gravity'] == GRAVITY_ACTIVITY) {
+ $item_profile = APContact::getByURL($item['author-link']);
+ } else {
+ $item_profile = APContact::getByURL($item['owner-link']);
+ }
+
+ foreach (['to', 'cc', 'bto', 'bcc'] as $element) {
+ if (empty($permissions[$element])) {
+ continue;
+ }
+
+ foreach ($permissions[$element] as $receiver) {
+ if ($receiver == $item_profile['followers']) {
+ $inboxes = self::fetchTargetInboxesforUser($uid);
+ } else {
+ $profile = APContact::getByURL($receiver);
+ if (!empty($profile)) {
+ $target = defaults($profile, 'sharedinbox', $profile['inbox']);
+ $inboxes[$target] = $target;
+ }
+ }
+ }
+ }
+
+ return $inboxes;
+ }
+
+ /**
+ * @brief Returns the activity type of a given item
+ *
+ * @param array $item
+ *
+ * @return activity type
+ */
+ public static function getTypeOfItem($item)
+ {
+ if ($item['verb'] == ACTIVITY_POST) {
+ if ($item['created'] == $item['edited']) {
+ $type = 'Create';
+ } else {
+ $type = 'Update';
+ }
+ } elseif ($item['verb'] == ACTIVITY_LIKE) {
+ $type = 'Like';
+ } elseif ($item['verb'] == ACTIVITY_DISLIKE) {
+ $type = 'Dislike';
+ } elseif ($item['verb'] == ACTIVITY_ATTEND) {
+ $type = 'Accept';
+ } elseif ($item['verb'] == ACTIVITY_ATTENDNO) {
+ $type = 'Reject';
+ } elseif ($item['verb'] == ACTIVITY_ATTENDMAYBE) {
+ $type = 'TentativeAccept';
+ } else {
+ $type = '';
+ }
+
+ return $type;
+ }
+
+ /**
+ * @brief Creates an activity array for a given item id
+ *
+ * @param integer $item_id
+ * @param boolean $object_mode Is the activity item is used inside another object?
+ *
+ * @return array of activity
+ */
+ public static function createActivityFromItem($item_id, $object_mode = false)
+ {
+ $item = Item::selectFirst([], ['id' => $item_id, 'parent-network' => Protocol::NATIVE_SUPPORT]);