]> git.mxchange.org Git - friendica.git/blobdiff - src/Model/Contact.php
Merge pull request #7919 from annando/mail-update
[friendica.git] / src / Model / Contact.php
index d4e18eda08b9ab6cb569fb0f2b4ebc72a2ecd4c3..a30cd39baf093c37fdb0853e0d7195b2aca035ac 100644 (file)
@@ -12,18 +12,20 @@ use Friendica\Core\Hook;
 use Friendica\Core\L10n;
 use Friendica\Core\Logger;
 use Friendica\Core\Protocol;
+use Friendica\Core\Session;
 use Friendica\Core\System;
 use Friendica\Core\Worker;
 use Friendica\Database\DBA;
 use Friendica\Network\Probe;
 use Friendica\Object\Image;
+use Friendica\Protocol\Activity;
 use Friendica\Protocol\ActivityPub;
 use Friendica\Protocol\DFRN;
 use Friendica\Protocol\Diaspora;
 use Friendica\Protocol\OStatus;
-use Friendica\Protocol\PortableContact;
 use Friendica\Protocol\Salmon;
 use Friendica\Util\DateTimeFormat;
+use Friendica\Util\Images;
 use Friendica\Util\Network;
 use Friendica\Util\Strings;
 
@@ -270,14 +272,17 @@ class Contact extends BaseObject
         * @param string $url The contact link
         *
         * @return string basepath
+        * @return boolean $dont_update Don't update the contact
         * @throws \Friendica\Network\HTTPException\InternalServerErrorException
         * @throws \ImagickException
         */
-       public static function getBasepath($url)
+       public static function getBasepath($url, $dont_update = false)
        {
                $contact = DBA::selectFirst('contact', ['baseurl'], ['uid' => 0, 'nurl' => Strings::normaliseLink($url)]);
                if (!empty($contact['baseurl'])) {
                        return $contact['baseurl'];
+               } elseif ($dont_update) {
+                       return '';
                }
 
                self::updateFromProbeByURL($url, true);
@@ -290,6 +295,18 @@ class Contact extends BaseObject
                return '';
        }
 
+       /**
+        * Check if the given contact url is on the same server
+        *
+        * @param string $url The contact link
+        *
+        * @return boolean Is it the same server?
+        */
+       public static function isLocal($url)
+       {
+               return Strings::compareLink(self::getBasepath($url, true), System::baseUrl());
+       }
+
        /**
         * Returns the public contact id of the given user id
         *
@@ -668,21 +685,21 @@ class Contact extends BaseObject
        public static function updateSelfFromUserID($uid, $update_avatar = false)
        {
                $fields = ['id', 'name', 'nick', 'location', 'about', 'keywords', 'gender', 'avatar',
-                       'xmpp', 'contact-type', 'forum', 'prv', 'avatar-date', 'url', 'nurl',
+                       'xmpp', 'contact-type', 'forum', 'prv', 'avatar-date', 'url', 'nurl', 'unsearchable',
                        'photo', 'thumb', 'micro', 'addr', 'request', 'notify', 'poll', 'confirm', 'poco'];
                $self = DBA::selectFirst('contact', $fields, ['uid' => $uid, 'self' => true]);
                if (!DBA::isResult($self)) {
                        return;
                }
 
-               $fields = ['nickname', 'page-flags', 'account-type'];
+               $fields = ['nickname', 'page-flags', 'account-type', 'hidewall'];
                $user = DBA::selectFirst('user', $fields, ['uid' => $uid]);
                if (!DBA::isResult($user)) {
                        return;
                }
 
                $fields = ['name', 'photo', 'thumb', 'about', 'address', 'locality', 'region',
-                       'country-name', 'gender', 'pub_keywords', 'xmpp'];
+                       'country-name', 'gender', 'pub_keywords', 'xmpp', 'net-publish'];
                $profile = DBA::selectFirst('profile', $fields, ['uid' => $uid, 'is-default' => true]);
                if (!DBA::isResult($profile)) {
                        return;
@@ -703,7 +720,7 @@ class Contact extends BaseObject
                        }
 
                        // Creating the path to the avatar, beginning with the file suffix
-                       $types = Image::supportedTypes();
+                       $types = Images::supportedTypes();
                        if (isset($types[$avatar['type']])) {
                                $file_suffix = $types[$avatar['type']];
                        }
@@ -727,6 +744,7 @@ class Contact extends BaseObject
                $fields['avatar'] = System::baseUrl() . '/photo/profile/' .$uid . '.' . $file_suffix;
                $fields['forum'] = $user['page-flags'] == User::PAGE_FLAGS_COMMUNITY;
                $fields['prv'] = $user['page-flags'] == User::PAGE_FLAGS_PRVGROUP;
+               $fields['unsearchable'] = $user['hidewall'] || !$profile['net-publish'];
 
                // it seems as if ported accounts can have wrong values, so we make sure that now everything is fine.
                $fields['url'] = System::baseUrl() . '/profile/' . $user['nickname'];
@@ -811,7 +829,7 @@ class Contact extends BaseObject
                } elseif (in_array($protocol, [Protocol::OSTATUS, Protocol::DFRN])) {
                        // create an unfollow slap
                        $item = [];
-                       $item['verb'] = NAMESPACE_OSTATUS . "/unfollow";
+                       $item['verb'] = Activity::O_UNFOLLOW;
                        $item['follow'] = $contact["url"];
                        $item['body'] = '';
                        $item['title'] = '';
@@ -966,41 +984,43 @@ class Contact extends BaseObject
 
                $ssl_url = str_replace('http://', 'https://', $url);
 
+               $nurl = Strings::normaliseLink($url);
+
                // Fetch contact data from the contact table for the given user
                $s = DBA::p("SELECT `id`, `id` AS `cid`, 0 AS `gid`, 0 AS `zid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
-                       `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`
-               FROM `contact` WHERE `nurl` = ? AND `uid` = ?", Strings::normaliseLink($url), $uid);
+                       `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`, `rel`, `pending`
+               FROM `contact` WHERE `nurl` = ? AND `uid` = ?", $nurl, $uid);
                $r = DBA::toArray($s);
 
                // Fetch contact data from the contact table for the given user, checking with the alias
                if (!DBA::isResult($r)) {
                        $s = DBA::p("SELECT `id`, `id` AS `cid`, 0 AS `gid`, 0 AS `zid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
-                               `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`
-                       FROM `contact` WHERE `alias` IN (?, ?, ?) AND `uid` = ?", Strings::normaliseLink($url), $url, $ssl_url, $uid);
+                               `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`, `rel`, `pending`
+                       FROM `contact` WHERE `alias` IN (?, ?, ?) AND `uid` = ?", $nurl, $url, $ssl_url, $uid);
                        $r = DBA::toArray($s);
                }
 
                // Fetch the data from the contact table with "uid=0" (which is filled automatically)
                if (!DBA::isResult($r)) {
                        $s = DBA::p("SELECT `id`, 0 AS `cid`, `id` AS `zid`, 0 AS `gid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
-                       `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`
-                       FROM `contact` WHERE `nurl` = ? AND `uid` = 0", Strings::normaliseLink($url));
+                       `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`, `rel`, `pending`
+                       FROM `contact` WHERE `nurl` = ? AND `uid` = 0", $nurl);
                        $r = DBA::toArray($s);
                }
 
                // Fetch the data from the contact table with "uid=0" (which is filled automatically) - checked with the alias
                if (!DBA::isResult($r)) {
                        $s = DBA::p("SELECT `id`, 0 AS `cid`, `id` AS `zid`, 0 AS `gid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
-                       `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`
-                       FROM `contact` WHERE `alias` IN (?, ?, ?) AND `uid` = 0", Strings::normaliseLink($url), $url, $ssl_url);
+                       `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`, `rel`, `pending`
+                       FROM `contact` WHERE `alias` IN (?, ?, ?) AND `uid` = 0", $nurl, $url, $ssl_url);
                        $r = DBA::toArray($s);
                }
 
                // Fetch the data from the gcontact table
                if (!DBA::isResult($r)) {
                        $s = DBA::p("SELECT 0 AS `id`, 0 AS `cid`, `id` AS `gid`, 0 AS `zid`, 0 AS `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, '' AS `xmpp`,
-                       `keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, 0 AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self`
-                       FROM `gcontact` WHERE `nurl` = ?", Strings::normaliseLink($url));
+                       `keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, 0 AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self`, 2 AS `rel`, 0 AS `pending`
+                       FROM `gcontact` WHERE `nurl` = ?", $nurl);
                        $r = DBA::toArray($s);
                }
 
@@ -1061,14 +1081,14 @@ class Contact extends BaseObject
                        $profile["micro"] = $profile["thumb"];
                }
 
-               if ((empty($profile["addr"]) || empty($profile["name"])) && (defaults($profile, "gid", 0) != 0)
+               if ((empty($profile["addr"]) || empty($profile["name"])) && !empty($profile["gid"])
                        && in_array($profile["network"], Protocol::FEDERATED)
                ) {
                        Worker::add(PRIORITY_LOW, "UpdateGContact", $url);
                }
 
                // Show contact details of Diaspora contacts only if connected
-               if ((defaults($profile, "cid", 0) == 0) && (defaults($profile, "network", "") == Protocol::DIASPORA)) {
+               if (empty($profile["cid"]) && ($profile["network"] ?? "") == Protocol::DIASPORA) {
                        $profile["location"] = "";
                        $profile["about"] = "";
                        $profile["gender"] = "";
@@ -1104,7 +1124,7 @@ class Contact extends BaseObject
 
                // Fetch contact data from the contact table for the given user
                $r = q("SELECT `id`, `id` AS `cid`, 0 AS `gid`, 0 AS `zid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
-                       `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`
+                       `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`, `rel`, `pending`
                        FROM `contact` WHERE `addr` = '%s' AND `uid` = %d AND NOT `deleted`",
                        DBA::escape($addr),
                        intval($uid)
@@ -1112,7 +1132,7 @@ class Contact extends BaseObject
                // Fetch the data from the contact table with "uid=0" (which is filled automatically)
                if (!DBA::isResult($r)) {
                        $r = q("SELECT `id`, 0 AS `cid`, `id` AS `zid`, 0 AS `gid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
-                               `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`
+                               `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`, `rel`, `pending`
                                FROM `contact` WHERE `addr` = '%s' AND `uid` = 0 AND NOT `deleted`",
                                DBA::escape($addr)
                        );
@@ -1121,7 +1141,7 @@ class Contact extends BaseObject
                // Fetch the data from the gcontact table
                if (!DBA::isResult($r)) {
                        $r = q("SELECT 0 AS `id`, 0 AS `cid`, `id` AS `gid`, 0 AS `zid`, 0 AS `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, '' AS `xmpp`,
-                               `keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, `community` AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self`
+                               `keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, `community` AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self`, 2 AS `rel`, 0 AS `pending`
                                FROM `gcontact` WHERE `addr` = '%s'",
                                DBA::escape($addr)
                        );
@@ -1175,9 +1195,9 @@ class Contact extends BaseObject
                }
 
                $sparkle = false;
-               if (($contact['network'] === Protocol::DFRN) && !$contact['self'] && !$contact['pending']) {
+               if (($contact['network'] === Protocol::DFRN) && !$contact['self'] && empty($contact['pending'])) {
                        $sparkle = true;
-                       $profile_link = System::baseUrl() . '/redir/' . $contact['id'] . '?url=' . $contact['url'];
+                       $profile_link = System::baseUrl() . '/redir/' . $contact['id'];
                } else {
                        $profile_link = $contact['url'];
                }
@@ -1192,12 +1212,12 @@ class Contact extends BaseObject
                        $profile_link = $profile_link . '?tab=profile';
                }
 
-               if (self::canReceivePrivateMessages($contact) && !$contact['pending']) {
+               if (self::canReceivePrivateMessages($contact) && empty($contact['pending'])) {
                        $pm_url = System::baseUrl() . '/message/new/' . $contact['id'];
                }
 
-               if (($contact['network'] == Protocol::DFRN) && !$contact['self'] && !$contact['pending']) {
-                       $poke_link = System::baseUrl() . '/poke/?f=&c=' . $contact['id'];
+               if (($contact['network'] == Protocol::DFRN) && !$contact['self'] && empty($contact['pending'])) {
+                       $poke_link = System::baseUrl() . '/poke/?c=' . $contact['id'];
                }
 
                $contact_url = System::baseUrl() . '/contact/' . $contact['id'];
@@ -1208,31 +1228,43 @@ class Contact extends BaseObject
                        $contact_drop_link = System::baseUrl() . '/contact/' . $contact['id'] . '/drop?confirm=1';
                }
 
+               $follow_link = '';
+               $unfollow_link = '';
+               if (in_array($contact['network'], Protocol::NATIVE_SUPPORT)) {
+                       if ($contact['uid'] && in_array($contact['rel'], [self::SHARING, self::FRIEND])) {
+                               $unfollow_link = 'unfollow?url=' . urlencode($contact['url']);
+                       } elseif(!$contact['pending']) {
+                               $follow_link = 'follow?url=' . urlencode($contact['url']);
+                       }
+               }
+
                /**
                 * Menu array:
                 * "name" => [ "Label", "link", (bool)Should the link opened in a new tab? ]
                 */
                if (empty($contact['uid'])) {
-                       $connlnk = 'follow/?url=' . $contact['url'];
                        $menu = [
-                               'profile' => [L10n::t('View Profile'),   $profile_link, true],
-                               'network' => [L10n::t('Network Posts'),  $posts_link,   false],
-                               'edit'    => [L10n::t('View Contact'),   $contact_url,  false],
-                               'follow'  => [L10n::t('Connect/Follow'), $connlnk,      true],
+                               'profile' => [L10n::t('View Profile')  , $profile_link , true],
+                               'network' => [L10n::t('Network Posts') , $posts_link   , false],
+                               'edit'    => [L10n::t('View Contact')  , $contact_url  , false],
+                               'follow'  => [L10n::t('Connect/Follow'), $follow_link  , true],
+                               'unfollow'=> [L10n::t('UnFollow')      , $unfollow_link, true],
                        ];
                } else {
                        $menu = [
-                               'status'  => [L10n::t('View Status'),   $status_link,       true],
-                               'profile' => [L10n::t('View Profile'),  $profile_link,      true],
-                               'photos'  => [L10n::t('View Photos'),   $photos_link,       true],
-                               'network' => [L10n::t('Network Posts'), $posts_link,        false],
-                               'edit'    => [L10n::t('View Contact'),  $contact_url,       false],
-                               'drop'    => [L10n::t('Drop Contact'),  $contact_drop_link, false],
-                               'pm'      => [L10n::t('Send PM'),       $pm_url,            false],
-                               'poke'    => [L10n::t('Poke'),          $poke_link,         false],
+                               'status'  => [L10n::t('View Status')   , $status_link      , true],
+                               'profile' => [L10n::t('View Profile')  , $profile_link     , true],
+                               'photos'  => [L10n::t('View Photos')   , $photos_link      , true],
+                               'network' => [L10n::t('Network Posts') , $posts_link       , false],
+                               'edit'    => [L10n::t('View Contact')  , $contact_url      , false],
+                               'drop'    => [L10n::t('Drop Contact')  , $contact_drop_link, false],
+                               'pm'      => [L10n::t('Send PM')       , $pm_url           , false],
+                               'poke'    => [L10n::t('Poke')          , $poke_link        , false],
+                               'follow'  => [L10n::t('Connect/Follow'), $follow_link      , true],
+                               'unfollow'=> [L10n::t('UnFollow')      , $unfollow_link    , true],
                        ];
 
-                       if ($contact['pending']) {
+                       if (!empty($contact['pending'])) {
                                $intro = DBA::selectFirst('intro', ['id'], ['contact-id' => $contact['id']]);
                                if (DBA::isResult($intro)) {
                                        $menu['follow'] = [L10n::t('Approve'), 'notifications/intros/' . $intro['id'], true];
@@ -1426,12 +1458,27 @@ class Contact extends BaseObject
                if (DBA::isResult($contact)) {
                        $contact_id = $contact["id"];
 
-                       // Update the contact every 7 days
-                       $update_contact = ($contact['updated'] < DateTimeFormat::utc('now -7 days'));
+                       // Update the contact every 7 days (Don't update mail or feed contacts)
+                       if (in_array($contact['network'], Protocol::FEDERATED)) {
+                               $update_contact = ($contact['updated'] < DateTimeFormat::utc('now -7 days'));
+
+                               // We force the update if the avatar is empty
+                               if (empty($contact['avatar'])) {
+                                       $update_contact = true;
+                               }
+                       } elseif (empty($default) && in_array($contact['network'], [Protocol::MAIL, Protocol::PHANTOM]) && ($uid == 0)) {
+                               // Update public mail accounts via their user's accounts
+                               $fields = ['network', 'addr', 'name', 'nick', 'avatar', 'photo', 'thumb', 'micro'];
+                               $mailcontact = DBA::selectFirst('contact', $fields, ["`addr` = ? AND `network` = ? AND `uid` != 0", $url, Protocol::MAIL]);
+                               if (!DBA::isResult($mailcontact)) {
+                                       $mailcontact = DBA::selectFirst('contact', $fields, ["`nurl` = ? AND `network` = ? AND `uid` != 0", $url, Protocol::MAIL]);
+                               }
+
+                               if (DBA::isResult($mailcontact)) {
+                                       DBA::update('contact', $mailcontact, ['id' => $contact_id]);
+                               }
 
-                       // We force the update if the avatar is empty
-                       if (empty($contact['avatar'])) {
-                               $update_contact = true;
+                               $update_contact = false;
                        }
 
                        // Update the contact in the background if needed but it is called by the frontend
@@ -1462,10 +1509,9 @@ class Contact extends BaseObject
 
                if (empty($data)) {
                        $data = Probe::uri($url, "", $uid);
-
                        // Ensure that there is a gserver entry
                        if (!empty($data['baseurl']) && ($data['network'] != Protocol::PHANTOM)) {
-                               PortableContact::checkServer($data['baseurl']);
+                               GServer::check($data['baseurl']);
                        }
                }
 
@@ -1488,25 +1534,25 @@ class Contact extends BaseObject
                                'created'   => DateTimeFormat::utcNow(),
                                'url'       => $data['url'],
                                'nurl'      => Strings::normaliseLink($data['url']),
-                               'addr'      => defaults($data, 'addr', ''),
-                               'alias'     => defaults($data, 'alias', ''),
-                               'notify'    => defaults($data, 'notify', ''),
-                               'poll'      => defaults($data, 'poll', ''),
-                               'name'      => defaults($data, 'name', ''),
-                               'nick'      => defaults($data, 'nick', ''),
-                               'photo'     => defaults($data, 'photo', ''),
-                               'keywords'  => defaults($data, 'keywords', ''),
-                               'location'  => defaults($data, 'location', ''),
-                               'about'     => defaults($data, 'about', ''),
+                               'addr'      => $data['addr'] ?? '',
+                               'alias'     => $data['alias'] ?? '',
+                               'notify'    => $data['notify'] ?? '',
+                               'poll'      => $data['poll'] ?? '',
+                               'name'      => $data['name'] ?? '',
+                               'nick'      => $data['nick'] ?? '',
+                               'photo'     => $data['photo'] ?? '',
+                               'keywords'  => $data['keywords'] ?? '',
+                               'location'  => $data['location'] ?? '',
+                               'about'     => $data['about'] ?? '',
                                'network'   => $data['network'],
-                               'pubkey'    => defaults($data, 'pubkey', ''),
+                               'pubkey'    => $data['pubkey'] ?? '',
                                'rel'       => self::SHARING,
-                               'priority'  => defaults($data, 'priority', 0),
-                               'batch'     => defaults($data, 'batch', ''),
-                               'request'   => defaults($data, 'request', ''),
-                               'confirm'   => defaults($data, 'confirm', ''),
-                               'poco'      => defaults($data, 'poco', ''),
-                               'baseurl'   => defaults($data, 'baseurl', ''),
+                               'priority'  => $data['priority'] ?? 0,
+                               'batch'     => $data['batch'] ?? '',
+                               'request'   => $data['request'] ?? '',
+                               'confirm'   => $data['confirm'] ?? '',
+                               'poco'      => $data['poco'] ?? '',
+                               'baseurl'   => $data['baseurl'] ?? '',
                                'name-date' => DateTimeFormat::utcNow(),
                                'uri-date'  => DateTimeFormat::utcNow(),
                                'avatar-date' => DateTimeFormat::utcNow(),
@@ -1573,7 +1619,7 @@ class Contact extends BaseObject
                        $fields = ['addr', 'alias', 'name', 'nick', 'keywords', 'location', 'about', 'baseurl'];
 
                        foreach ($fields as $field) {
-                               $updated[$field] = defaults($data, $field, $contact[$field]);
+                               $updated[$field] = ($data[$field] ?? '') ?: $contact[$field];
                        }
 
                        if (($updated['addr'] != $contact['addr']) || (!empty($data['alias']) && ($data['alias'] != $contact['alias']))) {
@@ -1708,7 +1754,7 @@ class Contact extends BaseObject
                        $sql = "`item`.`uid` = ?";
                }
 
-               $contact_field = ($contact["contact-type"] == self::TYPE_COMMUNITY ? 'owner-id' : 'author-id');
+               $contact_field = ((($contact["contact-type"] == self::TYPE_COMMUNITY) || ($contact['network'] == Protocol::MAIL)) ? 'owner-id' : 'author-id');
 
                if ($thread_mode) {
                        $condition = ["`$contact_field` = ? AND `gravity` = ? AND " . $sql,
@@ -2021,9 +2067,8 @@ class Contact extends BaseObject
                        return true;
                }
 
-               // If Probe::uri fails the network code will be different (mostly "feed" or "unkn")
-               if (!in_array($ret['network'], Protocol::NATIVE_SUPPORT) ||
-                       (in_array($ret['network'], [Protocol::FEED, Protocol::PHANTOM]) && ($ret['network'] != $contact['network']))) {
+               // If Probe::uri fails the network code will be different ("feed" or "unkn")
+               if (in_array($ret['network'], [Protocol::FEED, Protocol::PHANTOM]) && ($ret['network'] != $contact['network'])) {
                        if ($force && ($uid == 0)) {
                                self::updateContact($id, $uid, $ret['url'], ['last-update' => $updated, 'failure_update' => $updated]);
                        }
@@ -2063,7 +2108,7 @@ class Contact extends BaseObject
                        }
                }
 
-               if ($ret['network'] != Protocol::FEED) {
+               if (!empty($ret['photo']) && ($ret['network'] != Protocol::FEED)) {
                        self::updateAvatar($ret['photo'], $uid, $id, $update || $force);
                }
 
@@ -2283,7 +2328,13 @@ class Contact extends BaseObject
 
                $hidden = (($protocol === Protocol::MAIL) ? 1 : 0);
 
-               $pending = in_array($protocol, [Protocol::ACTIVITYPUB]);
+               $pending = false;
+               if ($protocol == Protocol::ACTIVITYPUB) {
+                       $apcontact = APContact::getByURL($url, false);
+                       if (isset($apcontact['manually-approve'])) {
+                               $pending = (bool)$apcontact['manually-approve'];
+                       }                       
+               }
 
                if (in_array($protocol, [Protocol::MAIL, Protocol::DIASPORA, Protocol::ACTIVITYPUB])) {
                        $writeable = 1;
@@ -2351,7 +2402,7 @@ class Contact extends BaseObject
                        if (in_array($protocol, [Protocol::OSTATUS, Protocol::DFRN])) {
                                // create a follow slap
                                $item = [];
-                               $item['verb'] = ACTIVITY_FOLLOW;
+                               $item['verb'] = Activity::FOLLOW;
                                $item['follow'] = $contact["url"];
                                $item['body'] = '';
                                $item['title'] = '';
@@ -2454,9 +2505,9 @@ class Contact extends BaseObject
                        return false;
                }
 
-               $url = defaults($datarray, 'author-link', $pub_contact['url']);
+               $url = ($datarray['author-link'] ?? '') ?: $pub_contact['url'];
                $name = $pub_contact['name'];
-               $photo = defaults($pub_contact, 'avatar', $pub_contact["photo"]);
+               $photo = ($pub_contact['avatar'] ?? '') ?: $pub_contact["photo"];
                $nick = $pub_contact['nick'];
                $network = $pub_contact['network'];
 
@@ -2487,6 +2538,9 @@ class Contact extends BaseObject
                                                ['id' => $contact['id'], 'uid' => $importer['uid']]);
                        }
 
+                       // Ensure to always have the correct network type, independent from the connection request method
+                       self::updateFromProbe($contact['id'], '', true);
+
                        return true;
                } else {
                        // send email notification to owner?
@@ -2512,15 +2566,14 @@ class Contact extends BaseObject
                                'writable' => 1,
                        ]);
 
-                       $contact_record = [
-                               'id' => DBA::lastInsertId(),
-                               'network' => $network,
-                               'name' => $name,
-                               'url' => $url,
-                               'photo' => $photo
-                       ];
+                       $contact_id = DBA::lastInsertId();
+
+                       // Ensure to always have the correct network type, independent from the connection request method
+                       self::updateFromProbe($contact_id, '', true);
+
+                       Contact::updateAvatar($photo, $importer["uid"], $contact_id, true);
 
-                       Contact::updateAvatar($photo, $importer["uid"], $contact_record["id"], true);
+                       $contact_record = DBA::selectFirst('contact', ['id', 'network', 'name', 'url', 'photo'], ['id' => $contact_id]);
 
                        /// @TODO Encapsulate this into a function/method
                        $fields = ['uid', 'username', 'email', 'page-flags', 'notify-flags', 'language'];
@@ -2551,7 +2604,7 @@ class Contact extends BaseObject
                                                'source_name'  => ((strlen(stripslashes($contact_record['name']))) ? stripslashes($contact_record['name']) : L10n::t('[Name Withheld]')),
                                                'source_link'  => $contact_record['url'],
                                                'source_photo' => $contact_record['photo'],
-                                               'verb'         => ($sharing ? ACTIVITY_FRIEND : ACTIVITY_FOLLOW),
+                                               'verb'         => ($sharing ? Activity::FRIEND : Activity::FOLLOW),
                                                'otype'        => 'intro'
                                        ]);
                                }
@@ -2663,7 +2716,7 @@ class Contact extends BaseObject
         */
        public static function magicLink($contact_url, $url = '')
        {
-               if (!local_user() && !remote_user()) {
+               if (!Session::isAuthenticated()) {
                        return $url ?: $contact_url; // Equivalent to: ($url != '') ? $url : $contact_url;
                }
 
@@ -2709,7 +2762,7 @@ class Contact extends BaseObject
        {
                $destination = $url ?: $contact['url']; // Equivalent to ($url != '') ? $url : $contact['url'];
 
-               if ((!local_user() && !remote_user()) || ($contact['network'] != Protocol::DFRN)) {
+               if (!Session::isAuthenticated() || ($contact['network'] != Protocol::DFRN)) {
                        return $destination;
                }
 
@@ -2728,7 +2781,7 @@ class Contact extends BaseObject
 
                $redirect = 'redir/' . $contact['id'];
 
-               if ($url != '') {
+               if (($url != '') && !Strings::compareLink($contact['url'], $url)) {
                        $redirect .= '?url=' . $url;
                }