]> git.mxchange.org Git - friendica.git/blobdiff - src/Module/Contact.php
Merge pull request #12459 from MrPetovan/bug/12454-link-preview-translation
[friendica.git] / src / Module / Contact.php
index 87fff3e963bdad502a17481d137b107936042232..db71ab00cc5ed73aeb20481b346476cb3137ca97 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * @copyright Copyright (C) 2020, Friendica
+ * @copyright Copyright (C) 2010-2022, the Friendica project
  *
  * @license GNU AGPL version 3 or any later version
  *
 
 namespace Friendica\Module;
 
-use Friendica\App;
 use Friendica\BaseModule;
 use Friendica\Content\ContactSelector;
 use Friendica\Content\Nav;
 use Friendica\Content\Pager;
-use Friendica\Content\Text\BBCode;
 use Friendica\Content\Widget;
-use Friendica\Core\ACL;
-use Friendica\Core\Hook;
 use Friendica\Core\Protocol;
 use Friendica\Core\Renderer;
 use Friendica\Core\Theme;
@@ -39,10 +35,7 @@ use Friendica\DI;
 use Friendica\Model;
 use Friendica\Model\User;
 use Friendica\Module\Security\Login;
-use Friendica\Network\HTTPException\BadRequestException;
 use Friendica\Network\HTTPException\NotFoundException;
-use Friendica\Util\DateTimeFormat;
-use Friendica\Util\Strings;
 
 /**
  *  Manages and show Contacts and their content
@@ -54,6 +47,7 @@ class Contact extends BaseModule
        const TAB_PROFILE = 3;
        const TAB_CONTACTS = 4;
        const TAB_ADVANCED = 5;
+       const TAB_MEDIA = 6;
 
        private static function batchActions()
        {
@@ -61,205 +55,118 @@ class Contact extends BaseModule
                        return;
                }
 
-               $contacts_id = $_POST['contact_batch'];
+               $redirectUrl = $_POST['redirect_url'] ?? 'contact';
 
-               $stmt = DBA::select('contact', ['id', 'archive'], ['id' => $contacts_id, 'uid' => local_user(), 'self' => false, 'deleted' => false]);
-               $orig_records = DBA::toArray($stmt);
+               self::checkFormSecurityTokenRedirectOnError($redirectUrl, 'contact_batch_actions');
+
+               $orig_records = Model\Contact::selectToArray(['id', 'uid'], ['id' => $_POST['contact_batch'], 'uid' => [0, DI::userSession()->getLocalUserId()], 'self' => false, 'deleted' => false]);
 
                $count_actions = 0;
                foreach ($orig_records as $orig_record) {
-                       $contact_id = $orig_record['id'];
-                       if (!empty($_POST['contacts_batch_update'])) {
-                               self::updateContactFromPoll($contact_id);
+                       $cdata = Model\Contact::getPublicAndUserContactID($orig_record['id'], DI::userSession()->getLocalUserId());
+                       if (empty($cdata) || DI::userSession()->getPublicContactId() === $cdata['public']) {
+                               // No action available on your own contact
+                               continue;
+                       }
+
+                       if (!empty($_POST['contacts_batch_update']) && $cdata['user']) {
+                               self::updateContactFromPoll($cdata['user']);
                                $count_actions++;
                        }
+
                        if (!empty($_POST['contacts_batch_block'])) {
-                               self::blockContact($contact_id);
+                               self::toggleBlockContact($cdata['public'], DI::userSession()->getLocalUserId());
                                $count_actions++;
                        }
+
                        if (!empty($_POST['contacts_batch_ignore'])) {
-                               self::ignoreContact($contact_id);
-                               $count_actions++;
-                       }
-                       if (!empty($_POST['contacts_batch_archive'])
-                               && self::archiveContact($contact_id, $orig_record)
-                       ) {
-                               $count_actions++;
-                       }
-                       if (!empty($_POST['contacts_batch_drop'])) {
-                               self::dropContact($orig_record);
+                               self::toggleIgnoreContact($cdata['public']);
                                $count_actions++;
                        }
                }
                if ($count_actions > 0) {
-                       info(DI::l10n()->tt('%d contact edited.', '%d contacts edited.', $count_actions));
+                       DI::sysmsg()->addInfo(DI::l10n()->tt('%d contact edited.', '%d contacts edited.', $count_actions));
                }
 
-               DI::baseUrl()->redirect('contact');
+               DI::baseUrl()->redirect($redirectUrl);
        }
 
-       public static function post(array $parameters = [])
+       protected function post(array $request = [])
        {
-               $a = DI::app();
-
-               if (!local_user()) {
+               if (!DI::userSession()->getLocalUserId()) {
                        return;
                }
 
                // @TODO: Replace with parameter from router
-               if ($a->argv[1] === 'batch') {
+               if (DI::args()->getArgv()[1] === 'batch') {
                        self::batchActions();
-                       return;
-               }
-
-               // @TODO: Replace with parameter from router
-               $contact_id = intval($a->argv[1]);
-               if (!$contact_id) {
-                       return;
-               }
-
-               if (!DBA::exists('contact', ['id' => $contact_id, 'uid' => local_user(), 'deleted' => false])) {
-                       notice(DI::l10n()->t('Could not access contact record.'));
-                       DI::baseUrl()->redirect('contact');
-                       return; // NOTREACHED
-               }
-
-               Hook::callAll('contact_edit_post', $_POST);
-
-               $hidden = !empty($_POST['hidden']);
-
-               $notify = !empty($_POST['notify']);
-
-               $fetch_further_information = intval($_POST['fetch_further_information'] ?? 0);
-
-               $ffi_keyword_denylist = Strings::escapeHtml(trim($_POST['ffi_keyword_denylist'] ?? ''));
-
-               $priority = intval($_POST['poll'] ?? 0);
-               if ($priority > 5 || $priority < 0) {
-                       $priority = 0;
-               }
-
-               $info = Strings::escapeHtml(trim($_POST['info'] ?? ''));
-
-               $r = DBA::update('contact', [
-                       'priority'   => $priority,
-                       'info'       => $info,
-                       'hidden'     => $hidden,
-                       'notify_new_posts' => $notify,
-                       'fetch_further_information' => $fetch_further_information,
-                       'ffi_keyword_denylist'     => $ffi_keyword_denylist],
-                       ['id' => $contact_id, 'uid' => local_user()]
-               );
-
-               if (!DBA::isResult($r)) {
-                       notice(DI::l10n()->t('Failed to update contact record.'));
                }
-
-               $contact = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => local_user(), 'deleted' => false]);
-               if (DBA::isResult($contact)) {
-                       $a->data['contact'] = $contact;
-               }
-
-               return;
        }
 
        /* contact actions */
 
-       private static function updateContactFromPoll($contact_id)
+       /**
+        * @param int $contact_id Id of contact with uid != 0
+        * @throws NotFoundException
+        * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+        * @throws \ImagickException
+        */
+       public static function updateContactFromPoll(int $contact_id)
        {
-               $contact = DBA::selectFirst('contact', ['uid', 'url', 'network'], ['id' => $contact_id, 'uid' => local_user(), 'deleted' => false]);
+               $contact = DBA::selectFirst('contact', ['uid', 'url', 'network'], ['id' => $contact_id, 'uid' => DI::userSession()->getLocalUserId(), 'deleted' => false]);
                if (!DBA::isResult($contact)) {
                        return;
                }
 
                if ($contact['network'] == Protocol::OSTATUS) {
-                       $user = Model\User::getById($contact['uid']);
-                       $result = Model\Contact::createFromProbe($user, $contact['url'], false, $contact['network']);
+                       $result = Model\Contact::createFromProbeForUser($contact['uid'], $contact['url'], $contact['network']);
 
                        if ($result['success']) {
-                               DBA::update('contact', ['subhub' => 1], ['id' => $contact_id]);
+                               Model\Contact::update(['subhub' => 1], ['id' => $contact_id]);
                        }
-               } else {
-                       // pull feed and consume it, which should subscribe to the hub.
-                       Worker::add(PRIORITY_HIGH, 'OnePoll', $contact_id, 'force');
-               }
-       }
 
-       private static function updateContactFromProbe($contact_id)
-       {
-               $contact = DBA::selectFirst('contact', ['url'], ['id' => $contact_id, 'uid' => [0, local_user()], 'deleted' => false]);
-               if (!DBA::isResult($contact)) {
-                       return;
+                       // pull feed and consume it, which should subscribe to the hub.
+                       Worker::add(Worker::PRIORITY_HIGH, 'OnePoll', $contact_id, 'force');
+               } else {
+                       Worker::add(Worker::PRIORITY_HIGH, 'UpdateContact', $contact_id);
                }
-
-               // Update the entry in the contact table
-               Model\Contact::updateFromProbe($contact_id);
        }
 
        /**
         * Toggles the blocked status of a contact identified by id.
         *
-        * @param $contact_id
+        * @param int $contact_id Id of the contact with uid = 0
+        * @param int $owner_id   Id of the user we want to block the contact for
         * @throws \Exception
         */
-       private static function blockContact($contact_id)
+       private static function toggleBlockContact(int $contact_id, int $owner_id)
        {
-               $blocked = !Model\Contact\User::isBlocked($contact_id, local_user());
-               Model\Contact\User::setBlocked($contact_id, local_user(), $blocked);
+               $blocked = !Model\Contact\User::isBlocked($contact_id, $owner_id);
+               Model\Contact\User::setBlocked($contact_id, $owner_id, $blocked);
        }
 
        /**
         * Toggles the ignored status of a contact identified by id.
         *
-        * @param $contact_id
-        * @throws \Exception
-        */
-       private static function ignoreContact($contact_id)
-       {
-               $ignored = !Model\Contact\User::isIgnored($contact_id, local_user());
-               Model\Contact\User::setIgnored($contact_id, local_user(), $ignored);
-       }
-
-       /**
-        * Toggles the archived status of a contact identified by id.
-        * If the current status isn't provided, this will always archive the contact.
-        *
-        * @param $contact_id
-        * @param $orig_record
-        * @return bool
+        * @param int $contact_id Id of the contact with uid = 0
         * @throws \Exception
         */
-       private static function archiveContact($contact_id, $orig_record)
+       private static function toggleIgnoreContact(int $contact_id)
        {
-               $archived = empty($orig_record['archive']);
-               $r = DBA::update('contact', ['archive' => $archived], ['id' => $contact_id, 'uid' => local_user()]);
-
-               return DBA::isResult($r);
+               $ignored = !Model\Contact\User::isIgnored($contact_id, DI::userSession()->getLocalUserId());
+               Model\Contact\User::setIgnored($contact_id, DI::userSession()->getLocalUserId(), $ignored);
        }
 
-       private static function dropContact($orig_record)
+       protected function content(array $request = []): string
        {
-               $owner = Model\User::getOwnerDataById(local_user());
-               if (!DBA::isResult($owner)) {
-                       return;
-               }
-
-               Model\Contact::terminateFriendship($owner, $orig_record, true);
-               Model\Contact::remove($orig_record['id']);
-       }
-
-       public static function content(array $parameters = [], $update = 0)
-       {
-               if (!local_user()) {
+               if (!DI::userSession()->getLocalUserId()) {
                        return Login::form($_SERVER['REQUEST_URI']);
                }
 
-               $a = DI::app();
-
-               $search = Strings::escapeTags(trim($_GET['search'] ?? ''));
-               $nets   = Strings::escapeTags(trim($_GET['nets']   ?? ''));
-               $rel    = Strings::escapeTags(trim($_GET['rel']    ?? ''));
-               $group  = Strings::escapeTags(trim($_GET['group']  ?? ''));
+               $search = trim($_GET['search'] ?? '');
+               $nets   = trim($_GET['nets']   ?? '');
+               $rel    = trim($_GET['rel']    ?? '');
+               $group  = trim($_GET['group']  ?? '');
 
                $accounttype = $_GET['accounttype'] ?? '';
                $accounttypeid = User::getAccountTypeByString($accounttype);
@@ -271,103 +178,20 @@ class Contact extends BaseModule
                $page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.css'));
                $page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput-typeahead.css'));
 
-               $contact = null;
-               // @TODO: Replace with parameter from router
-               if ($a->argc == 2 && intval($a->argv[1])
-                       || $a->argc == 3 && intval($a->argv[1]) && in_array($a->argv[2], ['posts', 'conversations'])
-               ) {
-                       $contact_id = intval($a->argv[1]);
-
-                       // Ensure to use the user contact when the public contact was provided
-                       $data = Model\Contact::getPublicAndUserContacID($contact_id, local_user());
-                       if (!empty($data['user']) && ($contact_id == $data['public'])) {
-                               $contact_id = $data['user'];
-                       }
-
-                       $contact = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => [0, local_user()], 'deleted' => false]);
-
-                       // Don't display contacts that are about to be deleted
-                       if ($contact['network'] == Protocol::PHANTOM) {
-                               $contact = false;
-                       }
-               }
-
-               if (DBA::isResult($contact)) {
-                       if ($contact['self']) {
-                               // @TODO: Replace with parameter from router
-                               if (($a->argc == 3) && intval($a->argv[1]) && in_array($a->argv[2], ['posts', 'conversations'])) {
-                                       DI::baseUrl()->redirect('profile/' . $contact['nick']);
-                               } else {
-                                       DI::baseUrl()->redirect('profile/' . $contact['nick'] . '/profile');
-                               }
-                       }
-
-                       $a->data['contact'] = $contact;
-
-                       if (($contact['network'] != '') && ($contact['network'] != Protocol::DFRN)) {
-                               $network_link = Strings::formatNetworkName($contact['network'], $contact['url']);
-                       } else {
-                               $network_link = '';
-                       }
-
-                       $follow_link = '';
-                       $unfollow_link = '';
-                       if (in_array($contact['network'], Protocol::NATIVE_SUPPORT)) {
-                               if ($contact['uid'] && in_array($contact['rel'], [Model\Contact::SHARING, Model\Contact::FRIEND])) {
-                                       $unfollow_link = 'unfollow?url=' . urlencode($contact['url']) . '&auto=1';
-                               } elseif(!$contact['pending']) {
-                                       $follow_link = 'follow?url=' . urlencode($contact['url']) . '&auto=1';
-                               }
-                       }
-
-                       $wallmessage_link = '';
-                       if ($contact['uid'] && Model\Contact::canReceivePrivateMessages($contact)) {
-                               $wallmessage_link = 'message/new/' . $contact['id'];
-                       }
-
-                       $vcard_widget = Renderer::replaceMacros(Renderer::getMarkupTemplate('widget/vcard.tpl'), [
-                               '$name'         => $contact['name'],
-                               '$photo'        => Model\Contact::getPhoto($contact),
-                               '$url'          => Model\Contact::magicLinkByContact($contact, $contact['url']),
-                               '$addr'         => $contact['addr'] ?? '',
-                               '$network_link' => $network_link,
-                               '$network'      => DI::l10n()->t('Network:'),
-                               '$account_type' => Model\Contact::getAccountType($contact),
-                               '$follow'       => DI::l10n()->t('Follow'),
-                               '$follow_link'   => $follow_link,
-                               '$unfollow'     => DI::l10n()->t('Unfollow'),
-                               '$unfollow_link' => $unfollow_link,
-                               '$wallmessage'  => DI::l10n()->t('Message'),
-                               '$wallmessage_link' => $wallmessage_link,
-                       ]);
-
-                       $findpeople_widget = '';
-                       $follow_widget = '';
-                       $account_widget = '';
-                       $networks_widget = '';
-                       $rel_widget = '';
-
-                       if ($contact['uid'] != 0) {
-                               $groups_widget = Model\Group::sidebarWidget('contact', 'group', 'full', 'everyone', $contact_id);
-                       } else {
-                               $groups_widget = '';
-                       }
+               $vcard_widget = '';
+               $findpeople_widget = Widget::findPeople();
+               if (isset($_GET['add'])) {
+                       $follow_widget = Widget::follow($_GET['add']);
                } else {
-                       $vcard_widget = '';
-                       $findpeople_widget = Widget::findPeople();
-                       if (isset($_GET['add'])) {
-                               $follow_widget = Widget::follow($_GET['add']);
-                       } else {
-                               $follow_widget = Widget::follow();
-                       }
-
-                       $account_widget = Widget::accounttypes($_SERVER['REQUEST_URI'], $accounttype);
-                       $networks_widget = Widget::networks($_SERVER['REQUEST_URI'], $nets);
-                       $rel_widget = Widget::contactRels($_SERVER['REQUEST_URI'], $rel);
-                       $groups_widget = Widget::groups($_SERVER['REQUEST_URI'], $group);
+                       $follow_widget = Widget::follow();
                }
 
-               DI::page()['aside'] .= $vcard_widget . $findpeople_widget . $follow_widget . $account_widget . $groups_widget . $networks_widget . $rel_widget;
+               $account_widget = Widget::accountTypes($_SERVER['REQUEST_URI'], $accounttype);
+               $networks_widget = Widget::networks($_SERVER['REQUEST_URI'], $nets);
+               $rel_widget = Widget::contactRels($_SERVER['REQUEST_URI'], $rel);
+               $groups_widget = Widget::groups($_SERVER['REQUEST_URI'], $group);
+
+               DI::page()['aside'] .= $vcard_widget . $findpeople_widget . $follow_widget . $rel_widget . $groups_widget . $networks_widget . $account_widget;
 
                $tpl = Renderer::getMarkupTemplate('contacts-head.tpl');
                DI::page()['htmlhead'] .= Renderer::replaceMacros($tpl, [
@@ -377,275 +201,16 @@ class Contact extends BaseModule
                $o = '';
                Nav::setSelected('contact');
 
-               if (!local_user()) {
-                       notice(DI::l10n()->t('Permission denied.'));
-                       return Login::form();
-               }
-
-               if ($a->argc == 3) {
-                       $contact_id = intval($a->argv[1]);
-                       if (!$contact_id) {
-                               throw new BadRequestException();
-                       }
-
-                       // @TODO: Replace with parameter from router
-                       $cmd = $a->argv[2];
-
-                       $orig_record = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => [0, local_user()], 'self' => false, 'deleted' => false]);
-                       if (!DBA::isResult($orig_record)) {
-                               throw new NotFoundException(DI::l10n()->t('Contact not found'));
-                       }
-
-                       if ($cmd === 'update' && ($orig_record['uid'] != 0)) {
-                               self::updateContactFromPoll($contact_id);
-                               DI::baseUrl()->redirect('contact/' . $contact_id);
-                               // NOTREACHED
-                       }
-
-                       if ($cmd === 'updateprofile') {
-                               self::updateContactFromProbe($contact_id);
-                               DI::baseUrl()->redirect('contact/' . $contact_id);
-                               // NOTREACHED
-                       }
-
-                       if ($cmd === 'block') {
-                               self::blockContact($contact_id);
-
-                               $blocked = Model\Contact\User::isBlocked($contact_id, local_user());
-                               info(($blocked ? DI::l10n()->t('Contact has been blocked') : DI::l10n()->t('Contact has been unblocked')));
-
-                               DI::baseUrl()->redirect('contact/' . $contact_id);
-                               // NOTREACHED
-                       }
-
-                       if ($cmd === 'ignore') {
-                               self::ignoreContact($contact_id);
-
-                               $ignored = Model\Contact\User::isIgnored($contact_id, local_user());
-                               info(($ignored ? DI::l10n()->t('Contact has been ignored') : DI::l10n()->t('Contact has been unignored')));
-
-                               DI::baseUrl()->redirect('contact/' . $contact_id);
-                               // NOTREACHED
-                       }
-
-                       if ($cmd === 'archive' && ($orig_record['uid'] != 0)) {
-                               $r = self::archiveContact($contact_id, $orig_record);
-                               if ($r) {
-                                       $archived = (($orig_record['archive']) ? 0 : 1);
-                                       info((($archived) ? DI::l10n()->t('Contact has been archived') : DI::l10n()->t('Contact has been unarchived')));
-                               }
-
-                               DI::baseUrl()->redirect('contact/' . $contact_id);
-                               // NOTREACHED
-                       }
-
-                       if ($cmd === 'drop' && ($orig_record['uid'] != 0)) {
-                               // Check if we should do HTML-based delete confirmation
-                               if (!empty($_REQUEST['confirm'])) {
-                                       DI::page()['aside'] = '';
-
-                                       return Renderer::replaceMacros(Renderer::getMarkupTemplate('contact_drop_confirm.tpl'), [
-                                               '$header' => DI::l10n()->t('Drop contact'),
-                                               '$contact' => self::getContactTemplateVars($orig_record),
-                                               '$method' => 'get',
-                                               '$message' => DI::l10n()->t('Do you really want to delete this contact?'),
-                                               '$confirm' => DI::l10n()->t('Yes'),
-                                               '$confirm_url' => DI::args()->getCommand(),
-                                               '$confirm_name' => 'confirmed',
-                                               '$cancel' => DI::l10n()->t('Cancel'),
-                                       ]);
-                               }
-                               // Now check how the user responded to the confirmation query
-                               if (!empty($_REQUEST['canceled'])) {
-                                       DI::baseUrl()->redirect('contact');
-                               }
-
-                               self::dropContact($orig_record);
-                               info(DI::l10n()->t('Contact has been removed.'));
-
-                               DI::baseUrl()->redirect('contact');
-                               // NOTREACHED
-                       }
-                       if ($cmd === 'posts') {
-                               return self::getPostsHTML($a, $contact_id);
-                       }
-                       if ($cmd === 'conversations') {
-                               return self::getConversationsHMTL($a, $contact_id, $update);
-                       }
-               }
-
                $_SESSION['return_path'] = DI::args()->getQueryString();
 
-               if (!empty($a->data['contact']) && is_array($a->data['contact'])) {
-                       $contact = $a->data['contact'];
-
-                       DI::page()['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('contact_head.tpl'), [
-                               '$baseurl' => DI::baseUrl()->get(true),
-                       ]);
-
-                       $contact['blocked']  = Model\Contact\User::isBlocked($contact['id'], local_user());
-                       $contact['readonly'] = Model\Contact\User::isIgnored($contact['id'], local_user());
-
-                       $relation_text = '';
-                       switch ($contact['rel']) {
-                               case Model\Contact::FRIEND:
-                                       $relation_text = DI::l10n()->t('You are mutual friends with %s');
-                                       break;
-
-                               case Model\Contact::FOLLOWER;
-                                       $relation_text = DI::l10n()->t('You are sharing with %s');
-                                       break;
-
-                               case Model\Contact::SHARING;
-                                       $relation_text = DI::l10n()->t('%s is sharing with you');
-                                       break;
-
-                               default:
-                                       break;
-                       }
-
-                       if ($contact['uid'] == 0) {
-                               $relation_text = '';
-                       }
-
-                       if (!in_array($contact['network'], array_merge(Protocol::FEDERATED, [Protocol::TWITTER]))) {
-                               $relation_text = '';
-                       }
-
-                       $relation_text = sprintf($relation_text, $contact['name']);
-
-                       $url = Model\Contact::magicLink($contact['url']);
-                       if (strpos($url, 'redir/') === 0) {
-                               $sparkle = ' class="sparkle" ';
-                       } else {
-                               $sparkle = '';
-                       }
-
-                       $insecure = DI::l10n()->t('Private communications are not available for this contact.');
-
-                       $last_update = (($contact['last-update'] <= DBA::NULL_DATETIME) ? DI::l10n()->t('Never') : DateTimeFormat::local($contact['last-update'], 'D, j M Y, g:i A'));
-
-                       if ($contact['last-update'] > DBA::NULL_DATETIME) {
-                               $last_update .= ' ' . (($contact['last-update'] <= $contact['success_update']) ? DI::l10n()->t('(Update was successful)') : DI::l10n()->t('(Update was not successful)'));
-                       }
-                       $lblsuggest = (($contact['network'] === Protocol::DFRN) ? DI::l10n()->t('Suggest friends') : '');
-
-                       $poll_enabled = in_array($contact['network'], [Protocol::DFRN, Protocol::OSTATUS, Protocol::FEED, Protocol::MAIL]);
-
-                       $nettype = DI::l10n()->t('Network type: %s', ContactSelector::networkToName($contact['network'], $contact['url'], $contact['protocol']));
-
-                       // tabs
-                       $tab_str = self::getTabsHTML($contact, self::TAB_PROFILE);
-
-                       $lost_contact = (($contact['archive'] && $contact['term-date'] > DBA::NULL_DATETIME && $contact['term-date'] < DateTimeFormat::utcNow()) ? DI::l10n()->t('Communications lost with this contact!') : '');
-
-                       $fetch_further_information = null;
-                       if ($contact['network'] == Protocol::FEED) {
-                               $fetch_further_information = [
-                                       'fetch_further_information',
-                                       DI::l10n()->t('Fetch further information for feeds'),
-                                       $contact['fetch_further_information'],
-                                       DI::l10n()->t('Fetch information like preview pictures, title and teaser from the feed item. You can activate this if the feed doesn\'t contain much text. Keywords are taken from the meta header in the feed item and are posted as hash tags.'),
-                                       [
-                                               '0' => DI::l10n()->t('Disabled'),
-                                               '1' => DI::l10n()->t('Fetch information'),
-                                               '3' => DI::l10n()->t('Fetch keywords'),
-                                               '2' => DI::l10n()->t('Fetch information and keywords')
-                                       ]
-                               ];
-                       }
-
-                       $poll_interval = null;
-                       if ((($contact['network'] == Protocol::FEED) && !DI::config()->get('system', 'adjust_poll_frequency')) || ($contact['network']== Protocol::MAIL)) {
-                               $poll_interval = ContactSelector::pollInterval($contact['priority'], !$poll_enabled);
-                       }
-
-                       // Load contactact related actions like hide, suggest, delete and others
-                       $contact_actions = self::getContactActions($contact);
-
-                       if ($contact['uid'] != 0) {
-                               $lbl_info1 = DI::l10n()->t('Contact Information / Notes');
-                               $contact_settings_label = DI::l10n()->t('Contact Settings');
-                       } else {
-                               $lbl_info1 = null;
-                               $contact_settings_label = null;
-                       }
-
-                       $tpl = Renderer::getMarkupTemplate('contact_edit.tpl');
-                       $o .= Renderer::replaceMacros($tpl, [
-                               '$header'         => DI::l10n()->t('Contact'),
-                               '$tab_str'        => $tab_str,
-                               '$submit'         => DI::l10n()->t('Submit'),
-                               '$lbl_info1'      => $lbl_info1,
-                               '$lbl_info2'      => DI::l10n()->t('Their personal note'),
-                               '$reason'         => trim(Strings::escapeTags($contact['reason'])),
-                               '$infedit'        => DI::l10n()->t('Edit contact notes'),
-                               '$common_link'    => 'contact/' . $contact['id'] . '/contacts/common',
-                               '$relation_text'  => $relation_text,
-                               '$visit'          => DI::l10n()->t('Visit %s\'s profile [%s]', $contact['name'], $contact['url']),
-                               '$blockunblock'   => DI::l10n()->t('Block/Unblock contact'),
-                               '$ignorecont'     => DI::l10n()->t('Ignore contact'),
-                               '$lblrecent'      => DI::l10n()->t('View conversations'),
-                               '$lblsuggest'     => $lblsuggest,
-                               '$nettype'        => $nettype,
-                               '$poll_interval'  => $poll_interval,
-                               '$poll_enabled'   => $poll_enabled,
-                               '$lastupdtext'    => DI::l10n()->t('Last update:'),
-                               '$lost_contact'   => $lost_contact,
-                               '$updpub'         => DI::l10n()->t('Update public posts'),
-                               '$last_update'    => $last_update,
-                               '$udnow'          => DI::l10n()->t('Update now'),
-                               '$contact_id'     => $contact['id'],
-                               '$block_text'     => ($contact['blocked'] ? DI::l10n()->t('Unblock') : DI::l10n()->t('Block')),
-                               '$ignore_text'    => ($contact['readonly'] ? DI::l10n()->t('Unignore') : DI::l10n()->t('Ignore')),
-                               '$insecure'       => (in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::MAIL, Protocol::DIASPORA]) ? '' : $insecure),
-                               '$info'           => $contact['info'],
-                               '$cinfo'          => ['info', '', $contact['info'], ''],
-                               '$blocked'        => ($contact['blocked'] ? DI::l10n()->t('Currently blocked') : ''),
-                               '$ignored'        => ($contact['readonly'] ? DI::l10n()->t('Currently ignored') : ''),
-                               '$archived'       => ($contact['archive'] ? DI::l10n()->t('Currently archived') : ''),
-                               '$pending'        => ($contact['pending'] ? DI::l10n()->t('Awaiting connection acknowledge') : ''),
-                               '$hidden'         => ['hidden', DI::l10n()->t('Hide this contact from others'), ($contact['hidden'] == 1), DI::l10n()->t('Replies/likes to your public posts <strong>may</strong> still be visible')],
-                               '$notify'         => ['notify', DI::l10n()->t('Notification for new posts'), ($contact['notify_new_posts'] == 1), DI::l10n()->t('Send a notification of every new post of this contact')],
-                               '$fetch_further_information' => $fetch_further_information,
-                               '$ffi_keyword_denylist' => ['ffi_keyword_denylist', DI::l10n()->t('Keyword Deny List'), $contact['ffi_keyword_denylist'], DI::l10n()->t('Comma separated list of keywords that should not be converted to hashtags, when "Fetch information and keywords" is selected')],
-                               '$photo'          => Model\Contact::getPhoto($contact),
-                               '$name'           => $contact['name'],
-                               '$sparkle'        => $sparkle,
-                               '$url'            => $url,
-                               '$profileurllabel'=> DI::l10n()->t('Profile URL'),
-                               '$profileurl'     => $contact['url'],
-                               '$account_type'   => Model\Contact::getAccountType($contact),
-                               '$location'       => BBCode::convert($contact['location']),
-                               '$location_label' => DI::l10n()->t('Location:'),
-                               '$xmpp'           => BBCode::convert($contact['xmpp']),
-                               '$xmpp_label'     => DI::l10n()->t('XMPP:'),
-                               '$about'          => BBCode::convert($contact['about'], false),
-                               '$about_label'    => DI::l10n()->t('About:'),
-                               '$keywords'       => $contact['keywords'],
-                               '$keywords_label' => DI::l10n()->t('Tags:'),
-                               '$contact_action_button' => DI::l10n()->t('Actions'),
-                               '$contact_actions'=> $contact_actions,
-                               '$contact_status' => DI::l10n()->t('Status'),
-                               '$contact_settings_label' => $contact_settings_label,
-                               '$contact_profile_label' => DI::l10n()->t('Profile'),
-                       ]);
-
-                       $arr = ['contact' => $contact, 'output' => $o];
-
-                       Hook::callAll('contact_edit', $arr);
-
-                       return $arr['output'];
-               }
-
-               $sql_values = [local_user()];
+               $sql_values = [DI::userSession()->getLocalUserId()];
 
                // @TODO: Replace with parameter from router
-               $type = $a->argv[1] ?? '';
+               $type = DI::args()->getArgv()[1] ?? '';
 
                switch ($type) {
                        case 'blocked':
-                               $sql_extra = " AND EXISTS(SELECT `id` from `user-contact` WHERE `contact`.`id` = `user-contact`.`cid` and `user-contact`.`uid` = ? and `user-contact`.`blocked`)";
+                               $sql_extra = " AND `id` IN (SELECT `cid` FROM `user-contact` WHERE `user-contact`.`uid` = ? AND `user-contact`.`blocked`)";
                                // This makes the query look for contact.uid = 0
                                array_unshift($sql_values, 0);
                                break;
@@ -653,20 +218,21 @@ class Contact extends BaseModule
                                $sql_extra = " AND `hidden` AND NOT `blocked` AND NOT `pending`";
                                break;
                        case 'ignored':
-                               $sql_extra = " AND EXISTS(SELECT `id` from `user-contact` WHERE `contact`.`id` = `user-contact`.`cid` and `user-contact`.`uid` = ? and `user-contact`.`ignored`)";
+                               $sql_extra = " AND `id` IN (SELECT `cid` FROM `user-contact` WHERE `user-contact`.`uid` = ? AND `user-contact`.`ignored`)";
                                // This makes the query look for contact.uid = 0
                                array_unshift($sql_values, 0);
                                break;
                        case 'archived':
-                               $sql_extra = " AND (`archive` OR `failed`) AND NOT `blocked` AND NOT `pending`";
+                               $sql_extra = " AND `archive` AND NOT `blocked` AND NOT `pending`";
                                break;
                        case 'pending':
                                $sql_extra = " AND `pending` AND NOT `archive` AND NOT `failed` AND ((`rel` = ?)
-                                       OR EXISTS (SELECT `id` FROM `intro` WHERE `contact-id` = `contact`.`id` AND NOT `ignore`))";
+                                       OR `id` IN (SELECT `contact-id` FROM `intro` WHERE `intro`.`uid` = ? AND NOT `ignore`))";
                                $sql_values[] = Model\Contact::SHARING;
+                               $sql_values[] = DI::userSession()->getLocalUserId();
                                break;
                        default:
-                               $sql_extra = " AND NOT `archive` AND NOT `blocked` AND NOT `pending` AND NOT `failed`";
+                               $sql_extra = " AND NOT `archive` AND NOT `blocked` AND NOT `pending`";
                                break;
                }
 
@@ -680,8 +246,10 @@ class Contact extends BaseModule
                if ($search) {
                        $searching = true;
                        $search_hdr = $search;
-                       $search_txt = preg_quote($search);
-                       $sql_extra .= " AND (name REGEXP ? OR url REGEXP ? OR nick REGEXP ?)";
+                       $search_txt = preg_quote(trim($search, ' @!'));
+                       $sql_extra .= " AND (`name` REGEXP ? OR `url` REGEXP ? OR `nick` REGEXP ? OR `addr` REGEXP ? OR `alias` REGEXP ?)";
+                       $sql_values[] = $search_txt;
+                       $sql_values[] = $search_txt;
                        $sql_values[] = $search_txt;
                        $sql_values[] = $search_txt;
                        $sql_values[] = $search_txt;
@@ -710,45 +278,28 @@ class Contact extends BaseModule
                }
 
                if ($group) {
-                       $sql_extra = " AND EXISTS(SELECT `id` FROM `group_member` WHERE `gid` = ? AND `contact`.`id` = `contact-id`)";
+                       $sql_extra .= " AND `id` IN (SELECT `contact-id` FROM `group_member` WHERE `gid` = ?)";
                        $sql_values[] = $group;
                }
 
-               $total = 0;
-               $stmt = DBA::p("SELECT COUNT(*) AS `total`
-                       FROM `contact`
-                       WHERE `uid` = ?
-                       AND `self` = 0
-                       AND NOT `deleted`
-                       $sql_extra
-                       " . Widget::unavailableNetworks(),
-                       $sql_values
-               );
-               if (DBA::isResult($stmt)) {
-                       $total = DBA::fetch($stmt)['total'];
-               }
-               DBA::close($stmt);
+               $networks = Widget::unavailableNetworks();
+               $sql_extra .= " AND NOT `network` IN (" . substr(str_repeat("?, ", count($networks)), 0, -2) . ")";
+               $sql_values = array_merge($sql_values, $networks);
 
-               $pager = new Pager(DI::l10n(), DI::args()->getQueryString());
+               $condition = ["`uid` = ? AND NOT `self` AND NOT `deleted`" . $sql_extra];
+               $condition = array_merge($condition, $sql_values);
 
-               $sql_values[] = $pager->getStart();
-               $sql_values[] = $pager->getItemsPerPage();
+               $total = DBA::count('contact', $condition);
+
+               $pager = new Pager(DI::l10n(), DI::args()->getQueryString());
 
                $contacts = [];
 
-               $stmt = DBA::p("SELECT *
-                       FROM `contact`
-                       WHERE `uid` = ?
-                       AND `self` = 0
-                       AND NOT `deleted`
-                       $sql_extra
-                       ORDER BY `name` ASC
-                       LIMIT ?, ?",
-                       $sql_values
-               );
+               $stmt = DBA::select('contact', [], $condition, ['order' => ['name'], 'limit' => [$pager->getStart(), $pager->getItemsPerPage()]]);
+
                while ($contact = DBA::fetch($stmt)) {
-                       $contact['blocked'] = Model\Contact\User::isBlocked($contact['id'], local_user());
-                       $contact['readonly'] = Model\Contact\User::isIgnored($contact['id'], local_user());
+                       $contact['blocked'] = Model\Contact\User::isBlocked($contact['id'], DI::userSession()->getLocalUserId());
+                       $contact['readonly'] = Model\Contact\User::isIgnored($contact['id'], DI::userSession()->getLocalUserId());
                        $contacts[] = self::getContactTemplateVars($contact);
                }
                DBA::close($stmt);
@@ -843,14 +394,12 @@ class Contact extends BaseModule
                        '$submit'     => DI::l10n()->t('Find'),
                        '$cmd'        => DI::args()->getCommand(),
                        '$contacts'   => $contacts,
-                       '$contact_drop_confirm' => DI::l10n()->t('Do you really want to delete this contact?'),
+                       '$form_security_token'  => BaseModule::getFormSecurityToken('contact_batch_actions'),
                        'multiselect' => 1,
                        '$batch_actions' => [
                                'contacts_batch_update'  => DI::l10n()->t('Update'),
                                'contacts_batch_block'   => DI::l10n()->t('Block') . '/' . DI::l10n()->t('Unblock'),
                                'contacts_batch_ignore'  => DI::l10n()->t('Ignore') . '/' . DI::l10n()->t('Unignore'),
-                               'contacts_batch_archive' => DI::l10n()->t('Archive') . '/' . DI::l10n()->t('Unarchive'),
-                               'contacts_batch_drop'    => DI::l10n()->t('Delete'),
                        ],
                        '$h_batch_actions' => DI::l10n()->t('Batch Actions'),
                        '$paginate'   => $pager->renderFull($total),
@@ -874,7 +423,7 @@ class Contact extends BaseModule
        public static function getTabsHTML(array $contact, int $active_tab)
        {
                $cid = $pcid = $contact['id'];
-               $data = Model\Contact::getPublicAndUserContacID($contact['id'], local_user());
+               $data = Model\Contact::getPublicAndUserContactID($contact['id'], DI::userSession()->getLocalUserId());
                if (!empty($data['user']) && ($contact['id'] == $data['public'])) {
                        $cid = $data['user'];
                } elseif (!empty($data['public'])) {
@@ -899,6 +448,14 @@ class Contact extends BaseModule
                                'id'    => 'posts-tab',
                                'accesskey' => 'p',
                        ],
+                       [
+                               'label' => DI::l10n()->t('Media'),
+                               'url'   => 'contact/' . $pcid . '/media',
+                               'sel'   => (($active_tab == self::TAB_MEDIA) ? 'active' : ''),
+                               'title' => DI::l10n()->t('Posts containing media objects'),
+                               'id'    => 'media-tab',
+                               'accesskey' => 'd',
+                       ],
                        [
                                'label' => DI::l10n()->t('Profile'),
                                'url'   => 'contact/' . $cid,
@@ -916,7 +473,7 @@ class Contact extends BaseModule
                        ],
                ];
 
-               if ($cid != $pcid) {
+               if (!empty($contact['network']) && in_array($contact['network'], [Protocol::FEED, Protocol::MAIL]) && ($cid != $pcid)) {
                        $tabs[] = ['label' => DI::l10n()->t('Advanced'),
                                'url'   => 'contact/' . $cid . '/advanced/',
                                'sel'   => (($active_tab == self::TAB_ADVANCED) ? 'active' : ''),
@@ -932,79 +489,6 @@ class Contact extends BaseModule
                return $tab_str;
        }
 
-       public static function getConversationsHMTL($a, $contact_id, $update, $parent = 0)
-       {
-               $o = '';
-
-               if (!$update) {
-                       // We need the editor here to be able to reshare an item.
-                       if (local_user()) {
-                               $x = [
-                                       'is_owner' => true,
-                                       'allow_location' => $a->user['allow_location'],
-                                       'default_location' => $a->user['default-location'],
-                                       'nickname' => $a->user['nickname'],
-                                       'lockstate' => (is_array($a->user) && (strlen($a->user['allow_cid']) || strlen($a->user['allow_gid']) || strlen($a->user['deny_cid']) || strlen($a->user['deny_gid'])) ? 'lock' : 'unlock'),
-                                       'acl' => ACL::getFullSelectorHTML(DI::page(), $a->user, true),
-                                       'bang' => '',
-                                       'visitor' => 'block',
-                                       'profile_uid' => local_user(),
-                               ];
-                               $o = status_editor($a, $x, 0, true);
-                       }
-               }
-
-               $contact = DBA::selectFirst('contact', ['uid', 'url', 'id'], ['id' => $contact_id, 'deleted' => false]);
-
-               if (!$update) {
-                       $o .= self::getTabsHTML($contact, self::TAB_CONVERSATIONS);
-               }
-
-               if (DBA::isResult($contact)) {
-                       DI::page()['aside'] = '';
-
-                       if (!$update) {
-                               $profiledata = Model\Contact::getByURLForUser($contact['url'], local_user());
-                               Model\Profile::load($a, '', $profiledata, true);
-                       }
-
-                       if ($contact['uid'] == 0) {
-                               $o .= Model\Contact::getPostsFromId($contact['id'], true, $update, $parent);
-                       } else {
-                               $o .= Model\Contact::getPostsFromUrl($contact['url'], true, $update, $parent);
-                       }
-               }
-
-               return $o;
-       }
-
-       private static function getPostsHTML($a, $contact_id)
-       {
-               $contact = DBA::selectFirst('contact', ['uid', 'url', 'id'], ['id' => $contact_id, 'deleted' => false]);
-
-               $o = self::getTabsHTML($contact, self::TAB_POSTS);
-
-               if (DBA::isResult($contact)) {
-                       DI::page()['aside'] = '';
-
-                       $profiledata = Model\Contact::getByURLForUser($contact['url'], local_user());
-
-                       if (local_user() && in_array($profiledata['network'], Protocol::FEDERATED)) {
-                               $profiledata['remoteconnect'] = DI::baseUrl() . '/follow?url=' . urlencode($profiledata['url']);
-                       }
-
-                       Model\Profile::load($a, '', $profiledata, true);
-
-                       if ($contact['uid'] == 0) {
-                               $o .= Model\Contact::getPostsFromId($contact['id']);
-                       } else {
-                               $o .= Model\Contact::getPostsFromUrl($contact['url']);
-                       }
-               }
-
-               return $o;
-       }
-
        /**
         * Return the fields for the contact template
         *
@@ -1015,8 +499,8 @@ class Contact extends BaseModule
        {
                $alt_text = '';
 
-               if (!empty($contact['url']) && isset($contact['uid']) && ($contact['uid'] == 0) && local_user()) {
-                       $personal = Model\Contact::getByURL($contact['url'], false, ['uid', 'rel', 'self'], local_user());
+               if (!empty($contact['url']) && isset($contact['uid']) && ($contact['uid'] == 0) && DI::userSession()->getLocalUserId()) {
+                       $personal = Model\Contact::getByURL($contact['url'], false, ['uid', 'rel', 'self'], DI::userSession()->getLocalUserId());
                        if (!empty($personal)) {
                                $contact['uid'] = $personal['uid'];
                                $contact['rel'] = $personal['rel'];
@@ -1024,7 +508,7 @@ class Contact extends BaseModule
                        }
                }
 
-               if (!empty($contact['uid']) && !empty($contact['rel']) && local_user() == $contact['uid']) {
+               if (!empty($contact['uid']) && !empty($contact['rel']) && DI::userSession()->getLocalUserId() == $contact['uid']) {
                        switch ($contact['rel']) {
                                case Model\Contact::FRIEND:
                                        $alt_text = DI::l10n()->t('Mutual Friendship');
@@ -1043,9 +527,9 @@ class Contact extends BaseModule
                        }
                }
 
-               $url = Model\Contact::magicLink($contact['url']);
+               $url = Model\Contact::magicLinkByContact($contact);
 
-               if (strpos($url, 'redir/') === 0) {
+               if (strpos($url, 'contact/redir/') === 0) {
                        $sparkle = ' class="sparkle" ';
                } else {
                        $sparkle = '';
@@ -1070,98 +554,17 @@ class Contact extends BaseModule
                        'url'          => $url,
                        'img_hover'    => DI::l10n()->t('Visit %s\'s profile [%s]', $contact['name'], $contact['url']),
                        'photo_menu'   => Model\Contact::photoMenu($contact),
-                       'thumb'        => Model\Contact::getThumb($contact),
+                       'thumb'        => Model\Contact::getThumb($contact, true),
                        'alt_text'     => $alt_text,
                        'name'         => $contact['name'],
                        'nick'         => $contact['nick'],
-                       'details'      => $contact['location'], 
+                       'details'      => $contact['location'],
                        'tags'         => $contact['keywords'],
                        'about'        => $contact['about'],
-                       'account_type' => Model\Contact::getAccountType($contact),
+                       'account_type' => Model\Contact::getAccountType($contact['contact-type']),
                        'sparkle'      => $sparkle,
                        'itemurl'      => ($contact['addr'] ?? '') ?: $contact['url'],
-                       'network'      => ContactSelector::networkToName($contact['network'], $contact['url'], $contact['protocol']),
+                       'network'      => ContactSelector::networkToName($contact['network'], $contact['url'], $contact['protocol'], $contact['gsid']),
                ];
        }
-
-       /**
-        * Gives a array with actions which can performed to a given contact
-        *
-        * This includes actions like e.g. 'block', 'hide', 'archive', 'delete' and others
-        *
-        * @param array $contact Data about the Contact
-        * @return array with contact related actions
-        */
-       private static function getContactActions($contact)
-       {
-               $poll_enabled = in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::OSTATUS, Protocol::FEED, Protocol::MAIL]);
-               $contact_actions = [];
-
-               // Provide friend suggestion only for Friendica contacts
-               if ($contact['network'] === Protocol::DFRN) {
-                       $contact_actions['suggest'] = [
-                               'label' => DI::l10n()->t('Suggest friends'),
-                               'url'   => 'fsuggest/' . $contact['id'],
-                               'title' => '',
-                               'sel'   => '',
-                               'id'    => 'suggest',
-                       ];
-               }
-
-               if ($poll_enabled) {
-                       $contact_actions['update'] = [
-                               'label' => DI::l10n()->t('Update now'),
-                               'url'   => 'contact/' . $contact['id'] . '/update',
-                               'title' => '',
-                               'sel'   => '',
-                               'id'    => 'update',
-                       ];
-               }
-
-               if (in_array($contact['network'], Protocol::FEDERATED)) {
-                       $contact_actions['updateprofile'] = [
-                               'label' => DI::l10n()->t('Refetch contact data'),
-                               'url'   => 'contact/' . $contact['id'] . '/updateprofile',
-                               'title' => '',
-                               'sel'   => '',
-                               'id'    => 'updateprofile',
-                       ];
-               }
-
-               $contact_actions['block'] = [
-                       'label' => (intval($contact['blocked']) ? DI::l10n()->t('Unblock') : DI::l10n()->t('Block')),
-                       'url'   => 'contact/' . $contact['id'] . '/block',
-                       'title' => DI::l10n()->t('Toggle Blocked status'),
-                       'sel'   => (intval($contact['blocked']) ? 'active' : ''),
-                       'id'    => 'toggle-block',
-               ];
-
-               $contact_actions['ignore'] = [
-                       'label' => (intval($contact['readonly']) ? DI::l10n()->t('Unignore') : DI::l10n()->t('Ignore')),
-                       'url'   => 'contact/' . $contact['id'] . '/ignore',
-                       'title' => DI::l10n()->t('Toggle Ignored status'),
-                       'sel'   => (intval($contact['readonly']) ? 'active' : ''),
-                       'id'    => 'toggle-ignore',
-               ];
-
-               if ($contact['uid'] != 0) {
-                       $contact_actions['archive'] = [
-                               'label' => (intval($contact['archive']) ? DI::l10n()->t('Unarchive') : DI::l10n()->t('Archive')),
-                               'url'   => 'contact/' . $contact['id'] . '/archive',
-                               'title' => DI::l10n()->t('Toggle Archive status'),
-                               'sel'   => (intval($contact['archive']) ? 'active' : ''),
-                               'id'    => 'toggle-archive',
-                       ];
-
-                       $contact_actions['delete'] = [
-                               'label' => DI::l10n()->t('Delete'),
-                               'url'   => 'contact/' . $contact['id'] . '/drop',
-                               'title' => DI::l10n()->t('Delete contact'),
-                               'sel'   => '',
-                               'id'    => 'delete',
-                       ];
-               }
-
-               return $contact_actions;
-       }
 }