X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FProtocol%2FDiaspora.php;h=981abb0831defaec2816419afe5ec16b307cbc7b;hb=dcfd81e2eec9bde5c30f4738afb0a29b623ee0f6;hp=f925dc9b5797cb8a6f5d5dba6d7a08f043fe4b85;hpb=bc03c8846c04888c42a9babf1787dfdb10a40132;p=friendica.git diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index f925dc9b57..981abb0831 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -47,60 +47,149 @@ class Diaspora /** * @brief Return a list of relay servers * - * This is an experimental Diaspora feature. + * The list contains not only the official relays but also servers that we serve directly + * + * @param integer $item_id The id of the item that is sent + * @param array $contacts The previously fetched contacts * * @return array of relay servers */ - public static function relayList() + public static function relayList($item_id, $contacts = []) { + $serverlist = []; + + // Fetching relay servers $serverdata = Config::get("system", "relay_server"); - if ($serverdata == "") { - return []; + if ($serverdata != "") { + $servers = explode(",", $serverdata); + foreach ($servers as $server) { + $serverlist[$server] = trim($server); + } } - $relay = []; + if (Config::get("system", "relay_directly", false)) { + // We distribute our stuff based on the parent to ensure that the thread will be complete + $parent = dba::selectFirst('item', ['parent'], ['id' => $item_id]); + if (!DBM::is_result($parent)) { + return; + } - $servers = explode(",", $serverdata); + // Servers that want to get all content + $servers = dba::select('gserver', ['url'], ['relay-subscribe' => true, 'relay-scope' => 'all']); + while ($server = dba::fetch($servers)) { + $serverlist[$server['url']] = $server['url']; + } - foreach ($servers as $server) { - $server = trim($server); - $addr = "relay@".str_replace("http://", "", normalise_link($server)); - $batch = $server."/receive/public"; + // All tags of the current post + $condition = ['otype' => TERM_OBJ_POST, 'type' => TERM_HASHTAG, 'oid' => $parent['parent']]; + $tags = dba::select('term', ['term'], $condition); + $taglist = []; + while ($tag = dba::fetch($tags)) { + $taglist[] = $tag['term']; + } - $relais = q( - "SELECT `batch`, `id`, `name`,`network` FROM `contact` WHERE `uid` = 0 AND `batch` = '%s' AND `addr` = '%s' AND `nurl` = '%s' LIMIT 1", - dbesc($batch), - dbesc($addr), - dbesc(normalise_link($server)) - ); + // All servers who wants content with this tag + $tagserverlist = []; + if (!empty($taglist)) { + $tagserver = dba::select('gserver-tag', ['gserver-id'], ['tag' => $taglist]); + while ($server = dba::fetch($tagserver)) { + $tagserverlist[] = $server['gserver-id']; + } + } - if (!$relais) { - $r = q( - "INSERT INTO `contact` (`uid`, `created`, `name`, `nick`, `addr`, `url`, `nurl`, `batch`, `network`, `rel`, `blocked`, `pending`, `writable`, `name-date`, `uri-date`, `avatar-date`) - VALUES (0, '%s', '%s', 'relay', '%s', '%s', '%s', '%s', '%s', %d, 0, 0, 1, '%s', '%s', '%s')", - DateTimeFormat::utcNow(), - dbesc($addr), - dbesc($addr), - dbesc($server), - dbesc(normalise_link($server)), - dbesc($batch), - dbesc(NETWORK_DIASPORA), - intval(CONTACT_IS_FOLLOWER), - dbesc(DateTimeFormat::utcNow()), - dbesc(DateTimeFormat::utcNow()), - dbesc(DateTimeFormat::utcNow()) - ); + // All adresses with the given id + if (!empty($tagserverlist)) { + $servers = dba::select('gserver', ['url'], ['relay-subscribe' => true, 'relay-scope' => 'tags', 'id' => $tagserverlist]); + while ($server = dba::fetch($servers)) { + $serverlist[$server['url']] = $server['url']; + } + } + } + + // Now we are collecting all relay contacts + foreach ($serverlist as $server_url) { + // We don't send messages to ourselves + if (link_compare($server_url, System::baseUrl())) { + continue; + } + $contact = self::getRelayContact($server_url); + if (is_bool($contact)) { + continue; + } - $relais = q("SELECT `batch`, `id`, `name`,`network` FROM `contact` WHERE `uid` = 0 AND `batch` = '%s' LIMIT 1", dbesc($batch)); - if ($relais) { - $relay[] = $relais[0]; + $exists = false; + foreach ($contacts as $entry) { + if ($entry['batch'] == $contact['batch']) { + $exists = true; } - } else { - $relay[] = $relais[0]; + } + + if (!$exists) { + $contacts[] = $contact; + } + } + + return $contacts; + } + + /** + * @brief Return a contact for a given server address or creates a dummy entry + * + * @param string $server_url The url of the server + * @return array with the contact + */ + 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' => ACCOUNT_TYPE_RELAY]; + $contact = dba::selectFirst('contact', $fields, $condition); + + if (DBM::is_result($contact)) { + if ($contact['archive'] || $contact['blocked']) { + return false; + } + return $contact; + } else { + self::setRelayContact($server_url); + + $contact = dba::selectFirst('contact', $fields, $condition); + if (DBM::is_result($contact)) { + return $contact; } } - return $relay; + // It should never happen that we arrive here + return []; + } + + /** + * @brief Update or insert a relay contact + * + * @param string $server_url The url of the server + * @param array $network_fields Optional network specific fields + */ + public static function setRelayContact($server_url, $network_fields = []) + { + $fields = ['created' => DateTimeFormat::utcNow(), + 'name' => 'relay', 'nick' => 'relay', + 'url' => $server_url, 'network' => NETWORK_DIASPORA, + 'batch' => $server_url . '/receive/public', + 'rel' => CONTACT_IS_FOLLOWER, 'blocked' => false, + 'pending' => false, 'writable' => true]; + + $fields = array_merge($fields, $network_fields); + + $condition = ['uid' => 0, 'nurl' => normalise_link($server_url), + 'contact-type' => ACCOUNT_TYPE_RELAY]; + + if (dba::exists('contact', $condition)) { + unset($fields['created']); + } + + dba::update('contact', $fields, $condition, true); } /** @@ -510,59 +599,15 @@ class Diaspora return false; } - if (!($postdata = self::validPosting($msg))) { + if (!($fields = self::validPosting($msg))) { logger("Invalid posting"); return false; } - $fields = $postdata['fields']; + $importer = ["uid" => 0, "page-flags" => PAGE_FREELOVE]; + $success = self::dispatch($importer, $msg, $fields); - // Is it a an action (comment, like, ...) for our own post? - if (isset($fields->parent_guid) && !$postdata["relayed"]) { - $guid = notags(unxmlify($fields->parent_guid)); - $importer = self::importerForGuid($guid); - if (is_array($importer)) { - logger("delivering to origin: ".$importer["name"]); - $message_id = self::dispatch($importer, $msg, $fields); - return $message_id; - } - } - - // Process item retractions. This has to be done separated from the other stuff, - // since retractions for comments could come even from non followers. - if (!empty($fields) && in_array($fields->getName(), ['retraction'])) { - $target = notags(unxmlify($fields->target_type)); - if (in_array($target, ["Comment", "Like", "Post", "Reshare", "StatusMessage"])) { - logger('processing retraction for '.$target, LOGGER_DEBUG); - $importer = ["uid" => 0, "page-flags" => PAGE_FREELOVE]; - $message_id = self::dispatch($importer, $msg, $fields); - return $message_id; - } - } - - // Now distribute it to the followers - $r = q( - "SELECT `user`.* FROM `user` WHERE `user`.`uid` IN - (SELECT `contact`.`uid` FROM `contact` WHERE `contact`.`network` = '%s' AND `contact`.`addr` = '%s') - AND NOT `account_expired` AND NOT `account_removed`", - dbesc(NETWORK_DIASPORA), - dbesc($msg["author"]) - ); - - if (DBM::is_result($r)) { - foreach ($r as $rr) { - logger("delivering to: ".$rr["username"]); - self::dispatch($rr, $msg, $fields); - } - } elseif (!Config::get('system', 'relay_subscribe', false)) { - logger("Unwanted message from ".$msg["author"]." send by ".$_SERVER["REMOTE_ADDR"]." with ".$_SERVER["HTTP_USER_AGENT"].": ".print_r($msg, true), LOGGER_DEBUG); - } else { - // Use a dummy importer to import the data for the public copy - $importer = ["uid" => 0, "page-flags" => PAGE_FREELOVE]; - $message_id = self::dispatch($importer, $msg, $fields); - } - - return $message_id; + return $success; } /** @@ -582,11 +627,13 @@ class Diaspora // This is only needed for private postings since this is already done for public ones before if (is_null($fields)) { - if (!($postdata = self::validPosting($msg))) { + $private = true; + if (!($fields = self::validPosting($msg))) { logger("Invalid posting"); return false; } - $fields = $postdata['fields']; + } else { + $private = false; } $type = $fields->getName(); @@ -595,27 +642,47 @@ class Diaspora switch ($type) { case "account_migration": + if (!$private) { + logger('Message with type ' . $type . ' is not private, quitting.'); + return false; + } return self::receiveAccountMigration($importer, $fields); case "account_deletion": - return self::receiveAccountDeletion($importer, $fields); + return self::receiveAccountDeletion($fields); case "comment": return self::receiveComment($importer, $sender, $fields, $msg["message"]); case "contact": + if (!$private) { + logger('Message with type ' . $type . ' is not private, quitting.'); + return false; + } return self::receiveContactRequest($importer, $fields); case "conversation": + if (!$private) { + logger('Message with type ' . $type . ' is not private, quitting.'); + return false; + } return self::receiveConversation($importer, $msg, $fields); case "like": return self::receiveLike($importer, $sender, $fields); case "message": + if (!$private) { + logger('Message with type ' . $type . ' is not private, quitting.'); + return false; + } return self::receiveMessage($importer, $fields); case "participation": + if (!$private) { + logger('Message with type ' . $type . ' is not private, quitting.'); + return false; + } return self::receiveParticipation($importer, $fields); case "photo": // Not implemented @@ -625,6 +692,10 @@ class Diaspora return self::receivePollParticipation($importer, $fields); case "profile": + if (!$private) { + logger('Message with type ' . $type . ' is not private, quitting.'); + return false; + } return self::receiveProfile($importer, $fields); case "reshare": @@ -760,7 +831,7 @@ class Diaspora // Only some message types have signatures. So we quit here for the other types. if (!in_array($type, ["comment", "like"])) { - return ["fields" => $fields, "relayed" => false]; + return $fields; } // No author_signature? This is a must, so we quit. if (!isset($author_signature)) { @@ -769,25 +840,29 @@ class Diaspora } if (isset($parent_author_signature)) { - $relayed = true; - $key = self::key($msg["author"]); + if (empty($key)) { + logger("No key found for parent author ".$msg["author"], LOGGER_DEBUG); + return false; + } if (!Crypto::rsaVerify($signed_data, $parent_author_signature, $key, "sha256")) { logger("No valid parent author signature for parent author ".$msg["author"]. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$parent_author_signature, LOGGER_DEBUG); return false; } - } else { - $relayed = false; } $key = self::key($fields->author); + if (empty($key)) { + logger("No key found for author ".$fields->author, LOGGER_DEBUG); + return false; + } if (!Crypto::rsaVerify($signed_data, $author_signature, $key, "sha256")) { logger("No valid author signature for author ".$fields->author. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$author_signature, LOGGER_DEBUG); return false; } else { - return ["fields" => $fields, "relayed" => $relayed]; + return $fields; } } @@ -1085,7 +1160,7 @@ class Diaspora //} // We don't seem to like that person - if ($contact["blocked"] || $contact["readonly"]) { + if ($contact["blocked"]) { // Maybe blocked, don't accept. return false; // We are following this person? @@ -1093,7 +1168,7 @@ class Diaspora // Yes, then it is fine. return true; // Is it a post to a community? - } elseif (($contact["rel"] == CONTACT_IS_FOLLOWER) && ($importer["page-flags"] == PAGE_COMMUNITY)) { + } elseif (($contact["rel"] == CONTACT_IS_FOLLOWER) && in_array($importer["page-flags"], [PAGE_COMMUNITY, PAGE_PRVGROUP])) { // That's good return true; // Is the message a global user or a comment? @@ -1448,36 +1523,29 @@ class Diaspora */ private static function plink($addr, $guid, $parent_guid = '') { - $r = q("SELECT `url`, `nick`, `network` FROM `fcontact` WHERE `addr`='%s' LIMIT 1", dbesc($addr)); + $contact = Contact::getDetailsByAddr($addr); // Fallback - if (!DBM::is_result($r)) { + if (!$contact) { if ($parent_guid != '') { - return "https://".substr($addr, strpos($addr, "@") + 1) . "/posts/" . $parent_guid . "#" . $guid; + return "https://" . substr($addr, strpos($addr, "@") + 1) . "/posts/" . $parent_guid . "#" . $guid; } else { - return "https://".substr($addr, strpos($addr, "@") + 1) . "/posts/" . $guid; + return "https://" . substr($addr, strpos($addr, "@") + 1) . "/posts/" . $guid; } } - // Friendica contacts are often detected as Diaspora contacts in the "fcontact" table - // So we try another way as well. - $s = q("SELECT `network` FROM `gcontact` WHERE `nurl`='%s' LIMIT 1", dbesc(normalise_link($r[0]["url"]))); - if (DBM::is_result($s)) { - $r[0]["network"] = $s[0]["network"]; - } - - if ($r[0]["network"] == NETWORK_DFRN) { - return str_replace("/profile/".$r[0]["nick"]."/", "/display/".$guid, $r[0]["url"]."/"); + if ($contact["network"] == NETWORK_DFRN) { + return str_replace("/profile/" . $contact["nick"] . "/", "/display/" . $guid, $contact["url"] . "/"); } - if (self::isRedmatrix($r[0]["url"])) { - return $r[0]["url"]."/?f=&mid=".$guid; + if (self::isRedmatrix($contact["url"])) { + return $contact["url"] . "/?f=&mid=" . $guid; } if ($parent_guid != '') { - return "https://".substr($addr, strpos($addr, "@") + 1) . "/posts/" . $parent_guid . "#" . $guid; + return "https://" . substr($addr, strpos($addr, "@") + 1) . "/posts/" . $parent_guid . "#" . $guid; } else { - return "https://".substr($addr, strpos($addr, "@") + 1) . "/posts/" . $guid; + return "https://" . substr($addr, strpos($addr, "@") + 1) . "/posts/" . $guid; } } @@ -1540,34 +1608,9 @@ class Diaspora logger('Contacts are updated.'); // update items - /// @todo This is an extreme performance killer - $fields = [ - 'owner-link' => [$contact["url"], $data["url"]], - 'author-link' => [$contact["url"], $data["url"]], - ]; - foreach ($fields as $n => $f) { - $r = q( - "SELECT `id` FROM `item` WHERE `%s` = '%s' AND `uid` = %d LIMIT 1", - $n, - dbesc($f[0]), - intval($importer["uid"]) - ); - - if (DBM::is_result($r)) { - $x = q( - "UPDATE `item` SET `%s` = '%s' WHERE `%s` = '%s' AND `uid` = %d", - $n, - dbesc($f[1]), - $n, - dbesc($f[0]), - intval($importer["uid"]) - ); - - if ($x === false) { - return false; - } - } - } + // This is an extreme performance killer + Item::update(['owner-link' => $data["url"]], ['owner-link' => $contact["url"], 'uid' => $importer["uid"]]); + Item::update(['author-link' => $data["url"]], ['author-link' => $contact["url"], 'uid' => $importer["uid"]]); logger('Items are updated.'); @@ -1577,25 +1620,23 @@ class Diaspora /** * @brief Processes an account deletion * - * @param array $importer Array of the importer user * @param object $data The message object * * @return bool Success */ - private static function receiveAccountDeletion($importer, $data) + private static function receiveAccountDeletion($data) { - /// @todo Account deletion should remove the contact from the global contacts as well - $author = notags(unxmlify($data->author)); - $contact = self::contactByHandle($importer["uid"], $author); - if (!$contact) { - logger("cannot find contact for author: ".$author); - return false; + $contacts = dba::select('contact', ['id'], ['addr' => $author]); + while ($contact = dba::fetch($contacts)) { + Contact::remove($contact["id"]); } - // We now remove the contact - Contact::remove($contact["id"]); + dba::delete('gcontact', ['addr' => $author]); + + logger('Removed contacts for ' . $author); + return true; } @@ -1763,6 +1804,9 @@ class Diaspora if ($message_id) { logger("Stored comment ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); + if ($datarray['uid'] == 0) { + Item::distribute($message_id); + } } // If we are the origin of the parent we store the original data and notify our followers @@ -2084,6 +2128,9 @@ class Diaspora if ($message_id) { logger("Stored like ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); + if ($datarray['uid'] == 0) { + Item::distribute($message_id); + } } // like on comments have the comment as parent. So we need to fetch the toplevel parent @@ -2592,7 +2639,7 @@ class Diaspora Contact::updateAvatar($ret["photo"], $importer['uid'], $contact_record["id"], true); - if ($importer["page-flags"] == PAGE_NORMAL) { + if (in_array($importer["page-flags"], [PAGE_NORMAL, PAGE_PRVGROUP])) { logger("Sending intra message for author ".$author.".", LOGGER_DEBUG); $hash = random_string().(string)time(); // Generate a confirm_key @@ -2664,65 +2711,71 @@ class Diaspora * * @return array The fetched item */ - private static function originalItem($guid, $orig_author, $author) + public static function originalItem($guid, $orig_author) { + if (empty($guid)) { + logger('Empty guid. Quitting.'); + return false; + } + // Do we already have this item? - $r = q( - "SELECT `body`, `tag`, `app`, `created`, `object-type`, `uri`, `guid`, - `author-name`, `author-link`, `author-avatar` - FROM `item` WHERE `guid` = '%s' AND `visible` AND NOT `deleted` AND `body` != '' LIMIT 1", - dbesc($guid) - ); + $fields = ['body', 'tag', 'app', 'created', 'object-type', 'uri', 'guid', + 'author-name', 'author-link', 'author-avatar']; + $condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => false]; + $item = dba::selectfirst('item', $fields, $condition); - if (DBM::is_result($r)) { + if (DBM::is_result($item)) { logger("reshared message ".$guid." already exists on system."); // Maybe it is already a reshared item? // Then refetch the content, if it is a reshare from a reshare. // If it is a reshared post from another network then reformat to avoid display problems with two share elements - if (self::isReshare($r[0]["body"], true)) { - $r = []; - } elseif (self::isReshare($r[0]["body"], false) || strstr($r[0]["body"], "[share")) { - $r[0]["body"] = Markdown::toBBCode(BBCode::toMarkdown($r[0]["body"])); + if (self::isReshare($item["body"], true)) { + $item = []; + } elseif (self::isReshare($item["body"], false) || strstr($item["body"], "[share")) { + $item["body"] = Markdown::toBBCode(BBCode::toMarkdown($item["body"])); - $r[0]["body"] = self::replacePeopleGuid($r[0]["body"], $r[0]["author-link"]); + $item["body"] = self::replacePeopleGuid($item["body"], $item["author-link"]); // Add OEmbed and other information to the body - $r[0]["body"] = add_page_info_to_body($r[0]["body"], false, true); + $item["body"] = add_page_info_to_body($item["body"], false, true); - return $r[0]; + return $item; } else { - return $r[0]; + return $item; } } - if (!DBM::is_result($r)) { + if (!DBM::is_result($item)) { + if (empty($orig_author)) { + logger('Empty author for guid ' . $guid . '. Quitting.'); + return false; + } + $server = "https://".substr($orig_author, strpos($orig_author, "@") + 1); logger("1st try: reshared message ".$guid." will be fetched via SSL from the server ".$server); - $item_id = self::storeByGuid($guid, $server); + $stored = self::storeByGuid($guid, $server); - if (!$item_id) { + if (!$stored) { $server = "http://".substr($orig_author, strpos($orig_author, "@") + 1); - logger("2nd try: reshared message ".$guid." will be fetched without SLL from the server ".$server); - $item_id = self::storeByGuid($guid, $server); + logger("2nd try: reshared message ".$guid." will be fetched without SSL from the server ".$server); + $stored = self::storeByGuid($guid, $server); } - if ($item_id) { - $r = q( - "SELECT `body`, `tag`, `app`, `created`, `object-type`, `uri`, `guid`, - `author-name`, `author-link`, `author-avatar` - FROM `item` WHERE `id` = %d AND `visible` AND NOT `deleted` AND `body` != '' LIMIT 1", - intval($item_id) - ); + if ($stored) { + $fields = ['body', 'tag', 'app', 'created', 'object-type', 'uri', 'guid', + 'author-name', 'author-link', 'author-avatar']; + $condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => false]; + $item = dba::selectfirst('item', $fields, $condition); - if (DBM::is_result($r)) { + if (DBM::is_result($item)) { // If it is a reshared post from another network then reformat to avoid display problems with two share elements - if (self::isReshare($r[0]["body"], false)) { - $r[0]["body"] = Markdown::toBBCode(BBCode::toMarkdown($r[0]["body"])); - $r[0]["body"] = self::replacePeopleGuid($r[0]["body"], $r[0]["author-link"]); + if (self::isReshare($item["body"], false)) { + $item["body"] = Markdown::toBBCode(BBCode::toMarkdown($item["body"])); + $item["body"] = self::replacePeopleGuid($item["body"], $item["author-link"]); } - return $r[0]; + return $item; } } } @@ -2758,7 +2811,7 @@ class Diaspora return true; } - $original_item = self::originalItem($root_guid, $root_author, $author); + $original_item = self::originalItem($root_guid, $root_author); if (!$original_item) { return false; } @@ -2814,6 +2867,9 @@ class Diaspora if ($message_id) { logger("Stored reshare ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); + if ($datarray['uid'] == 0) { + Item::distribute($message_id); + } return true; } else { return false; @@ -2913,12 +2969,10 @@ class Diaspora case "StatusMessage": return self::itemRetraction($importer, $contact, $data); - case "Contact": - case "Person": - /// @todo What should we do with an "unshare"? - // Removing the contact isn't correct since we still can read the public items - Contact::remove($contact["id"]); - return true; + case "PollParticipation": + case "Photo": + // Currently unsupported + break; default: logger("Unknown target type ".$target_type); @@ -3038,6 +3092,9 @@ class Diaspora if ($message_id) { logger("Stored item ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); + if ($datarray['uid'] == 0) { + Item::distribute($message_id); + } return true; } else { return false; @@ -3165,7 +3222,7 @@ class Diaspora * * @return string The message that will be transmitted to other servers */ - private static function buildMessage($msg, $user, $contact, $prvkey, $pubkey, $public = false) + public static function buildMessage($msg, $user, $contact, $prvkey, $pubkey, $public = false) { // The message is put into an envelope with the sender's signature $envelope = self::buildMagicEnvelope($msg, $user); @@ -3220,13 +3277,15 @@ class Diaspora $logid = random_string(4); + $dest_url = ($public_batch ? $contact["batch"] : $contact["notify"]); + // We always try to use the data from the fcontact table. // This is important for transmitting data to Friendica servers. - if (!empty($contact['addr']) && ($contact['network'] != NETWORK_DIASPORA)) { + if (!empty($contact['addr'])) { $fcontact = self::personByHandle($contact['addr']); - $dest_url = ($public_batch ? $fcontact["batch"] : $fcontact["notify"]); - } else { - $dest_url = ($public_batch ? $contact["batch"] : $contact["notify"]); + if (!empty($fcontact)) { + $dest_url = ($public_batch ? $fcontact["batch"] : $fcontact["notify"]); + } } if (!$dest_url) { @@ -3250,10 +3309,10 @@ class Diaspora } } - logger("transmit: ".$logid."-".$guid." returns: ".$return_code); + logger("transmit: ".$logid."-".$guid." to ".$dest_url." returns: ".$return_code); if (!$return_code || (($return_code == 503) && (stristr($a->get_curl_headers(), "retry-after")))) { - if (!$no_queue) { + if (!$no_queue && ($contact['contact-type'] != ACCOUNT_TYPE_RELAY)) { logger("queue message"); // queue message for redelivery Queue::add($contact["id"], NETWORK_DIASPORA, $envelope, $public_batch, $guid); @@ -3474,24 +3533,21 @@ class Diaspora // Skip if it isn't a pure repeated messages // Does it start with a share? if ((strpos($body, "[share") > 0) && $complete) { - return(false); + return false; } // Does it end with a share? if (strlen($body) > (strrpos($body, "[/share]") + 8)) { - return(false); + return false; } $attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism", "$1", $body); // Skip if there is no shared message in there if ($body == $attributes) { - return(false); + return false; } // If we don't do the complete check we quit here - if (!$complete) { - return true; - } $guid = ""; preg_match("/guid='(.*?)'/ism", $attributes, $matches); @@ -3504,21 +3560,21 @@ class Diaspora $guid = $matches[1]; } - if ($guid != "") { - $r = q( - "SELECT `contact-id` FROM `item` WHERE `guid` = '%s' AND `network` IN ('%s', '%s') LIMIT 1", - dbesc($guid), - NETWORK_DFRN, - NETWORK_DIASPORA - ); - if ($r) { + if (($guid != "") && $complete) { + $condition = ['guid' => $guid, 'network' => [NETWORK_DFRN, NETWORK_DIASPORA]]; + $item = dba::selectFirst('item', ['contact-id'], $condition); + if (DBM::is_result($item)) { $ret= []; - $ret["root_handle"] = self::handleFromContact($r[0]["contact-id"]); + $ret["root_handle"] = self::handleFromContact($item["contact-id"]); $ret["root_guid"] = $guid; - return($ret); + return $ret; } + } elseif (($guid == "") && $complete) { + return false; } + $ret["root_guid"] = $guid; + $profile = ""; preg_match("/profile='(.*?)'/ism", $attributes, $matches); if ($matches[1] != "") { @@ -3532,28 +3588,18 @@ class Diaspora $ret= []; - $ret["root_handle"] = preg_replace("=https?://(.*)/u/(.*)=ism", "$2@$1", $profile); - if (($ret["root_handle"] == $profile) || ($ret["root_handle"] == "")) { - return(false); - } - - $link = ""; - preg_match("/link='(.*?)'/ism", $attributes, $matches); - if ($matches[1] != "") { - $link = $matches[1]; - } - - preg_match('/link="(.*?)"/ism', $attributes, $matches); - if ($matches[1] != "") { - $link = $matches[1]; + if ($profile != "") { + if (Contact::getIdForURL($profile)) { + $author = Contact::getDetailsByURL($profile); + $ret["root_handle"] = $author['addr']; + } } - $ret["root_guid"] = preg_replace("=https?://(.*)/posts/(.*)=ism", "$2", $link); - if (($ret["root_guid"] == $link) || (trim($ret["root_guid"]) == "")) { - return(false); + if (empty($ret) && !$complete) { + return true; } - return($ret); + return $ret; } /** @@ -3678,6 +3724,12 @@ class Diaspora $title = $item["title"]; $body = $item["body"]; + if ($item['author-link'] != $item['owner-link']) { + require_once 'mod/share.php'; + $body = share_header($item['author-name'], $item['author-link'], $item['author-avatar'], + "", $item['created'], $item['plink']) . $body . '[/share]'; + } + // convert to markdown $body = html_entity_decode(BBCode::toMarkdown($body));