]> git.mxchange.org Git - friendica.git/blobdiff - src/Protocol/DFRN.php
Improve communication
[friendica.git] / src / Protocol / DFRN.php
index 1a2e8c56954006b88f7c46704e1f97a827bc493a..b207c3ca87cde7b4be9d705e936150c26a2c4cac 100644 (file)
@@ -17,15 +17,16 @@ use Friendica\Content\Text\HTML;
 use Friendica\Core\Addon;
 use Friendica\Core\Config;
 use Friendica\Core\L10n;
+use Friendica\Core\Protocol;
 use Friendica\Core\System;
 use Friendica\Database\DBA;
 use Friendica\Model\Contact;
+use Friendica\Model\Conversation;
 use Friendica\Model\Event;
 use Friendica\Model\GContact;
-use Friendica\Model\Group;
 use Friendica\Model\Item;
-use Friendica\Model\Profile;
 use Friendica\Model\PermissionSet;
+use Friendica\Model\Profile;
 use Friendica\Model\User;
 use Friendica\Object\Image;
 use Friendica\Util\Crypto;
@@ -51,6 +52,46 @@ class DFRN
        const REPLY = 1;                // Regular reply that is stored locally
        const REPLY_RC = 2;     // Reply that will be relayed
 
+       /**
+        * @brief Generates an array of contact and user for DFRN imports
+        *
+        * This array contains not only the receiver but also the sender of the message.
+        *
+        * @param integer $cid Contact id
+        * @param integer $uid User id
+        *
+        * @return array importer
+        */
+       public static function getImporter($cid, $uid = 0)
+       {
+               $condition = ['id' => $cid, 'blocked' => false, 'pending' => false];
+               $contact = DBA::selectFirst('contact', [], $condition);
+               if (!DBA::isResult($contact)) {
+                       return [];
+               }
+
+               $contact['cpubkey'] = $contact['pubkey'];
+               $contact['cprvkey'] = $contact['prvkey'];
+               $contact['senderName'] = $contact['name'];
+
+               if ($uid != 0) {
+                       $condition = ['uid' => $uid, 'account_expired' => false, 'account_removed' => false];
+                       $user = DBA::selectFirst('user', [], $condition);
+                       if (!DBA::isResult($user)) {
+                               return [];
+                       }
+
+                       $user['importer_uid'] = $user['uid'];
+                       $user['uprvkey'] = $user['prvkey'];
+               } else {
+                       $user = ['importer_uid' => 0, 'uprvkey' => '', 'timezone' => 'UTC',
+                               'nickname' => '', 'sprvkey' => '', 'spubkey' => '',
+                               'page-flags' => 0, 'account-type' => 0, 'prvnets' => 0];
+               }
+
+               return array_merge($contact, $user);
+       }
+
        /**
         * @brief Generates the atom entries for delivery.php
         *
@@ -272,7 +313,7 @@ class DFRN
 
                foreach ($items as $item) {
                        // prevent private email from leaking.
-                       if ($item['network'] == NETWORK_MAIL) {
+                       if ($item['network'] == Protocol::MAIL) {
                                continue;
                        }
 
@@ -1055,13 +1096,10 @@ class DFRN
                }
 
                foreach ($mentioned as $mention) {
-                       $r = q(
-                               "SELECT `forum`, `prv` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s'",
-                               intval($owner["uid"]),
-                               DBA::escape(normalise_link($mention))
-                       );
+                       $condition = ['uid' => $owner["uid"], 'nurl' => normalise_link($mention)];
+                       $contact = DBA::selectFirst('contact', ['forum', 'prv'], $condition);
 
-                       if (DBA::isResult($r) && ($r[0]["forum"] || $r[0]["prv"])) {
+                       if (DBA::isResult($contact) && ($contact["forum"] || $contact["prv"])) {
                                XML::addElement(
                                        $doc,
                                        $entry,
@@ -1131,10 +1169,12 @@ class DFRN
                $a = get_app();
 
                // At first try the Diaspora transport layer
-               $ret = self::transmit($owner, $contact, $atom);
-               if ($ret >= 200) {
-                       logger('Delivery via Diaspora transport layer was successful with status ' . $ret);
-                       return $ret;
+               if (!$dissolve) {
+                       $ret = self::transmit($owner, $contact, $atom);
+                       if ($ret >= 200) {
+                               logger('Delivery via Diaspora transport layer was successful with status ' . $ret);
+                               return $ret;
+                       }
                }
 
                $idtosend = $orig_id = (($contact['dfrn-id']) ? $contact['dfrn-id'] : $contact['issued-id']);
@@ -1231,14 +1271,11 @@ class DFRN
                $final_dfrn_id = '';
 
                if ($perm) {
-                       if ((($perm == 'rw') && (! intval($contact['writable'])))
-                               || (($perm == 'r') && (intval($contact['writable'])))
+                       if ((($perm == 'rw') && !intval($contact['writable']))
+                               || (($perm == 'r') && intval($contact['writable']))
                        ) {
-                               q(
-                                       "update contact set writable = %d where id = %d",
-                                       intval(($perm == 'rw') ? 1 : 0),
-                                       intval($contact['id'])
-                               );
+                               DBA::update('contact', ['writable' => ($perm == 'rw')], ['id' => $contact['id']]);
+
                                $contact['writable'] = (string) 1 - intval($contact['writable']);
                        }
                }
@@ -1296,6 +1333,7 @@ class DFRN
                                        $key = openssl_random_pseudo_bytes(16);
                                        $data = self::aesEncrypt($postvars['data'], $key);
                                        break;
+
                                default:
                                        logger("rino: invalid requested version '$rino_remote_version'");
                                        Contact::markForArchival($contact);
@@ -1479,15 +1517,9 @@ class DFRN
        private static function birthdayEvent($contact, $birthday)
        {
                // Check for duplicates
-               $r = q(
-                       "SELECT `id` FROM `event` WHERE `uid` = %d AND `cid` = %d AND `start` = '%s' AND `type` = '%s' LIMIT 1",
-                       intval($contact['uid']),
-                       intval($contact['id']),
-                       DBA::escape(DateTimeFormat::utc($birthday)),
-                       DBA::escape('birthday')
-               );
-
-               if (DBA::isResult($r)) {
+               $condition = ['uid' => $contact['uid'], 'cid' => $contact['id'],
+                       'start' => DateTimeFormat::utc($birthday), 'type' => 'birthday'];
+               if (DBA::exists('event', $condition)) {
                        return;
                }
 
@@ -1533,7 +1565,7 @@ class DFRN
                $fields = ['id', 'uid', 'url', 'network', 'avatar-date', 'avatar', 'name-date', 'uri-date', 'addr',
                        'name', 'nick', 'about', 'location', 'keywords', 'xmpp', 'bdyear', 'bd', 'hidden', 'contact-type'];
                $condition = ["`uid` = ? AND `nurl` = ? AND `network` != ?",
-                       $importer["importer_uid"], normalise_link($author["link"]), NETWORK_STATUSNET];
+                       $importer["importer_uid"], normalise_link($author["link"]), Protocol::STATUSNET];
                $contact_old = DBA::selectFirst('contact', $fields, $condition);
 
                if (DBA::isResult($contact_old)) {
@@ -1579,6 +1611,20 @@ class DFRN
                        $author["avatar"] = current($avatarlist);
                }
 
+               if (empty($author['avatar']) && !empty($author['link'])) {
+                       $cid = Contact::getIdForURL($author['link'], 0);
+                       if (!empty($cid)) {
+                               $contact = DBA::selectFirst('contact', ['avatar'], ['id' => $cid]);
+                               if (DBA::isResult($contact)) {
+                                       $author['avatar'] = $contact['avatar'];
+                               }
+                       }
+               }
+
+               if (empty($author['avatar'])) {
+                       logger('Empty author: ' . $xml);
+               }
+
                if (DBA::isResult($contact_old) && !$onlyfetch) {
                        logger("Check if contact details for contact " . $contact_old["id"] . " (" . $contact_old["nick"] . ") have to be updated.", LOGGER_DEBUG);
 
@@ -1708,6 +1754,10 @@ class DFRN
                        // Update check for this field has to be done differently
                        $datefields = ["name-date", "uri-date"];
                        foreach ($datefields as $field) {
+                               // The date fields arrives as '2018-07-17T10:44:45Z' - the database return '2018-07-17 10:44:45'
+                               // The fields have to be in the same format to be comparable, since strtotime does add timezones.
+                               $contact[$field] = DateTimeFormat::utc($contact[$field]);
+
                                if (strtotime($contact[$field]) > strtotime($contact_old[$field])) {
                                        logger("Difference for contact " . $contact["id"] . " in field '" . $field . "'. New value: '" . $contact[$field] . "', old value '" . $contact_old[$field] . "'", LOGGER_DEBUG);
                                        $update = true;
@@ -1899,13 +1949,6 @@ class DFRN
 
                // Does our member already have a friend matching this description?
 
-               $r = q(
-                       "SELECT `id` FROM `contact` WHERE `name` = '%s' AND `nurl` = '%s' AND `uid` = %d LIMIT 1",
-                       DBA::escape($suggest["name"]),
-                       DBA::escape(normalise_link($suggest["url"])),
-                       intval($suggest["uid"])
-               );
-
                /*
                 * The valid result means the friend we're about to send a friend
                 * suggestion already has them in their contact, which means no further
@@ -1913,37 +1956,29 @@ class DFRN
                 *
                 * @see https://github.com/friendica/friendica/pull/3254#discussion_r107315246
                 */
-               if (DBA::isResult($r)) {
+               $condition = ['name' => $suggest["name"], 'nurl' => normalise_link($suggest["url"]),
+                       'uid' => $suggest["uid"]];
+               if (DBA::exists('contact', $condition)) {
                        return false;
                }
 
                // Do we already have an fcontact record for this person?
 
                $fid = 0;
-               $r = q(
-                       "SELECT `id` FROM `fcontact` WHERE `url` = '%s' AND `name` = '%s' AND `request` = '%s' LIMIT 1",
-                       DBA::escape($suggest["url"]),
-                       DBA::escape($suggest["name"]),
-                       DBA::escape($suggest["request"])
-               );
-               if (DBA::isResult($r)) {
-                       $fid = $r[0]["id"];
+               $condition = ['url' => $suggest["url"], 'name' => $suggest["name"], 'request' => $suggest["request"]];
+               $fcontact = DBA::selectFirst('fcontact', ['id'], $condition);
+               if (DBA::isResult($fcontact)) {
+                       $fid = $fcontact["id"];
 
-                       // OK, we do. Do we already have an introduction for this person ?
-                       $r = q(
-                               "SELECT `id` FROM `intro` WHERE `uid` = %d AND `fid` = %d LIMIT 1",
-                               intval($suggest["uid"]),
-                               intval($fid)
-                       );
-
-                       /*
-                        * The valid result means the friend we're about to send a friend
-                        * suggestion already has them in their contact, which means no further
-                        * action is required.
-                        *
-                        * @see https://github.com/friendica/friendica/pull/3254#discussion_r107315246
-                        */
-                       if (DBA::isResult($r)) {
+                       // OK, we do. Do we already have an introduction for this person?
+                       if (DBA::exists('intro', ['uid' => $suggest["uid"], 'fid' => $fid])) {
+                               /*
+                                * The valid result means the friend we're about to send a friend
+                                * suggestion already has them in their contact, which means no further
+                                * action is required.
+                                *
+                                * @see https://github.com/friendica/friendica/pull/3254#discussion_r107315246
+                                */
                                return false;
                        }
                }
@@ -1956,18 +1991,15 @@ class DFRN
                                DBA::escape($suggest["request"])
                        );
                }
-               $r = q(
-                       "SELECT `id` FROM `fcontact` WHERE `url` = '%s' AND `name` = '%s' AND `request` = '%s' LIMIT 1",
-                       DBA::escape($suggest["url"]),
-                       DBA::escape($suggest["name"]),
-                       DBA::escape($suggest["request"])
-               );
+
+               $condition = ['url' => $suggest["url"], 'name' => $suggest["name"], 'request' => $suggest["request"]];
+               $fcontact = DBA::selectFirst('fcontact', ['id'], $condition);
 
                /*
                 * If no record in fcontact is found, below INSERT statement will not
                 * link an introduction to it.
                 */
-               if (!DBA::isResult($r)) {
+               if (!DBA::isResult($fcontact)) {
                        // Database record did not get created. Quietly give up.
                        killme();
                }
@@ -2223,6 +2255,11 @@ class DFRN
                        if ($Blink && link_compare($Blink, System::baseUrl() . "/profile/" . $importer["nickname"])) {
                                $author = DBA::selectFirst('contact', ['name', 'thumb', 'url'], ['id' => $item['author-id']]);
 
+                               $item['id'] = $posted_id;
+
+                               $parent = Item::selectFirst(['id'], ['uri' => $item['parent-uri'], 'uid' => $importer["importer_uid"]]);
+                               $item["parent"] = $parent['id'];
+
                                // send a notification
                                notification(
                                        [
@@ -2373,8 +2410,11 @@ class DFRN
                                                break;
                                        case "enclosure":
                                                $enclosure = $href;
-                                               if (strlen($item["attach"])) {
+
+                                               if (!empty($item["attach"])) {
                                                        $item["attach"] .= ",";
+                                               } else {
+                                                       $item["attach"] = "";
                                                }
 
                                                $item["attach"] .= '[attach]href="' . $href . '" length="' . $length . '" type="' . $type . '" title="' . $title . '"[/attach]';
@@ -2401,7 +2441,7 @@ class DFRN
 
                $item = $header;
 
-               $item["protocol"] = PROTOCOL_DFRN;
+               $item["protocol"] = Conversation::PARCEL_DFRN;
 
                $item["source"] = $xml;
 
@@ -2420,7 +2460,7 @@ class DFRN
                }
 
                // Fetch the owner
-               $owner = self::fetchauthor($xpath, $entry, $importer, "dfrn:owner", true);
+               $owner = self::fetchauthor($xpath, $entry, $importer, "dfrn:owner", true, $xml);
 
                $owner_unknown = (isset($owner["contact-unknown"]) && $owner["contact-unknown"]);
 
@@ -2430,7 +2470,7 @@ class DFRN
                $item["owner-id"] = Contact::getIdForURL($owner["link"], 0);
 
                // fetch the author
-               $author = self::fetchauthor($xpath, $entry, $importer, "atom:author", true);
+               $author = self::fetchauthor($xpath, $entry, $importer, "atom:author", true, $xml);
 
                $item["author-name"] = $author["name"];
                $item["author-link"] = $author["link"];
@@ -2635,13 +2675,10 @@ class DFRN
                                        $ev["guid"]    = $item["guid"];
                                        $ev["plink"]   = $item["plink"];
 
-                                       $r = q(
-                                               "SELECT `id` FROM `event` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
-                                               DBA::escape($item["uri"]),
-                                               intval($importer["importer_uid"])
-                                       );
-                                       if (DBA::isResult($r)) {
-                                               $ev["id"] = $r[0]["id"];
+                                       $condition = ['uri' => $item["uri"], 'uid' => $importer["importer_uid"]];
+                                       $event = DBA::selectFirst('event', ['id'], $condition);
+                                       if (DBA::isResult($event)) {
+                                               $ev["id"] = $event["id"];
                                        }
 
                                        $event_id = Event::store($ev);
@@ -2822,7 +2859,7 @@ class DFRN
 
                $header = [];
                $header["uid"] = $importer["importer_uid"];
-               $header["network"] = NETWORK_DFRN;
+               $header["network"] = Protocol::DFRN;
                $header["wall"] = 0;
                $header["origin"] = 0;
                $header["contact-id"] = $importer["id"];
@@ -2956,7 +2993,7 @@ class DFRN
                        $r = q("SELECT * FROM contact WHERE nick = '%s'
                                        AND network = '%s' AND uid = %d  AND url LIKE '%%%s%%' LIMIT 1",
                                DBA::escape($contact_nick),
-                               DBA::escape(NETWORK_DFRN),
+                               DBA::escape(Protocol::DFRN),
                                intval(local_user()),
                                DBA::escape($baseurl)
                        );
@@ -3024,23 +3061,21 @@ class DFRN
                        return false;
                }
 
-               $u = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
-                       intval($uid)
-               );
-               if (!DBA::isResult($u)) {
+               $user = DBA::selectFirst('user', ['page-flags', 'nickname'], ['uid' => $uid]);
+               if (!DBA::isResult($user)) {
                        return false;
                }
 
-               $community_page = ($u[0]['page-flags'] == Contact::PAGE_COMMUNITY);
-               $prvgroup = ($u[0]['page-flags'] == Contact::PAGE_PRVGROUP);
+               $community_page = ($user['page-flags'] == Contact::PAGE_COMMUNITY);
+               $prvgroup = ($user['page-flags'] == Contact::PAGE_PRVGROUP);
 
-               $link = normalise_link(System::baseUrl() . '/profile/' . $u[0]['nickname']);
+               $link = normalise_link(System::baseUrl() . '/profile/' . $user['nickname']);
 
                /*
                 * Diaspora uses their own hardwired link URL in @-tags
                 * instead of the one we supply with webfinger
                 */
-               $dlink = normalise_link(System::baseUrl() . '/u/' . $u[0]['nickname']);
+               $dlink = normalise_link(System::baseUrl() . '/u/' . $user['nickname']);
 
                $cnt = preg_match_all('/[\@\!]\[url\=(.*?)\](.*?)\[\/url\]/ism', $item['body'], $matches, PREG_SET_ORDER);
                if ($cnt) {