X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FProtocol%2FDiaspora.php;h=7bf0acbc49852a627d1301fed09dacdf9a988d79;hb=8a0c568fe103e2e7ef832a623bfb6be6c54e300a;hp=657009e7764fef624f9500b822fca1e94b4fa91b;hpb=5276c28a78e188eb4ec8dcbf87a4dd1ac193c8d7;p=friendica.git diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 657009e776..7bf0acbc49 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -10,6 +10,7 @@ namespace Friendica\Protocol; +use Friendica\Content\Feature; use Friendica\Content\Text\BBCode; use Friendica\Content\Text\Markdown; use Friendica\Core\Cache; @@ -26,8 +27,8 @@ use Friendica\Model\Conversation; use Friendica\Model\GContact; use Friendica\Model\Group; use Friendica\Model\Item; +use Friendica\Model\Mail; use Friendica\Model\Profile; -use Friendica\Model\Queue; use Friendica\Model\User; use Friendica\Network\Probe; use Friendica\Util\Crypto; @@ -38,9 +39,6 @@ use Friendica\Util\Strings; use Friendica\Util\XML; use SimpleXMLElement; -require_once 'include/dba.php'; -require_once 'include/items.php'; - /** * @brief This class contain functions to create and send Diaspora XML files * @@ -56,6 +54,7 @@ class Diaspora * @param array $contacts The previously fetched contacts * * @return array of relay servers + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ public static function relayList($item_id, array $contacts = []) { @@ -141,14 +140,15 @@ class Diaspora * * @param string $server_url The url of the server * @return array with the contact + * @throws \Exception */ private static function getRelayContact($server_url) { $fields = ['batch', 'id', 'name', 'network', 'archive', 'blocked']; // Fetch the relay contact - $condition = ['uid' => 0, 'nurl' => normalise_link($server_url), - 'contact-type' => Contact::ACCOUNT_TYPE_RELAY]; + $condition = ['uid' => 0, 'nurl' => Strings::normaliseLink($server_url), + 'contact-type' => Contact::TYPE_RELAY]; $contact = DBA::selectFirst('contact', $fields, $condition); if (DBA::isResult($contact)) { @@ -172,8 +172,9 @@ class Diaspora /** * @brief Update or insert a relay contact * - * @param string $server_url The url of the server - * @param array $network_fields Optional network specific fields + * @param string $server_url The url of the server + * @param array $network_fields Optional network specific fields + * @throws \Exception */ public static function setRelayContact($server_url, array $network_fields = []) { @@ -186,8 +187,8 @@ class Diaspora $fields = array_merge($fields, $network_fields); - $condition = ['uid' => 0, 'nurl' => normalise_link($server_url), - 'contact-type' => Contact::ACCOUNT_TYPE_RELAY]; + $condition = ['uid' => 0, 'nurl' => Strings::normaliseLink($server_url), + 'contact-type' => Contact::TYPE_RELAY]; if (DBA::exists('contact', $condition)) { unset($fields['created']); @@ -207,10 +208,11 @@ class Diaspora * @param array $contacts The previously fetched contacts * * @return array of relay servers + * @throws \Exception */ public static function participantsForThread($thread, array $contacts) { - $r = DBA::p("SELECT `contact`.`batch`, `contact`.`id`, `contact`.`name`, `contact`.`network`, + $r = DBA::p("SELECT `contact`.`batch`, `contact`.`id`, `contact`.`name`, `contact`.`network`, `contact`.`protocol`, `fcontact`.`batch` AS `fbatch`, `fcontact`.`network` AS `fnetwork` FROM `participation` INNER JOIN `contact` ON `contact`.`id` = `participation`.`cid` INNER JOIN `fcontact` ON `fcontact`.`id` = `participation`.`fid` @@ -222,6 +224,10 @@ class Diaspora } unset($contact['fnetwork']); + if (empty($contact['protocol'])) { + $contact['protocol'] = $contact['network']; + } + if (empty($contact['batch']) && !empty($contact['fbatch'])) { $contact['batch'] = $contact['fbatch']; } @@ -253,6 +259,7 @@ class Diaspora * @param integer $level This value is only set inside this function to avoid endless loops * * @return string the repaired signature + * @throws \Exception */ private static function repairSignature($signature, $handle = "", $level = 1) { @@ -279,6 +286,8 @@ class Diaspora * @param string $envelope The magic envelope * * @return string verified data + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ private static function verifyMagicEnvelope($envelope) { @@ -375,6 +384,8 @@ class Diaspora * 'message' -> decoded Diaspora XML message * 'author' -> author diaspora handle * 'key' -> author public key (converted to pkcs#8) + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ public static function decodeRaw(array $importer, $raw, $no_exit = false) { @@ -394,7 +405,7 @@ class Diaspora if ($no_exit) { return false; } else { - System::httpExit(400); + throw new \Friendica\Network\HTTPException\BadRequestException(); } } @@ -413,7 +424,7 @@ class Diaspora if ($no_exit) { return false; } else { - System::httpExit(400); + throw new \Friendica\Network\HTTPException\BadRequestException(); } } @@ -439,7 +450,7 @@ class Diaspora if ($no_exit) { return false; } else { - System::httpExit(400); + throw new \Friendica\Network\HTTPException\BadRequestException(); } } @@ -449,7 +460,7 @@ class Diaspora if ($no_exit) { return false; } else { - System::httpExit(400); + throw new \Friendica\Network\HTTPException\BadRequestException(); } } @@ -459,7 +470,7 @@ class Diaspora if ($no_exit) { return false; } else { - System::httpExit(400); + throw new \Friendica\Network\HTTPException\BadRequestException(); } } @@ -478,6 +489,8 @@ class Diaspora * 'message' -> decoded Diaspora XML message * 'author' -> author diaspora handle * 'key' -> author public key (converted to pkcs#8) + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ public static function decode(array $importer, $xml) { @@ -542,7 +555,7 @@ class Diaspora if (!$base) { Logger::log('unable to locate salmon data in xml'); - System::httpExit(400); + throw new \Friendica\Network\HTTPException\BadRequestException(); } @@ -580,7 +593,7 @@ class Diaspora if (!$author_link) { Logger::log('Could not retrieve author URI.'); - System::httpExit(400); + throw new \Friendica\Network\HTTPException\BadRequestException(); } // Once we have the author URI, go to the web and try to find their public key // (first this will look it up locally if it is in the fcontact cache) @@ -591,14 +604,14 @@ class Diaspora if (!$key) { Logger::log('Could not retrieve author key.'); - System::httpExit(400); + throw new \Friendica\Network\HTTPException\BadRequestException(); } $verify = Crypto::rsaVerify($signed_data, $signature, $key); if (!$verify) { Logger::log('Message did not verify. Discarding.'); - System::httpExit(400); + throw new \Friendica\Network\HTTPException\BadRequestException(); } Logger::log('Message verified.'); @@ -615,6 +628,8 @@ class Diaspora * @param array $msg The post that will be dispatched * * @return int The message id of the generated message, "true" or "false" if there was an error + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ public static function dispatchPublic($msg) { @@ -629,7 +644,7 @@ class Diaspora return false; } - $importer = ["uid" => 0, "page-flags" => Contact::PAGE_FREELOVE]; + $importer = ["uid" => 0, "page-flags" => User::PAGE_FLAGS_FREELOVE]; $success = self::dispatch($importer, $msg, $fields); return $success; @@ -638,13 +653,15 @@ class Diaspora /** * @brief Dispatches the different message types to the different functions * - * @param array $importer Array of the importer user - * @param array $msg The post that will be dispatched - * @param object $fields SimpleXML object that contains the message + * @param array $importer Array of the importer user + * @param array $msg The post that will be dispatched + * @param SimpleXMLElement $fields SimpleXML object that contains the message * * @return int The message id of the generated message, "true" or "false" if there was an error + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ - public static function dispatch(array $importer, $msg, $fields = null) + public static function dispatch(array $importer, $msg, SimpleXMLElement $fields = null) { // The sender is the handle of the contact that sent the message. // This will often be different with relayed messages (for example "like" and "comment") @@ -736,8 +753,6 @@ class Diaspora Logger::log("Unknown message type ".$type); return false; } - - return true; } /** @@ -748,7 +763,9 @@ class Diaspora * * @param array $msg Array with the XML, the sender handle and the sender signature * - * @return bool|array If the posting is valid then an array with an SimpleXML object is returned + * @return bool|SimpleXMLElement If the posting is valid then an array with an SimpleXML object is returned + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ private static function validPosting($msg) { @@ -897,6 +914,8 @@ class Diaspora * @param string $handle The handle * * @return string The public key + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ private static function key($handle) { @@ -918,6 +937,8 @@ class Diaspora * @param string $handle The handle * * @return array the queried data + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ public static function personByHandle($handle) { @@ -925,7 +946,7 @@ class Diaspora $person = DBA::selectFirst('fcontact', [], ['network' => Protocol::DIASPORA, 'addr' => $handle]); if (DBA::isResult($person)) { - Logger::log("In cache " . print_r($person, true), Logger::DEBUG); + Logger::debug("In cache " . print_r($person, true)); // update record occasionally so it doesn't get stale $d = strtotime($person["updated"]." +00:00"); @@ -963,6 +984,7 @@ class Diaspora * @brief Updates the fcontact table * * @param array $arr The fcontact data + * @throws \Exception */ private static function updateFContact($arr) { @@ -986,6 +1008,7 @@ class Diaspora * @param int $pcontact_id The id in the contact table (Used for the public contact) * * @return string the handle + * @throws \Exception */ private static function handleFromContact($contact_id, $pcontact_id = 0) { @@ -1032,6 +1055,7 @@ class Diaspora * @param mixed $fcontact_guid Hexadecimal string guid * * @return string the contact url or null + * @throws \Exception */ public static function urlFromContactGuid($fcontact_guid) { @@ -1053,12 +1077,14 @@ class Diaspora /** * @brief Get a contact id for a given handle * - * @todo Move to Friendica\Model\Contact + * @todo Move to Friendica\Model\Contact * * @param int $uid The user id * @param string $handle The handle in the format user@domain.tld * - * @return int Contact id + * @return array Contact data + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ private static function contactByHandle($uid, $handle) { @@ -1102,7 +1128,7 @@ class Diaspora */ // It is deactivated by now, due to side effects. See issue https://github.com/friendica/friendica/pull/4033 // It is not removed by now. Possibly the code is needed? - //if (!$is_comment && $contact["rel"] == Contact::FOLLOWER && in_array($importer["page-flags"], array(Contact::PAGE_FREELOVE))) { + //if (!$is_comment && $contact["rel"] == Contact::FOLLOWER && in_array($importer["page-flags"], array(User::PAGE_FLAGS_FREELOVE))) { // DBA::update( // 'contact', // array('rel' => Contact::FRIEND, 'writable' => true), @@ -1113,8 +1139,11 @@ class Diaspora // Logger::log("defining user ".$contact["nick"]." as friend"); //} - // We don't seem to like that person - if ($contact["blocked"]) { + // Contact server is blocked + if (Network::isUrlBlocked($contact['url'])) { + return false; + // We don't seem to like that person + } elseif ($contact["blocked"]) { // Maybe blocked, don't accept. return false; // We are following this person? @@ -1122,7 +1151,7 @@ class Diaspora // Yes, then it is fine. return true; // Is it a post to a community? - } elseif (($contact["rel"] == Contact::FOLLOWER) && in_array($importer["page-flags"], [Contact::PAGE_COMMUNITY, Contact::PAGE_PRVGROUP])) { + } elseif (($contact["rel"] == Contact::FOLLOWER) && in_array($importer["page-flags"], [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP])) { // That's good return true; // Is the message a global user or a comment? @@ -1142,6 +1171,7 @@ class Diaspora * @param bool $is_comment Is the check for a comment? * * @return array The contact data + * @throws \Exception */ private static function allowedContactByHandle(array $importer, $handle, $is_comment = false) { @@ -1172,6 +1202,7 @@ class Diaspora * @param string $guid The guid of the message * * @return int|bool message id if the message already was stored into the system - or false. + * @throws \Exception */ private static function messageExists($uid, $guid) { @@ -1252,6 +1283,8 @@ class Diaspora * @param array $match array containing a link that has to be checked for a message link * @param array $item The item array * @return void + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ private static function fetchGuidSub($match, $item) { @@ -1268,6 +1301,8 @@ class Diaspora * @param int $uid The user id of the user * * @return int the message id of the stored message or false + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ private static function storeByGuid($guid, $server, $uid = 0) { @@ -1304,6 +1339,7 @@ class Diaspora * 'message' => The message XML * 'author' => The author handle * 'key' => The public key of the author + * @throws \Exception */ private static function message($guid, $server, $level = 0) { @@ -1329,15 +1365,8 @@ class Diaspora $x = false; } - // This will work for older Diaspora and Friendica servers if (!$x) { - $source_url = $server."/p/".urlencode($guid).".xml"; - Logger::log("Fetch post from ".$source_url, Logger::DEBUG); - - $x = Network::fetchUrl($source_url); - if (!$x) { - return false; - } + return false; } $source_xml = XML::parseString($x); @@ -1387,6 +1416,7 @@ class Diaspora * @param array $contact The contact of the item owner * * @return array the item record + * @throws \Exception */ private static function parentItem($uid, $guid, $author, array $contact) { @@ -1431,10 +1461,11 @@ class Diaspora * @return array * 'cid' => contact id * 'network' => network type + * @throws \Exception */ private static function authorContactByUrl($def_contact, $person, $uid) { - $condition = ['nurl' => normalise_link($person["url"]), 'uid' => $uid]; + $condition = ['nurl' => Strings::normaliseLink($person["url"]), 'uid' => $uid]; $contact = DBA::selectFirst('contact', ['id', 'network'], $condition); if (DBA::isResult($contact)) { $cid = $contact["id"]; @@ -1467,6 +1498,8 @@ class Diaspora * @param string $parent_guid optional parent guid * * @return string the post link + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ private static function plink($addr, $guid, $parent_guid = '') { @@ -1503,12 +1536,14 @@ class Diaspora * @param object $data The message object * * @return bool Success + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ private static function receiveAccountMigration(array $importer, $data) { - $old_handle = Strings::removeTags(XML::unescape($data->author)); - $new_handle = Strings::removeTags(XML::unescape($data->profile->author)); - $signature = Strings::removeTags(XML::unescape($data->signature)); + $old_handle = Strings::escapeTags(XML::unescape($data->author)); + $new_handle = Strings::escapeTags(XML::unescape($data->profile->author)); + $signature = Strings::escapeTags(XML::unescape($data->signature)); $contact = self::contactByHandle($importer["uid"], $old_handle); if (!$contact) { @@ -1536,7 +1571,7 @@ class Diaspora return false; } - $fields = ['url' => $data['url'], 'nurl' => normalise_link($data['url']), + $fields = ['url' => $data['url'], 'nurl' => Strings::normaliseLink($data['url']), 'name' => $data['name'], 'nick' => $data['nick'], 'addr' => $data['addr'], 'batch' => $data['batch'], 'notify' => $data['notify'], 'poll' => $data['poll'], @@ -1544,7 +1579,7 @@ class Diaspora DBA::update('contact', $fields, ['addr' => $old_handle]); - $fields = ['url' => $data['url'], 'nurl' => normalise_link($data['url']), + $fields = ['url' => $data['url'], 'nurl' => Strings::normaliseLink($data['url']), 'name' => $data['name'], 'nick' => $data['nick'], 'addr' => $data['addr'], 'connect' => $data['addr'], 'notify' => $data['notify'], 'photo' => $data['photo'], @@ -1560,13 +1595,14 @@ class Diaspora /** * @brief Processes an account deletion * - * @param object $data The message object + * @param object $data The message object * * @return bool Success + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ private static function receiveAccountDeletion($data) { - $author = Strings::removeTags(XML::unescape($data->author)); + $author = Strings::escapeTags(XML::unescape($data->author)); $contacts = DBA::select('contact', ['id'], ['addr' => $author]); while ($contact = DBA::fetch($contacts)) { @@ -1588,6 +1624,8 @@ class Diaspora * @param boolean $onlyfound Only return uri when found in the database * * @return string The constructed uri or the one from our database + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ private static function getUriFromGuid($author, $guid, $onlyfound = false) { @@ -1614,6 +1652,7 @@ class Diaspora * @param string $uid Author handle * * @return string The post guid + * @throws \Exception */ private static function getGuidFromUri($uri, $uid) { @@ -1631,6 +1670,7 @@ class Diaspora * @param string $guid The guid of the item * * @return array|boolean the origin owner of that post - or false + * @throws \Exception */ private static function importerForGuid($guid) { @@ -1654,22 +1694,24 @@ class Diaspora * @param string $xml The original XML of the message * * @return int The message id of the generated comment or "false" if there was an error + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ private static function receiveComment(array $importer, $sender, $data, $xml) { - $author = Strings::removeTags(XML::unescape($data->author)); - $guid = Strings::removeTags(XML::unescape($data->guid)); - $parent_guid = Strings::removeTags(XML::unescape($data->parent_guid)); + $author = Strings::escapeTags(XML::unescape($data->author)); + $guid = Strings::escapeTags(XML::unescape($data->guid)); + $parent_guid = Strings::escapeTags(XML::unescape($data->parent_guid)); $text = XML::unescape($data->text); if (isset($data->created_at)) { - $created_at = DateTimeFormat::utc(Strings::removeTags(XML::unescape($data->created_at))); + $created_at = DateTimeFormat::utc(Strings::escapeTags(XML::unescape($data->created_at))); } else { $created_at = DateTimeFormat::utcNow(); } if (isset($data->thread_parent_guid)) { - $thread_parent_guid = Strings::removeTags(XML::unescape($data->thread_parent_guid)); + $thread_parent_guid = Strings::escapeTags(XML::unescape($data->thread_parent_guid)); $thr_uri = self::getUriFromGuid("", $thread_parent_guid, true); } else { $thr_uri = ""; @@ -1771,27 +1813,28 @@ class Diaspora * @param array $conversation The conversation record to which this message belongs * * @return bool "true" if it was successful + * @throws \Exception */ private static function receiveConversationMessage(array $importer, array $contact, $data, $msg, $mesg, $conversation) { - $author = Strings::removeTags(XML::unescape($data->author)); - $guid = Strings::removeTags(XML::unescape($data->guid)); - $subject = Strings::removeTags(XML::unescape($data->subject)); + $author = Strings::escapeTags(XML::unescape($data->author)); + $guid = Strings::escapeTags(XML::unescape($data->guid)); + $subject = Strings::escapeTags(XML::unescape($data->subject)); // "diaspora_handle" is the element name from the old version // "author" is the element name from the new version if ($mesg->author) { - $msg_author = Strings::removeTags(XML::unescape($mesg->author)); + $msg_author = Strings::escapeTags(XML::unescape($mesg->author)); } elseif ($mesg->diaspora_handle) { - $msg_author = Strings::removeTags(XML::unescape($mesg->diaspora_handle)); + $msg_author = Strings::escapeTags(XML::unescape($mesg->diaspora_handle)); } else { return false; } - $msg_guid = Strings::removeTags(XML::unescape($mesg->guid)); - $msg_conversation_guid = Strings::removeTags(XML::unescape($mesg->conversation_guid)); + $msg_guid = Strings::escapeTags(XML::unescape($mesg->guid)); + $msg_conversation_guid = Strings::escapeTags(XML::unescape($mesg->conversation_guid)); $msg_text = XML::unescape($mesg->text); - $msg_created_at = DateTimeFormat::utc(Strings::removeTags(XML::unescape($mesg->created_at))); + $msg_created_at = DateTimeFormat::utc(Strings::escapeTags(XML::unescape($mesg->created_at))); if ($msg_conversation_guid != $guid) { Logger::log("message conversation guid does not belong to the current conversation."); @@ -1803,52 +1846,20 @@ class Diaspora $person = self::personByHandle($msg_author); - DBA::lock('mail'); - - if (DBA::exists('mail', ['guid' => $msg_guid, 'uid' => $importer["uid"]])) { - Logger::log("duplicate message already delivered.", Logger::DEBUG); - return false; - } - - q( - "INSERT INTO `mail` (`uid`, `guid`, `convid`, `from-name`,`from-photo`,`from-url`,`contact-id`,`title`,`body`,`seen`,`reply`,`uri`,`parent-uri`,`created`) - VALUES (%d, '%s', %d, '%s', '%s', '%s', %d, '%s', '%s', %d, %d, '%s','%s','%s')", - intval($importer["uid"]), - DBA::escape($msg_guid), - intval($conversation["id"]), - DBA::escape($person["name"]), - DBA::escape($person["photo"]), - DBA::escape($person["url"]), - intval($contact["id"]), - DBA::escape($subject), - DBA::escape($body), - 0, - 0, - DBA::escape($message_uri), - DBA::escape($author.":".$guid), - DBA::escape($msg_created_at) - ); - - DBA::unlock(); - - DBA::update('conv', ['updated' => DateTimeFormat::utcNow()], ['id' => $conversation["id"]]); - - notification( - [ - "type" => NOTIFY_MAIL, - "notify_flags" => $importer["notify-flags"], - "language" => $importer["language"], - "to_name" => $importer["username"], - "to_email" => $importer["email"], - "uid" =>$importer["uid"], - "item" => ["id" => $conversation["id"], "title" => $subject, "subject" => $subject, "body" => $body], - "source_name" => $person["name"], - "source_link" => $person["url"], - "source_photo" => $person["photo"], - "verb" => ACTIVITY_POST, - "otype" => "mail"] - ); - return true; + return Mail::insert([ + 'uid' => $importer['uid'], + 'guid' => $msg_guid, + 'convid' => $conversation['id'], + 'from-name' => $person['name'], + 'from-photo' => $person['photo'], + 'from-url' => $person['url'], + 'contact-id' => $contact['id'], + 'title' => $subject, + 'body' => $body, + 'uri' => $message_uri, + 'parent-uri' => $author . ':' . $guid, + 'created' => $msg_created_at + ]); } /** @@ -1859,14 +1870,15 @@ class Diaspora * @param object $data The message object * * @return bool Success + * @throws \Exception */ private static function receiveConversation(array $importer, $msg, $data) { - $author = Strings::removeTags(XML::unescape($data->author)); - $guid = Strings::removeTags(XML::unescape($data->guid)); - $subject = Strings::removeTags(XML::unescape($data->subject)); - $created_at = DateTimeFormat::utc(Strings::removeTags(XML::unescape($data->created_at))); - $participants = Strings::removeTags(XML::unescape($data->participants)); + $author = Strings::escapeTags(XML::unescape($data->author)); + $guid = Strings::escapeTags(XML::unescape($data->guid)); + $subject = Strings::escapeTags(XML::unescape($data->subject)); + $created_at = DateTimeFormat::utc(Strings::escapeTags(XML::unescape($data->created_at))); + $participants = Strings::escapeTags(XML::unescape($data->participants)); $messages = $data->message; @@ -1917,14 +1929,16 @@ class Diaspora * @param object $data The message object * * @return int The message id of the generated like or "false" if there was an error + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ private static function receiveLike(array $importer, $sender, $data) { - $author = Strings::removeTags(XML::unescape($data->author)); - $guid = Strings::removeTags(XML::unescape($data->guid)); - $parent_guid = Strings::removeTags(XML::unescape($data->parent_guid)); - $parent_type = Strings::removeTags(XML::unescape($data->parent_type)); - $positive = Strings::removeTags(XML::unescape($data->positive)); + $author = Strings::escapeTags(XML::unescape($data->author)); + $guid = Strings::escapeTags(XML::unescape($data->guid)); + $parent_guid = Strings::escapeTags(XML::unescape($data->parent_guid)); + $parent_type = Strings::escapeTags(XML::unescape($data->parent_type)); + $positive = Strings::escapeTags(XML::unescape($data->positive)); // likes on comments aren't supported by Diaspora - only on posts // But maybe this will be supported in the future, so we will accept it. @@ -2026,14 +2040,15 @@ class Diaspora * @param object $data The message object * * @return bool Success? + * @throws \Exception */ private static function receiveMessage(array $importer, $data) { - $author = Strings::removeTags(XML::unescape($data->author)); - $guid = Strings::removeTags(XML::unescape($data->guid)); - $conversation_guid = Strings::removeTags(XML::unescape($data->conversation_guid)); + $author = Strings::escapeTags(XML::unescape($data->author)); + $guid = Strings::escapeTags(XML::unescape($data->guid)); + $conversation_guid = Strings::escapeTags(XML::unescape($data->conversation_guid)); $text = XML::unescape($data->text); - $created_at = DateTimeFormat::utc(Strings::removeTags(XML::unescape($data->created_at))); + $created_at = DateTimeFormat::utc(Strings::escapeTags(XML::unescape($data->created_at))); $contact = self::allowedContactByHandle($importer, $author, true); if (!$contact) { @@ -2062,36 +2077,21 @@ class Diaspora $body = self::replacePeopleGuid($body, $person["url"]); - DBA::lock('mail'); - - if (DBA::exists('mail', ['guid' => $guid, 'uid' => $importer["uid"]])) { - Logger::log("duplicate message already delivered.", Logger::DEBUG); - return false; - } - - q( - "INSERT INTO `mail` (`uid`, `guid`, `convid`, `from-name`,`from-photo`,`from-url`,`contact-id`,`title`,`body`,`seen`,`reply`,`uri`,`parent-uri`,`created`) - VALUES ( %d, '%s', %d, '%s', '%s', '%s', %d, '%s', '%s', %d, %d, '%s','%s','%s')", - intval($importer["uid"]), - DBA::escape($guid), - intval($conversation["id"]), - DBA::escape($person["name"]), - DBA::escape($person["photo"]), - DBA::escape($person["url"]), - intval($contact["id"]), - DBA::escape($conversation["subject"]), - DBA::escape($body), - 0, - 1, - DBA::escape($message_uri), - DBA::escape($author.":".$conversation["guid"]), - DBA::escape($created_at) - ); - - DBA::unlock(); - - DBA::update('conv', ['updated' => DateTimeFormat::utcNow()], ['id' => $conversation["id"]]); - return true; + return Mail::insert([ + 'uid' => $importer['uid'], + 'guid' => $guid, + 'convid' => $conversation['id'], + 'from-name' => $person['name'], + 'from-photo' => $person['photo'], + 'from-url' => $person['url'], + 'contact-id' => $contact['id'], + 'title' => $conversation['subject'], + 'body' => $body, + 'reply' => 1, + 'uri' => $message_uri, + 'parent-uri' => $author.":".$conversation['guid'], + 'created' => $created_at + ]); } /** @@ -2101,11 +2101,13 @@ class Diaspora * @param object $data The message object * * @return bool always true + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ private static function receiveParticipation(array $importer, $data) { - $author = strtolower(Strings::removeTags(XML::unescape($data->author))); - $parent_guid = Strings::removeTags(XML::unescape($data->parent_guid)); + $author = strtolower(Strings::escapeTags(XML::unescape($data->author))); + $parent_guid = Strings::escapeTags(XML::unescape($data->parent_guid)); $contact_id = Contact::getIdForURL($author); if (!$contact_id) { @@ -2194,10 +2196,12 @@ class Diaspora * @param object $data The message object * * @return bool Success + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ private static function receiveProfile(array $importer, $data) { - $author = strtolower(Strings::removeTags(XML::unescape($data->author))); + $author = strtolower(Strings::escapeTags(XML::unescape($data->author))); $contact = self::contactByHandle($importer["uid"], $author); if (!$contact) { @@ -2287,11 +2291,10 @@ class Diaspora * @param array $importer Array of the importer user * @param array $contact The contact that send the request * @return void + * @throws \Exception */ private static function receiveRequestMakeFriend(array $importer, array $contact) { - $a = get_app(); - if ($contact["rel"] == Contact::SHARING) { DBA::update( 'contact', @@ -2308,6 +2311,7 @@ class Diaspora * @param object $data The message object * * @return bool Success + * @throws \Exception */ private static function receiveContactRequest(array $importer, $data) { @@ -2350,7 +2354,7 @@ class Diaspora $user = DBA::selectFirst('user', [], ['uid' => $importer["uid"]]); if (DBA::isResult($user)) { Logger::log("Sending share message to author ".$author." - Contact: ".$contact["id"]." - User: ".$importer["uid"], Logger::DEBUG); - $ret = self::sendShare($user, $contact); + self::sendShare($user, $contact); } } return true; @@ -2361,7 +2365,7 @@ class Diaspora } } - if (!$following && $sharing && in_array($importer["page-flags"], [Contact::PAGE_SOAPBOX, Contact::PAGE_NORMAL])) { + if (!$following && $sharing && in_array($importer["page-flags"], [User::PAGE_FLAGS_SOAPBOX, User::PAGE_FLAGS_NORMAL])) { Logger::log("Author ".$author." wants to share with us - but doesn't want to listen. Request is ignored.", Logger::DEBUG); return false; } elseif (!$following && !$sharing) { @@ -2384,7 +2388,7 @@ class Diaspora $batch = (($ret["batch"]) ? $ret["batch"] : implode("/", array_slice(explode("/", $ret["url"]), 0, 3))."/receive/public"); - $r = q( + q( "INSERT INTO `contact` (`uid`, `network`,`addr`,`created`,`url`,`nurl`,`batch`,`name`,`nick`,`photo`,`pubkey`,`notify`,`poll`,`blocked`,`priority`) VALUES (%d, '%s', '%s', '%s', '%s','%s','%s','%s','%s','%s','%s','%s','%s',%d,%d)", intval($importer["uid"]), @@ -2392,7 +2396,7 @@ class Diaspora DBA::escape($ret["addr"]), DateTimeFormat::utcNow(), DBA::escape($ret["url"]), - DBA::escape(normalise_link($ret["url"])), + DBA::escape(Strings::normaliseLink($ret["url"])), DBA::escape($batch), DBA::escape($ret["name"]), DBA::escape($ret["nick"]), @@ -2419,12 +2423,12 @@ class Diaspora Contact::updateAvatar($ret["photo"], $importer['uid'], $contact_record["id"], true); - if (in_array($importer["page-flags"], [Contact::PAGE_NORMAL, Contact::PAGE_PRVGROUP])) { + if (in_array($importer["page-flags"], [User::PAGE_FLAGS_NORMAL, User::PAGE_FLAGS_PRVGROUP])) { Logger::log("Sending intra message for author ".$author.".", Logger::DEBUG); $hash = Strings::getRandomHex().(string)time(); // Generate a confirm_key - $ret = q( + q( "INSERT INTO `intro` (`uid`, `contact-id`, `blocked`, `knowyou`, `note`, `hash`, `datetime`) VALUES (%d, %d, %d, %d, '%s', '%s', '%s')", intval($importer["uid"]), @@ -2447,15 +2451,15 @@ class Diaspora * but if our page-type is Profile::PAGE_COMMUNITY or Profile::PAGE_SOAPBOX * we are going to change the relationship and make them a follower. */ - if (($importer["page-flags"] == Contact::PAGE_FREELOVE) && $sharing && $following) { + if (($importer["page-flags"] == User::PAGE_FLAGS_FREELOVE) && $sharing && $following) { $new_relation = Contact::FRIEND; - } elseif (($importer["page-flags"] == Contact::PAGE_FREELOVE) && $sharing) { + } elseif (($importer["page-flags"] == User::PAGE_FLAGS_FREELOVE) && $sharing) { $new_relation = Contact::SHARING; } else { $new_relation = Contact::FOLLOWER; } - $r = q( + q( "UPDATE `contact` SET `rel` = %d, `name-date` = '%s', `uri-date` = '%s', @@ -2473,7 +2477,7 @@ class Diaspora $user = DBA::selectFirst('user', [], ['uid' => $importer["uid"]]); if (DBA::isResult($user)) { Logger::log("Sending share message (Relation: ".$new_relation.") to author ".$author." - Contact: ".$contact_record["id"]." - User: ".$importer["uid"], Logger::DEBUG); - $ret = self::sendShare($user, $contact_record); + self::sendShare($user, $contact_record); // Send the profile data, maybe it weren't transmitted before self::sendProfile($importer["uid"], [$contact_record]); @@ -2488,9 +2492,9 @@ class Diaspora * * @param string $guid message guid * @param string $orig_author handle of the original post - * @param string $author handle of the sharer - * * @return array The fetched item + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ public static function originalItem($guid, $orig_author) { @@ -2563,6 +2567,54 @@ class Diaspora return false; } + /** + * @brief Stores a reshare activity + * + * @param array $item Array of reshare post + * @param integer $parent_message_id Id of the parent post + * @param string $guid GUID string of reshare action + * @param string $author Author handle + */ + private static function addReshareActivity($item, $parent_message_id, $guid, $author) + { + $parent = Item::selectFirst(['uri', 'guid'], ['id' => $parent_message_id]); + + $datarray = []; + + $datarray['uid'] = $item['uid']; + $datarray['contact-id'] = $item['contact-id']; + $datarray['network'] = $item['network']; + + $datarray['author-link'] = $item['author-link']; + $datarray['author-id'] = $item['author-id']; + + $datarray['owner-link'] = $datarray['author-link']; + $datarray['owner-id'] = $datarray['author-id']; + + $datarray['guid'] = $parent['guid'] . '-' . $guid; + $datarray['uri'] = self::getUriFromGuid($author, $datarray['guid']); + $datarray['parent-uri'] = $parent['uri']; + + $datarray['verb'] = $datarray['body'] = ACTIVITY2_ANNOUNCE; + $datarray['gravity'] = GRAVITY_ACTIVITY; + $datarray['object-type'] = ACTIVITY_OBJ_NOTE; + + $datarray['protocol'] = $item['protocol']; + + $datarray['plink'] = self::plink($author, $datarray['guid']); + $datarray['private'] = $item['private']; + $datarray['changed'] = $datarray['created'] = $datarray['edited'] = $item['created']; + + $message_id = Item::insert($datarray); + + if ($message_id) { + Logger::info('Stored reshare activity.', ['guid' => $guid, 'id' => $message_id]); + if ($datarray['uid'] == 0) { + Item::distribute($message_id); + } + } + } + /** * @brief Processes a reshare message * @@ -2571,16 +2623,18 @@ class Diaspora * @param string $xml The original XML of the message * * @return int the message id + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ private static function receiveReshare(array $importer, $data, $xml) { - $author = Strings::removeTags(XML::unescape($data->author)); - $guid = Strings::removeTags(XML::unescape($data->guid)); - $created_at = DateTimeFormat::utc(Strings::removeTags(XML::unescape($data->created_at))); - $root_author = Strings::removeTags(XML::unescape($data->root_author)); - $root_guid = Strings::removeTags(XML::unescape($data->root_guid)); + $author = Strings::escapeTags(XML::unescape($data->author)); + $guid = Strings::escapeTags(XML::unescape($data->guid)); + $created_at = DateTimeFormat::utc(Strings::escapeTags(XML::unescape($data->created_at))); + $root_author = Strings::escapeTags(XML::unescape($data->root_author)); + $root_guid = Strings::escapeTags(XML::unescape($data->root_guid)); /// @todo handle unprocessed property "provider_display_name" - $public = Strings::removeTags(XML::unescape($data->public)); + $public = Strings::escapeTags(XML::unescape($data->public)); $contact = self::allowedContactByHandle($importer, $author, false); if (!$contact) { @@ -2644,6 +2698,11 @@ class Diaspora self::sendParticipation($contact, $datarray); + $root_message_id = self::messageExists($importer["uid"], $root_guid); + if ($root_message_id) { + self::addReshareActivity($datarray, $root_message_id, $guid, $author); + } + if ($message_id) { Logger::log("Stored reshare ".$datarray["guid"]." with message id ".$message_id, Logger::DEBUG); if ($datarray['uid'] == 0) { @@ -2663,12 +2722,13 @@ class Diaspora * @param object $data The message object * * @return bool success + * @throws \Exception */ private static function itemRetraction(array $importer, array $contact, $data) { - $author = Strings::removeTags(XML::unescape($data->author)); - $target_guid = Strings::removeTags(XML::unescape($data->target_guid)); - $target_type = Strings::removeTags(XML::unescape($data->target_type)); + $author = Strings::escapeTags(XML::unescape($data->author)); + $target_guid = Strings::escapeTags(XML::unescape($data->target_guid)); + $target_type = Strings::escapeTags(XML::unescape($data->target_type)); $person = self::personByHandle($author); if (!is_array($person)) { @@ -2727,10 +2787,11 @@ class Diaspora * @param object $data The message object * * @return bool Success + * @throws \Exception */ private static function receiveRetraction(array $importer, $sender, $data) { - $target_type = Strings::removeTags(XML::unescape($data->target_type)); + $target_type = Strings::escapeTags(XML::unescape($data->target_type)); $contact = self::contactByHandle($importer["uid"], $sender); if (!$contact && (in_array($target_type, ["Contact", "Person"]))) { @@ -2767,20 +2828,22 @@ class Diaspora /** * @brief Receives status messages * - * @param array $importer Array of the importer user - * @param object $data The message object - * @param string $xml The original XML of the message + * @param array $importer Array of the importer user + * @param SimpleXMLElement $data The message object + * @param string $xml The original XML of the message * * @return int The message id of the newly created item + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ private static function receiveStatusMessage(array $importer, SimpleXMLElement $data, $xml) { - $author = Strings::removeTags(XML::unescape($data->author)); - $guid = Strings::removeTags(XML::unescape($data->guid)); - $created_at = DateTimeFormat::utc(Strings::removeTags(XML::unescape($data->created_at))); - $public = Strings::removeTags(XML::unescape($data->public)); + $author = Strings::escapeTags(XML::unescape($data->author)); + $guid = Strings::escapeTags(XML::unescape($data->guid)); + $created_at = DateTimeFormat::utc(Strings::escapeTags(XML::unescape($data->created_at))); + $public = Strings::escapeTags(XML::unescape($data->public)); $text = XML::unescape($data->text); - $provider_display_name = Strings::removeTags(XML::unescape($data->provider_display_name)); + $provider_display_name = Strings::escapeTags(XML::unescape($data->provider_display_name)); $contact = self::allowedContactByHandle($importer, $author, false); if (!$contact) { @@ -2795,7 +2858,7 @@ class Diaspora $address = []; if ($data->location) { foreach ($data->location->children() as $fieldname => $data) { - $address[$fieldname] = Strings::removeTags(XML::unescape($data)); + $address[$fieldname] = Strings::escapeTags(XML::unescape($data)); } } @@ -2892,6 +2955,7 @@ class Diaspora * @param array $contact contact array * * @return string the handle in the format user@domain.tld + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ private static function myHandle(array $contact) { @@ -2921,6 +2985,7 @@ class Diaspora * @param string $pubkey The public key of the receiver * * @return string The encrypted data + * @throws \Exception */ public static function encodePrivateData($msg, array $user, array $contact, $prvkey, $pubkey) { @@ -2959,6 +3024,7 @@ class Diaspora * @param array $user The record of the sender * * @return string The envelope + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ public static function buildMagicEnvelope($msg, array $user) { @@ -3002,6 +3068,7 @@ class Diaspora * @param bool $public Is the message public? * * @return string The message that will be transmitted to other servers + * @throws \Exception */ public static function buildMessage($msg, array $user, array $contact, $prvkey, $pubkey, $public = false) { @@ -3042,21 +3109,21 @@ class Diaspora * @param array $contact Target of the communication * @param string $envelope The message that is to be transmitted * @param bool $public_batch Is it a public post? - * @param bool $queue_run Is the transmission called from the queue? * @param string $guid message guid + * @param bool $no_defer Don't defer a failing delivery * * @return int Result of the transmission + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ - public static function transmit(array $owner, array $contact, $envelope, $public_batch, $queue_run = false, $guid = "", $no_queue = false) + public static function transmit(array $owner, array $contact, $envelope, $public_batch, $guid = "", $no_defer = false) { - $a = get_app(); - $enabled = intval(Config::get("system", "diaspora_enabled")); if (!$enabled) { return 200; } - $logid = String::getRandomHex(4); + $logid = Strings::getRandomHex(4); $dest_url = ($public_batch ? $contact["batch"] : $contact["notify"]); @@ -3076,27 +3143,23 @@ class Diaspora Logger::log("transmit: ".$logid."-".$guid." ".$dest_url); - if (!$queue_run && Queue::wasDelayed($contact["id"])) { - $return_code = 0; - } else { - if (!intval(Config::get("system", "diaspora_test"))) { - $content_type = (($public_batch) ? "application/magic-envelope+xml" : "application/json"); + if (!intval(Config::get("system", "diaspora_test"))) { + $content_type = (($public_batch) ? "application/magic-envelope+xml" : "application/json"); - $postResult = Network::post($dest_url."/", $envelope, ["Content-Type: ".$content_type]); - $return_code = $postResult->getReturnCode(); - } else { - Logger::log("test_mode"); - return 200; - } + $postResult = Network::post($dest_url."/", $envelope, ["Content-Type: ".$content_type]); + $return_code = $postResult->getReturnCode(); + } else { + Logger::log("test_mode"); + return 200; } Logger::log("transmit: ".$logid."-".$guid." to ".$dest_url." returns: ".$return_code); if (!$return_code || (($return_code == 503) && (stristr($postResult->getHeader(), "retry-after")))) { - if (!$no_queue && !empty($contact['contact-type']) && ($contact['contact-type'] != Contact::ACCOUNT_TYPE_RELAY)) { - Logger::log("queue message"); - // queue message for redelivery - Queue::add($contact["id"], Protocol::DIASPORA, $envelope, $public_batch, $guid); + if (!$no_defer && !empty($contact['contact-type']) && ($contact['contact-type'] != Contact::TYPE_RELAY)) { + Logger::info('defer message', ['log' => $logid, 'guid' => $guid, 'destination' => $dest_url]); + // defer message for redelivery + Worker::defer(); } // The message could not be delivered. We mark the contact as "dead" @@ -3134,11 +3197,13 @@ class Diaspora * @param array $message The message data * @param bool $public_batch Is it a public post? * @param string $guid message guid - * @param bool $spool Should the transmission be spooled or transmitted? + * @param bool $no_defer Don't defer a failing delivery * * @return int Result of the transmission + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ - private static function buildAndTransmit(array $owner, array $contact, $type, $message, $public_batch = false, $guid = "", $spool = false) + private static function buildAndTransmit(array $owner, array $contact, $type, $message, $public_batch = false, $guid = "", $no_defer = false) { $msg = self::buildPostXml($type, $message); @@ -3152,12 +3217,7 @@ class Diaspora $envelope = self::buildMessage($msg, $owner, $contact, $owner['uprvkey'], $contact['pubkey'], $public_batch); - if ($spool) { - Queue::add($contact['id'], Protocol::DIASPORA, $envelope, $public_batch, $guid); - return true; - } else { - $return_code = self::transmit($owner, $contact, $envelope, $public_batch, false, $guid); - } + $return_code = self::transmit($owner, $contact, $envelope, $public_batch, $guid, $no_defer); Logger::log("guid: ".$guid." result ".$return_code, Logger::DEBUG); @@ -3168,9 +3228,10 @@ class Diaspora * @brief sends a participation (Used to get all further updates) * * @param array $contact Target of the communication - * @param array $item Item array + * @param array $item Item array * * @return int The result of the transmission + * @throws \Exception */ private static function sendParticipation(array $contact, array $item) { @@ -3217,9 +3278,11 @@ class Diaspora * * @param array $owner the array of the item owner * @param array $contact Target of the communication - * @param int $uid User ID + * @param int $uid User ID * * @return int The result of the transmission + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ public static function sendAccountMigration(array $owner, array $contact, $uid) { @@ -3245,6 +3308,7 @@ class Diaspora * @param array $contact Target of the communication * * @return int The result of the transmission + * @throws \Exception */ public static function sendShare(array $owner, array $contact) { @@ -3288,6 +3352,7 @@ class Diaspora * @param array $contact Target of the communication * * @return int The result of the transmission + * @throws \Exception */ public static function sendUnshare(array $owner, array $contact) { @@ -3308,6 +3373,8 @@ class Diaspora * @param bool $complete Should it be a complete check or a simple check? * * @return array|bool Reshare details or "false" if no reshare + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ public static function isReshare($body, $complete = true) { @@ -3395,6 +3462,7 @@ class Diaspora * @param integer $event_id The id of the event * * @return array with event data + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ private static function buildEvent($event_id) { @@ -3477,6 +3545,8 @@ class Diaspora * @return array * 'type' -> Message type ("status_message" or "reshare") * 'message' -> Array of XML elements of the status + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ public static function buildStatus(array $item, array $owner) { @@ -3582,6 +3652,20 @@ class Diaspora return $msg; } + private static function prependParentAuthorMention($body, $profile_url) + { + $profile = Contact::getDetailsByURL($profile_url); + if (!empty($profile['addr']) + && $profile['contact-type'] != Contact::TYPE_COMMUNITY + && !strstr($body, $profile['addr']) + && !strstr($body, $profile_url) + ) { + $body = '@[url=' . $profile_url . ']' . $profile['name'] . '[/url] ' . $body; + } + + return $body; + } + /** * @brief Sends a post * @@ -3591,6 +3675,8 @@ class Diaspora * @param bool $public_batch Is it a public post? * * @return int The result of the transmission + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ public static function sendStatus(array $item, array $owner, array $contact, $public_batch = false) { @@ -3606,6 +3692,7 @@ class Diaspora * @param array $owner the array of the item owner * * @return array The data for a "like" + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ private static function constructLike(array $item, array $owner) { @@ -3637,6 +3724,7 @@ class Diaspora * @param array $owner the array of the item owner * * @return array The data for an "EventParticipation" + * @throws \Exception */ private static function constructAttend(array $item, array $owner) { @@ -3673,7 +3761,8 @@ class Diaspora * @param array $item The item that will be exported * @param array $owner the array of the item owner * - * @return array The data for a comment + * @return array|false The data for a comment + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ private static function constructComment(array $item, array $owner) { @@ -3684,24 +3773,40 @@ class Diaspora return $result; } - $parent = Item::selectFirst(['guid'], ['id' => $item["parent"], 'parent' => $item["parent"]]); - if (!DBA::isResult($parent)) { + $toplevel_item = Item::selectFirst(['guid', 'author-link'], ['id' => $item["parent"], 'parent' => $item["parent"]]); + if (!DBA::isResult($toplevel_item)) { + Logger::error('Missing parent conversation item', ['parent' => $item["parent"]]); return false; } - $text = html_entity_decode(BBCode::toMarkdown($item["body"])); + $thread_parent_item = $toplevel_item; + if ($item['thr-parent'] != $item['parent-uri']) { + $thread_parent_item = Item::selectFirst(['guid', 'author-link'], ['uri' => $item['thr-parent'], 'uid' => $item['uid']]); + } + + $body = $item["body"]; + + if ((empty($item['uid']) || !Feature::isEnabled($item['uid'], 'explicit_mentions')) + && !Config::get('system', 'disable_implicit_mentions') + ) { + $body = self::prependParentAuthorMention($body, $thread_parent_item['author-link']); + } + + $text = html_entity_decode(BBCode::toMarkdown($body)); $created = DateTimeFormat::utc($item["created"], DateTimeFormat::ATOM); - $comment = ["author" => self::myHandle($owner), - "guid" => $item["guid"], - "created_at" => $created, - "parent_guid" => $parent["guid"], - "text" => $text, - "author_signature" => ""]; + $comment = [ + "author" => self::myHandle($owner), + "guid" => $item["guid"], + "created_at" => $created, + "parent_guid" => $toplevel_item["guid"], + "text" => $text, + "author_signature" => "" + ]; // Send the thread parent guid only if it is a threaded comment if ($item['thr-parent'] != $item['parent-uri']) { - $comment['thread_parent_guid'] = self::getGuidFromUri($item['thr-parent'], $item['uid']); + $comment['thread_parent_guid'] = $thread_parent_item['guid']; } Cache::set($cachekey, $comment, Cache::QUARTER_HOUR); @@ -3718,6 +3823,8 @@ class Diaspora * @param bool $public_batch Is it a public post? * * @return int The result of the transmission + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ public static function sendFollowup(array $item, array $owner, array $contact, $public_batch = false) { @@ -3727,12 +3834,12 @@ class Diaspora } elseif (in_array($item["verb"], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) { $message = self::constructLike($item, $owner); $type = "like"; - } else { + } elseif (!in_array($item["verb"], [ACTIVITY_FOLLOW, ACTIVITY_TAG])) { $message = self::constructComment($item, $owner); $type = "comment"; } - if (!$message) { + if (empty($message)) { return false; } @@ -3744,10 +3851,8 @@ class Diaspora /** * @brief Creates a message from a signature record entry * - * @param array $item The item that will be exported - * @param array $signature The entry of the "sign" record - * - * @return string The message + * @param array $item The item that will be exported + * @return array The message */ private static function messageFromSignature(array $item) { @@ -3776,15 +3881,14 @@ class Diaspora // Remove the handle $handle = array_pop($signed_parts); - // Glue the parts together - $text = implode(";", $signed_parts); - - $message = ["author" => $handle, - "guid" => $guid, - "parent_guid" => $parent_guid, - "text" => implode(";", $signed_parts), - "author_signature" => $item['signature'], - "parent_author_signature" => ""]; + $message = [ + "author" => $handle, + "guid" => $guid, + "parent_guid" => $parent_guid, + "text" => implode(";", $signed_parts), + "author_signature" => $item['signature'], + "parent_author_signature" => "" + ]; } return $message; } @@ -3798,6 +3902,7 @@ class Diaspora * @param bool $public_batch Is it a public post? * * @return int The result of the transmission + * @throws \Exception */ public static function sendRelay(array $item, array $owner, array $contact, $public_batch = false) { @@ -3854,6 +3959,7 @@ class Diaspora * @param bool $relay Is the retraction transmitted from a relay? * * @return int The result of the transmission + * @throws \Exception */ public static function sendRetraction(array $item, array $owner, array $contact, $public_batch = false, $relay = false) { @@ -3886,6 +3992,8 @@ class Diaspora * @param array $contact Target of the communication * * @return int The result of the transmission + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ public static function sendMail(array $item, array $owner, array $contact) { @@ -3897,14 +4005,6 @@ class Diaspora return; } - $conv = [ - "author" => $cnv["creator"], - "guid" => $cnv["guid"], - "subject" => $cnv["subject"], - "created_at" => DateTimeFormat::utc($cnv['created'], DateTimeFormat::ATOM), - "participants" => $cnv["recips"] - ]; - $body = BBCode::toMarkdown($item["body"]); $created = DateTimeFormat::utc($item["created"], DateTimeFormat::ATOM); @@ -3921,12 +4021,13 @@ class Diaspora $type = "message"; } else { $message = [ - "author" => $cnv["creator"], - "guid" => $cnv["guid"], - "subject" => $cnv["subject"], - "created_at" => DateTimeFormat::utc($cnv['created'], DateTimeFormat::ATOM), - "participants" => $cnv["recips"], - "message" => $msg]; + "author" => $cnv["creator"], + "guid" => $cnv["guid"], + "subject" => $cnv["subject"], + "created_at" => DateTimeFormat::utc($cnv['created'], DateTimeFormat::ATOM), + "participants" => $cnv["recips"], + "message" => $msg + ]; $type = "conversation"; } @@ -3996,6 +4097,7 @@ class Diaspora * @param int $uid The user id * * @return array The profile data + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ private static function createProfileData($uid) { @@ -4047,7 +4149,7 @@ class Diaspora if ($profile['pub_keywords']) { $kw = str_replace(',', ' ', $profile['pub_keywords']); $kw = str_replace(' ', ' ', $kw); - $arr = explode(' ', $profile['pub_keywords']); + $arr = explode(' ', $kw); if (count($arr)) { for ($x = 0; $x < 5; $x ++) { if (!empty($arr[$x])) { @@ -4080,6 +4182,7 @@ class Diaspora * @param int $uid The user id * @param bool $recips optional, default false * @return void + * @throws \Exception */ public static function sendProfile($uid, $recips = false) { @@ -4110,7 +4213,7 @@ class Diaspora foreach ($recips as $recip) { Logger::log("Send updated profile data for user ".$uid." to contact ".$recip["id"], Logger::DEBUG); - self::buildAndTransmit($owner, $recip, "profile", $message, false, "", false); + self::buildAndTransmit($owner, $recip, "profile", $message, false, '', true); } } @@ -4121,6 +4224,7 @@ class Diaspora * @param array $item Item array * * @return array Signed content + * @throws \Exception */ public static function createLikeSignature($uid, array $item) { @@ -4151,6 +4255,7 @@ class Diaspora * @param array $item Item array * * @return array Signed content + * @throws \Exception */ public static function createCommentSignature($uid, array $item) {