"mobiledetect/mobiledetectlib": "2.8.*",
"monolog/monolog": "^1.24",
"nikic/fast-route": "^1.3",
+ "paragonie/hidden-string": "^1.0",
"pear/text_languagedetect": "1.*",
"pragmarx/google2fa": "^5.0",
"pragmarx/recovery": "^0.1.0",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "67821d2270bdf8cdd24e7a047b9544e7",
+ "content-hash": "eb985236d64ed0b0fe1fc2e4ac6616e2",
"packages": [
{
"name": "asika/simple-console",
},
{
"name": "paragonie/constant_time_encoding",
- "version": "v1.0.4",
+ "version": "v2.2.3",
"source": {
"type": "git",
"url": "https://github.com/paragonie/constant_time_encoding.git",
- "reference": "2132f0f293d856026d7d11bd81b9f4a23a1dc1f6"
+ "reference": "55af0dc01992b4d0da7f6372e2eac097bbbaffdb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/2132f0f293d856026d7d11bd81b9f4a23a1dc1f6",
- "reference": "2132f0f293d856026d7d11bd81b9f4a23a1dc1f6",
+ "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/55af0dc01992b4d0da7f6372e2eac097bbbaffdb",
+ "reference": "55af0dc01992b4d0da7f6372e2eac097bbbaffdb",
"shasum": ""
},
"require": {
- "php": "^5.3|^7"
+ "php": "^7"
},
"require-dev": {
- "paragonie/random_compat": "^1.4|^2",
- "phpunit/phpunit": "4.*|5.*",
- "vimeo/psalm": "^0.3|^1"
+ "phpunit/phpunit": "^6|^7",
+ "vimeo/psalm": "^1|^2"
},
"type": "library",
"autoload": {
"hex2bin",
"rfc4648"
],
- "time": "2018-04-30T17:57:16+00:00"
+ "time": "2019-01-03T20:26:31+00:00"
+ },
+ {
+ "name": "paragonie/hidden-string",
+ "version": "v1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/paragonie/hidden-string.git",
+ "reference": "0bbb00be0e33b8e1d48fa79ea35cd42d3091a936"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/paragonie/hidden-string/zipball/0bbb00be0e33b8e1d48fa79ea35cd42d3091a936",
+ "reference": "0bbb00be0e33b8e1d48fa79ea35cd42d3091a936",
+ "shasum": ""
+ },
+ "require": {
+ "paragonie/constant_time_encoding": "^2",
+ "paragonie/sodium_compat": "^1.6",
+ "php": "^7"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6|^7",
+ "vimeo/psalm": "^1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "ParagonIE\\HiddenString\\": "./src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MPL-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Paragon Initiative Enterprises",
+ "email": "info@paragonie.com",
+ "homepage": "https://paragonie.com"
+ }
+ ],
+ "description": "Encapsulate strings in an object to hide them from stack traces",
+ "homepage": "https://github.com/paragonie/hidden-string",
+ "keywords": [
+ "hidden",
+ "stack trace",
+ "string"
+ ],
+ "time": "2018-05-07T20:28:06+00:00"
},
{
"name": "paragonie/random_compat",
"version": "v1.6.5",
"source": {
"type": "git",
- "url": "https://github.com/mikey179/vfsStream.git",
+ "url": "https://github.com/bovigo/vfsStream.git",
"reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/mikey179/vfsStream/zipball/d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
+ "url": "https://api.github.com/repos/bovigo/vfsStream/zipball/d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
"reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
"shasum": ""
},
}
],
"description": "Provides the functionality to compare PHP values for equality",
- "homepage": "http://www.github.com/sebastianbergmann/comparator",
+ "homepage": "https://github.com/sebastianbergmann/comparator",
"keywords": [
"comparator",
"compare",
}
],
"description": "Provides functionality to handle HHVM/PHP environments",
- "homepage": "http://www.github.com/sebastianbergmann/environment",
+ "homepage": "https://github.com/sebastianbergmann/environment",
"keywords": [
"Xdebug",
"environment",
}
],
"description": "Provides the functionality to export PHP variables for visualization",
- "homepage": "http://www.github.com/sebastianbergmann/exporter",
+ "homepage": "https://github.com/sebastianbergmann/exporter",
"keywords": [
"export",
"exporter"
}
],
"description": "Snapshotting of global state",
- "homepage": "http://www.github.com/sebastianbergmann/global-state",
+ "homepage": "https://github.com/sebastianbergmann/global-state",
"keywords": [
"global state"
],
}
],
"description": "Provides functionality to recursively process PHP variables",
- "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
+ "homepage": "https://github.com/sebastianbergmann/recursion-context",
"time": "2016-11-19T07:33:16+00:00"
},
{
},
{
"name": "Gert de Pagter",
- "email": "backendtea@gmail.com"
+ "email": "BackEndTea@gmail.com"
}
],
"description": "Symfony polyfill for ctype functions",
*
*/
- $res = Network::post($dfrn_confirm, $params, null, $redirects, 120)->getBody();
+ $res = Network::post($dfrn_confirm, $params, [], 120)->getBody();
Logger::log(' Confirm: received data: ' . $res, Logger::DATA);
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Strings;
use Friendica\Util\Temporal;
+use Friendica\Worker\Delivery;
function events_init(App $a)
{
$item_id = Event::store($datarray);
if (!$cid) {
- Worker::add(PRIORITY_HIGH, "Notifier", "event", $item_id);
+ Worker::add(PRIORITY_HIGH, "Notifier", Delivery::POST, $item_id);
}
$a->internalRedirect('events');
use Friendica\Database\DBA;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Strings;
+use Friendica\Worker\Delivery;
function fsuggest_post(App $a)
{
'photo' => $contact['avatar'], 'note' => $note, 'created' => DateTimeFormat::utcNow()];
DBA::insert('fsuggest', $fields);
- Worker::add(PRIORITY_HIGH, 'Notifier', 'suggest', DBA::lastInsertId());
+ Worker::add(PRIORITY_HIGH, 'Notifier', Delivery::SUGGESTION, DBA::lastInsertId());
info(L10n::t('Friend suggestion sent.') . EOL);
}
$origin = $_REQUEST['origin'];
}
- $notify_type = ($toplevel_item_id ? Delivery::COMMENT : Delivery::POST);
-
$uri = ($message_id ? $message_id : Item::newURI($api_source ? $profile_uid : $uid, $guid));
// Fallback so that we alway have a parent uri
// When we are doing some forum posting via ! we have to start the notifier manually.
// These kind of posts don't initiate the notifier call in the item class.
if ($only_to_forum) {
- Worker::add(PRIORITY_HIGH, "Notifier", $notify_type, $post_id);
+ Worker::add(PRIORITY_HIGH, "Notifier", Delivery::POST, $post_id);
}
Logger::log('post_complete');
// Check if the URL is an image, video or audio file. If so format
// the URL with the corresponding BBCode media tag
- $redirects = 0;
// Fetch the header of the URL
- $curlResponse = Network::curl($url, false, $redirects, ['novalidate' => true, 'nobody' => true]);
+ $curlResponse = Network::curl($url, false, ['novalidate' => true, 'nobody' => true]);
if ($curlResponse->isSuccess()) {
// Convert the header fields into an array
use Friendica\Util\Network;
use Friendica\Util\Strings;
use Friendica\Util\Temporal;
+use Friendica\Worker\Delivery;
function get_theme_config_file($theme)
{
BaseModule::checkFormSecurityTokenRedirectOnError('/settings', 'settings');
if (!empty($_POST['resend_relocate'])) {
- Worker::add(PRIORITY_HIGH, 'Notifier', 'relocate', local_user());
+ Worker::add(PRIORITY_HIGH, 'Notifier', Delivery::RELOCATION, local_user());
info(L10n::t("Relocate message has been send to your contacts"));
$a->internalRedirect('settings');
}
use Friendica\Model\Item;
use Friendica\Util\Strings;
use Friendica\Util\XML;
+use Friendica\Worker\Delivery;
function tagger_content(App $a) {
Hook::callAll('post_local_end', $arr);
- Worker::add(PRIORITY_HIGH, "Notifier", "tag", $post_id);
+ Worker::add(PRIORITY_HIGH, "Notifier", Delivery::POST, $post_id);
exit();
}
if (!in_array($ext, $noexts)) {
// try oembed autodiscovery
- $redirects = 0;
- $html_text = Network::fetchUrl($embedurl, false, $redirects, 15, 'text/*');
+ $html_text = Network::fetchUrl($embedurl, false, 15, 'text/*');
if ($html_text) {
$dom = @DOMDocument::loadHTML($html_text);
if ($dom) {
if (preg_match_all("(\[url=([$URLSearchString]*)\]\s*\[img\]([$URLSearchString]*)\[\/img\]\s*\[\/url\])ism", $body, $pictures, PREG_SET_ORDER)) {
if ((count($pictures) == 1) && !$has_title) {
- // Checking, if the link goes to a picture
- $data = ParseUrl::getSiteinfoCached($pictures[0][1], true);
+ if (!empty($item['object-type']) && ($item['object-type'] == ACTIVITY_OBJ_IMAGE)) {
+ // Replace the preview picture with the real picture
+ $url = str_replace('-1.', '-0.', $pictures[0][2]);
+ $data = ['url' => $url, 'type' => 'photo'];
+ } else {
+ // Checking, if the link goes to a picture
+ $data = ParseUrl::getSiteinfoCached($pictures[0][1], true);
+ }
// Workaround:
// Sometimes photo posts to the own album are not detected at the start.
}
$post["preview"] = $pictures[0][2];
- $post["text"] = str_replace($pictures[0][0], "", $body);
+ $post["text"] = trim(str_replace($pictures[0][0], "", $body));
} else {
$imgdata = Image::getInfoFromURL($pictures[0][1]);
if ($imgdata && substr($imgdata["mime"], 0, 6) == "image/") {
$post["type"] = "photo";
$post["image"] = $pictures[0][1];
$post["preview"] = $pictures[0][2];
- $post["text"] = str_replace($pictures[0][0], "", $body);
+ $post["text"] = trim(str_replace($pictures[0][0], "", $body));
}
}
} elseif (count($pictures) > 0) {
}
$return = '';
- if ($simplehtml == 7) {
+ if (in_array($simplehtml, [7, 9])) {
$return = self::convertUrlForOStatus($data["url"]);
} elseif (($simplehtml != 4) && ($simplehtml != 0)) {
$return = sprintf('<a href="%s" target="_blank">%s</a><br>', $data["url"], $data["title"]);
$text = ($is_quote_share? '<br />' : '') . '<p>' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ': </p>' . "\n" . $content;
break;
case 7: // statusnet/GNU Social
+ case 9: // ActivityPub
$text = ($is_quote_share? '<br />' : '') . '<p>' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' @' . $author_contact['addr'] . ': ' . $content . '</p>' . "\n";
break;
- case 9: // Google+
- $text = ($is_quote_share? '<br />' : '') . '<p>' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ': </p>' . "\n";
- $text .= '<p>' . $content . '</p>' . "\n";
-
- if ($attributes['link'] != '') {
- $text .= '<p>' . $attributes['link'] . '</p>';
- }
- break;
default:
// Transforms quoted tweets in rich attachments to avoid nested tweets
if (stripos(Strings::normaliseLink($attributes['link']), 'http://twitter.com/') === 0 && OEmbed::isAllowedURL($attributes['link'])) {
* Simple HTML values meaning:
* - 0: Friendica display
* - 1: Unused
- * - 2: Used for Google+, Windows Phone push, Friendica API
+ * - 2: Used for Windows Phone push, Friendica API
* - 3: Used before converting to Markdown in bb2diaspora.php
* - 4: Used for WordPress, Libertree (before Markdown), pump.io and tumblr
* - 5: Unused
* - 6: Unused
* - 7: Used for dfrn, OStatus
* - 8: Used for WP backlink text setting
+ * - 9: ActivityPub
*
* @param string $text
* @param bool $try_oembed
// if the HTML is used to generate plain text, then don't do this search, but replace all URL of that kind to text
if (!$for_plaintext) {
$text = preg_replace(Strings::autoLinkRegEx(), '[url]$1[/url]', $text);
- if ($simple_html == 7) {
+ if (in_array($simple_html, [7, 9])) {
$text = preg_replace_callback("/\[url\]([$URLSearchString]*)\[\/url\]/ism", 'self::convertUrlForOStatusCallback', $text);
$text = preg_replace_callback("/\[url\=([$URLSearchString]*)\]([$URLSearchString]*)\[\/url\]/ism", 'self::convertUrlForOStatusCallback', $text);
}
$text = str_replace(["\r","\n"], ['<br />', '<br />'], $text);
// Remove all hashtag addresses
- if ((!$try_oembed || $simple_html) && !in_array($simple_html, [3, 7])) {
+ if ((!$try_oembed || $simple_html) && !in_array($simple_html, [3, 7, 9])) {
$text = preg_replace("/([#@!])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $text);
} elseif ($simple_html == 3) {
// The ! is converted to @ since Diaspora only understands the @
$text = preg_replace("/([@!])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
'@<a href="$2">$3</a>',
$text);
- } elseif ($simple_html == 7) {
+ } elseif (in_array($simple_html, [7, 9])) {
$text = preg_replace("/([@!])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
'$1<span class="vcard"><a href="$2" class="url u-url mention" title="$3"><span class="fn nickname mention">$3</span></a></span>',
$text);
$text = preg_replace("/#\[url\=[$URLSearchString]*\]\^\[\/url\]\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/i",
"[bookmark=$1]$2[/bookmark]", $text);
- if (in_array($simple_html, [2, 6, 7, 8, 9])) {
+ if (in_array($simple_html, [2, 6, 7, 8])) {
$text = preg_replace_callback("/([^#@!])\[url\=([^\]]*)\](.*?)\[\/url\]/ism", "self::expandLinksCallback", $text);
//$Text = preg_replace("/[^#@!]\[url\=([^\]]*)\](.*?)\[\/url\]/ism", ' $2 [url]$1[/url]', $Text);
$text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", ' $2 [url]$1[/url]',$text);
namespace Friendica\Core\Config\Cache;
+use ParagonIE\HiddenString\HiddenString;
+
/**
* The Friendica config cache for the application
* Initial, all *.config.php files are loaded into this cache with the
*/
private $config;
+ /**
+ * @var bool
+ */
+ private $hidePasswordOutput;
+
/**
* @param array $config A initial config array
+ * @param bool $hidePasswordOutput True, if cache variables should take extra care of password values
*/
- public function __construct(array $config = [])
+ public function __construct(array $config = [], $hidePasswordOutput = true)
{
+ $this->hidePasswordOutput = $hidePasswordOutput;
$this->load($config);
}
$this->config[$cat] = [];
}
- $this->config[$cat][$key] = $value;
-
+ if ($this->hidePasswordOutput &&
+ $key == 'password' &&
+ !empty($value) && is_string($value)) {
+ $this->config[$cat][$key] = new HiddenString((string) $value);
+ } else {
+ $this->config[$cat][$key] = $value;
+ }
return true;
}
if (isset($dbvalue)) {
$this->configCache->set($cat, $key, $dbvalue);
- return $dbvalue;
+ unset($dbvalue);
}
}
$searchUrl .= '&page=' . $page;
}
- $red = 0;
- $resultJson = Network::fetchUrl($searchUrl, false, $red, 0, 'application/json');
+ $resultJson = Network::fetchUrl($searchUrl, false, 0, 'application/json');
$results = json_decode($resultJson, true);
use Friendica\Model\Photo;
use Friendica\Object\Image;
use Friendica\Util\Strings;
+use Friendica\Worker\Delivery;
/**
* @brief UserImport class
}
// send relocate messages
- Worker::add(PRIORITY_HIGH, 'Notifier', 'relocate', $newuid);
+ Worker::add(PRIORITY_HIGH, 'Notifier', Delivery::RELOCATION, $newuid);
info(L10n::t("Done. You can now login with your username and password"));
$a->internalRedirect('login');
}
$url = System::baseUrl()."/worker";
- Network::fetchUrl($url, false, $redirects, 1);
+ Network::fetchUrl($url, false, 1);
}
/**
* @param (integer|array) priority or parameter array, strings are deprecated and are ignored
*
* next args are passed as $cmd command line
- * or: Worker::add(PRIORITY_HIGH, "Notifier", "drop", $drop_id);
+ * or: Worker::add(PRIORITY_HIGH, "Notifier", Delivery::DELETION, $drop_id);
* or: Worker::add(array('priority' => PRIORITY_HIGH, 'dont_fork' => true), "CreateShadowEntry", $post_id);
*
* @return boolean "false" if proc_run couldn't be executed
use Friendica\Database;
use Friendica\Util\Logger\VoidLogger;
use Friendica\Util\Profiler;
+use ParagonIE\HiddenString\HiddenString;
class DBFactory
{
} else {
$db_user = $server['MYSQL_USER'];
}
- $db_pass = (string) $server['MYSQL_PASSWORD'];
+ $db_pass = new HiddenString((string) $server['MYSQL_PASSWORD']);
$db_data = $server['MYSQL_DATABASE'];
}
$webfinger = 'https://' . $addr_parts[1] . '/.well-known/webfinger?resource=acct:' . urlencode($addr);
- $curlResult = Network::curl($webfinger, false, $redirects, ['accept_content' => 'application/jrd+json,application/json']);
+ $curlResult = Network::curl($webfinger, false, ['accept_content' => 'application/jrd+json,application/json']);
if (!$curlResult->isSuccess() || empty($curlResult->getBody())) {
return false;
}
$apcontact['alias'] = JsonLD::fetchElement($compacted['as:url'], 'as:href', '@id');
}
- if (empty($apcontact['url']) || empty($apcontact['inbox'])) {
+ // Quit if none of the basic values are set
+ if (empty($apcontact['url']) || empty($apcontact['inbox']) || empty($apcontact['type'])) {
+ return false;
+ }
+
+ // Quit if this doesn't seem to be an account at all
+ if (!in_array($apcontact['type'], ActivityPub::ACCOUNT_TYPES)) {
return false;
}
DBA::update('contact', $contact_fields, ['nurl' => Strings::normaliseLink($url)]);
- $contacts = DBA::select('contact', ['uid', 'id'], ['nurl' => Strings::normaliseLink($url)]);
- while ($contact = DBA::fetch($contacts)) {
- Contact::updateAvatar($apcontact['photo'], $contact['uid'], $contact['id']);
+ if (!empty($apcontact['photo'])) {
+ $contacts = DBA::select('contact', ['uid', 'id'], ['nurl' => Strings::normaliseLink($url)]);
+ while ($contact = DBA::fetch($contacts)) {
+ Contact::updateAvatar($apcontact['photo'], $contact['uid'], $contact['id']);
+ }
+ DBA::close($contacts);
}
- DBA::close($contacts);
// Update the gcontact table
// These two fields don't exist in the gcontact table
if (!empty($contact)) {
// Contact is blocked at user-level
- if (self::isBlockedByUser($contact['id'], $importer['id'])) {
+ if (!empty($contact['id']) && !empty($importer['id']) &&
+ self::isBlockedByUser($contact['id'], $importer['id'])) {
return false;
}
// We only need to notfiy others when it is an original entry from us.
// Only call the notifier when the item has some content relevant change.
if ($item['origin'] && in_array('edited', array_keys($fields))) {
- Worker::add(PRIORITY_HIGH, "Notifier", 'edit_post', $item['id']);
+ Worker::add(PRIORITY_HIGH, "Notifier", Delivery::POST, $item['id']);
}
}
self::delete(['uri' => $item['uri'], 'deleted' => false], $priority);
// send the notification upstream/downstream
- Worker::add(['priority' => $priority, 'dont_fork' => true], "Notifier", "drop", intval($item['id']));
+ Worker::add(['priority' => $priority, 'dont_fork' => true], "Notifier", Delivery::DELETION, intval($item['id']));
} elseif ($item['uid'] != 0) {
// When we delete just our local user copy of an item, we have to set a marker to hide it
$item['thr-parent'] = $item['parent-uri'];
- $notify_type = '';
+ $notify_type = Delivery::POST;
$allow_cid = '';
$allow_gid = '';
$deny_cid = '';
$allow_gid = $item['allow_gid'];
$deny_cid = $item['deny_cid'];
$deny_gid = $item['deny_gid'];
- $notify_type = Delivery::POST;
} else {
// find the parent and snarf the item id and ACLs
// and anything else we need to inherit
$deny_cid = $parent['deny_cid'];
$deny_gid = $parent['deny_gid'];
$item['wall'] = $parent['wall'];
- $notify_type = Delivery::COMMENT;
/*
* If the parent is private, force privacy for the entire conversation
check_user_notification($current_post);
- if ($notify) {
+ if ($notify || ($item['visible'] && ((!empty($parent) && $parent['origin']) || $item['origin']))) {
Worker::add(['priority' => $priority, 'dont_fork' => true], 'Notifier', $notify_type, $current_post);
- } elseif ($item['visible'] && ((!empty($parent) && $parent['origin']) || $item['origin'])) {
- if ($item['gravity'] == GRAVITY_ACTIVITY) {
- $cmd = $item['origin'] ? Delivery::ACTIVITY : 'activity-import';
- } elseif ($item['gravity'] == GRAVITY_COMMENT) {
- $cmd = $item['origin'] ? Delivery::COMMENT : 'comment-import';
- } elseif (!empty($notify_type)) {
- $cmd = $notify_type;
- } else {
- $cmd = Delivery::POST;
- }
-
- Worker::add(['priority' => $priority, 'dont_fork' => true], 'Notifier', $cmd, $current_post);
}
return $current_post;
self::updateThread($item_id);
- Worker::add(['priority' => PRIORITY_HIGH, 'dont_fork' => true], 'Notifier', 'tgroup', $item_id);
+ Worker::add(['priority' => PRIORITY_HIGH, 'dont_fork' => true], 'Notifier', Delivery::POST, $item_id);
}
public static function isRemoteSelf($contact, &$datarray)
use Friendica\Database\DBA;
use Friendica\Network\Probe;
use Friendica\Util\DateTimeFormat;
+use Friendica\Worker\Delivery;
/**
* Class to handle private messages
}
if ($post_id) {
- Worker::add(PRIORITY_HIGH, "Notifier", "mail", $post_id);
+ Worker::add(PRIORITY_HIGH, "Notifier", Delivery::MAIL, $post_id);
return intval($post_id);
} else {
return -3;
$photo_failure = false;
$filename = basename($image_url);
- $img_str = Network::fetchUrl($image_url, true);
+ if (!empty($image_url)) {
+ $img_str = Network::fetchUrl($image_url, true);
+ } else {
+ $img_str = '';
+ }
if ($quit_on_error && ($img_str == "")) {
return false;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Network;
use Friendica\Util\Strings;
+use Friendica\Worker\Delivery;
use LightOpenID;
/**
// The user and related data will be deleted in "cron_expire_and_remove_users" (cronjobs.php)
DBA::update('user', ['account_removed' => true, 'account_expires_on' => DateTimeFormat::utc('now + 7 day')], ['uid' => $uid]);
- Worker::add(PRIORITY_HIGH, 'Notifier', 'removeme', $uid);
+ Worker::add(PRIORITY_HIGH, 'Notifier', Delivery::REMOVAL, $uid);
// Send an update to the directory
$self = DBA::selectFirst('contact', ['url'], ['uid' => $uid, 'self' => true]);
use Friendica\Util\BasePath;
use Friendica\Util\BaseURL;
use Friendica\Util\Strings;
+use Friendica\Worker\Delivery;
require_once __DIR__ . '/../../../boot.php';
// send relocate
$usersStmt = DBA::select('user', ['uid'], ['account_removed' => false, 'account_expired' => false]);
while ($user = DBA::fetch($usersStmt)) {
- Worker::add(PRIORITY_HIGH, 'Notifier', 'relocate', $user['uid']);
+ Worker::add(PRIORITY_HIGH, 'Notifier', Delivery::RELOCATION, $user['uid']);
}
info("Relocation started. Could take a while to complete.");
);
// Try to get an authentication token from the other instance.
- $curlResult = Network::curl($basepath . '/owa', false, $redirects, ['headers' => $headers]);
+ $curlResult = Network::curl($basepath . '/owa', false, ['headers' => $headers]);
if ($curlResult->isSuccess()) {
$j = json_decode($curlResult->getBody(), true);
$url = "http://".$host."/.well-known/host-meta";
$xrd_timeout = Config::get('system', 'xrd_timeout', 20);
- $redirects = 0;
Logger::log("Probing for ".$host, Logger::DEBUG);
$xrd = null;
- $curlResult = Network::curl($ssl_url, false, $redirects, ['timeout' => $xrd_timeout, 'accept_content' => 'application/xrd+xml']);
+ $curlResult = Network::curl($ssl_url, false, ['timeout' => $xrd_timeout, 'accept_content' => 'application/xrd+xml']);
if ($curlResult->isSuccess()) {
$xml = $curlResult->getBody();
$xrd = XML::parseString($xml, false);
}
if (!is_object($xrd)) {
- $curlResult = Network::curl($url, false, $redirects, ['timeout' => $xrd_timeout, 'accept_content' => 'application/xrd+xml']);
+ $curlResult = Network::curl($url, false, ['timeout' => $xrd_timeout, 'accept_content' => 'application/xrd+xml']);
if ($curlResult->isTimeout()) {
Logger::log("Probing timeout for " . $url, Logger::DEBUG);
self::$istimeout = true;
private static function webfinger($url, $type)
{
$xrd_timeout = Config::get('system', 'xrd_timeout', 20);
- $redirects = 0;
- $curlResult = Network::curl($url, false, $redirects, ['timeout' => $xrd_timeout, 'accept_content' => $type]);
+ $curlResult = Network::curl($url, false, ['timeout' => $xrd_timeout, 'accept_content' => $type]);
if ($curlResult->isTimeout()) {
self::$istimeout = true;
return false;
$data = Cache::get($url);
if (is_null($data) || !$data || !is_array($data)) {
- $img_str = Network::fetchUrl($url, true, $redirects, 4);
+ $img_str = Network::fetchUrl($url, true, 4);
if (!$img_str) {
return false;
return HTTPSignature::fetch($url, $uid);
}
- $curlResult = Network::curl($url, false, $redirects, ['accept_content' => 'application/activity+json, application/ld+json']);
+ $curlResult = Network::curl($url, false, ['accept_content' => 'application/activity+json, application/ld+json']);
if (!$curlResult->isSuccess() || empty($curlResult->getBody())) {
return false;
}
$data['to'][] = $profile['url'];
} else {
$data['cc'][] = $profile['url'];
- if (!$item['private']) {
+ if (!$item['private'] && !empty($actor_profile['followers'])) {
$data['cc'][] = $actor_profile['followers'];
}
}
{
$event = [];
$event['name'] = $item['event-summary'];
- $event['content'] = BBCode::convert($item['event-desc'], false, 7);
+ $event['content'] = BBCode::convert($item['event-desc'], false, 9);
$event['startTime'] = DateTimeFormat::utc($item['event-start'] . '+00:00', DateTimeFormat::ATOM);
if (!$item['event-nofinish']) {
$regexp = "/[@!]\[url\=([^\[\]]*)\].*?\[\/url\]/ism";
$body = preg_replace_callback($regexp, ['self', 'mentionCallback'], $body);
- $data['content'] = BBCode::convert($body, false, 7);
+ $data['content'] = BBCode::convert($body, false, 9);
}
$data['source'] = ['content' => $item['body'], 'mediaType' => "text/bbcode"];
{
Logger::log("Process verb ".$item["verb"]." and object-type ".$item["object-type"]." for entrytype ".$entrytype, Logger::DEBUG);
- if (($entrytype == DFRN::TOP_LEVEL)) {
+ if (($entrytype == DFRN::TOP_LEVEL) && !empty($importer['id'])) {
// The filling of the the "contact" variable is done for legcy reasons
// The functions below are partly used by ostatus.php as well - where we have this variable
- $r = q("SELECT * FROM `contact` WHERE `id` = %d", intval($importer["id"]));
- $contact = $r[0];
+ $contact = Contact::select([], ['id' => $importer['id']]);
// Big question: Do we need these functions? They were part of the "consume_feed" function.
// This function once was responsible for DFRN and OStatus.
if ($comment['id'] == $comment['parent']) {
continue;
}
- if ($comment['verb'] == ACTIVITY_POST) {
- $cmd = $comment['self'] ? Delivery::COMMENT : 'comment-import';
- } else {
- $cmd = $comment['self'] ? Delivery::ACTIVITY : 'activity-import';
- }
- Logger::log("Send ".$cmd." for item ".$comment['id']." to contact ".$contact_id, Logger::DEBUG);
- Worker::add(PRIORITY_HIGH, 'Delivery', $cmd, $comment['id'], $contact_id);
+
+ Logger::info('Deliver participation', ['item' => $comment['id'], 'contact' => $contact_id]);
+ Worker::add(PRIORITY_HIGH, 'Delivery', Delivery::POST, $comment['id'], $contact_id);
}
DBA::close($comments);
self::$conv_list[$conversation] = true;
- $curlResult = Network::curl($conversation, false, $redirects, ['accept_content' => 'application/atom+xml, text/html']);
+ $curlResult = Network::curl($conversation, false, ['accept_content' => 'application/atom+xml, text/html']);
if (!$curlResult->isSuccess()) {
return;
}
$stored = false;
- $curlResult = Network::curl($related, false, $redirects, ['accept_content' => 'application/atom+xml, text/html']);
+ $curlResult = Network::curl($related, false, ['accept_content' => 'application/atom+xml, text/html']);
if (!$curlResult->isSuccess()) {
return;
$server_url = str_replace("http://", "https://", $server_url);
// We set the timeout to 20 seconds since this operation should be done in no time if the server was vital
- $curlResult = Network::curl($server_url."/.well-known/host-meta", false, $redirects, ['timeout' => 20]);
+ $curlResult = Network::curl($server_url."/.well-known/host-meta", false, ['timeout' => 20]);
// Quit if there is a timeout.
// But we want to make sure to only quit if we are mostly sure that this server url fits.
$server_url = str_replace("https://", "http://", $server_url);
// We set the timeout to 20 seconds since this operation should be done in no time if the server was vital
- $curlResult = Network::curl($server_url."/.well-known/host-meta", false, $redirects, ['timeout' => 20]);
+ $curlResult = Network::curl($server_url."/.well-known/host-meta", false, ['timeout' => 20]);
// Quit if there is a timeout
if ($curlResult->isTimeout()) {
if (!empty($accesstoken)) {
$api = 'https://instances.social/api/1.0/instances/list?count=0';
$header = ['Authorization: Bearer '.$accesstoken];
- $curlResult = Network::curl($api, false, $redirects, ['headers' => $header]);
+ $curlResult = Network::curl($api, false, ['headers' => $header]);
if ($curlResult->isSuccess()) {
$servers = json_decode($curlResult->getBody(), true);
$curl_opts = $opts;
$curl_opts['header'] = $headers;
- $curlResult = Network::curl($request, false, $redirects, $curl_opts);
+ $curlResult = Network::curl($request, false, $curl_opts);
$return_code = $curlResult->getReturnCode();
Logger::log('Fetched for user ' . $uid . ' from ' . $request . ' returned ' . $return_code, Logger::DEBUG);
*
* @brief Curl wrapper
* @param string $url URL to fetch
- * @param boolean $binary default false
+ * @param bool $binary default false
* TRUE if asked to return binary results (file download)
- * @param integer $redirects The recursion counter for internal use - default 0
- * @param integer $timeout Timeout in seconds, default system config value or 60 seconds
+ * @param int $timeout Timeout in seconds, default system config value or 60 seconds
* @param string $accept_content supply Accept: header with 'accept_content' as the value
* @param string $cookiejar Path to cookie jar file
+ * @param int $redirects The recursion counter for internal use - default 0
*
* @return string The fetched content
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
- public static function fetchUrl($url, $binary = false, &$redirects = 0, $timeout = 0, $accept_content = null, $cookiejar = '')
+ public static function fetchUrl(string $url, bool $binary = false, int $timeout = 0, string $accept_content = '', string $cookiejar = '', int &$redirects = 0)
{
- $ret = self::fetchUrlFull($url, $binary, $redirects, $timeout, $accept_content, $cookiejar);
+ $ret = self::fetchUrlFull($url, $binary, $timeout, $accept_content, $cookiejar, $redirects);
return $ret->getBody();
}
*
* @brief Curl wrapper with array of return values.
* @param string $url URL to fetch
- * @param boolean $binary default false
+ * @param bool $binary default false
* TRUE if asked to return binary results (file download)
- * @param integer $redirects The recursion counter for internal use - default 0
- * @param integer $timeout Timeout in seconds, default system config value or 60 seconds
+ * @param int $timeout Timeout in seconds, default system config value or 60 seconds
* @param string $accept_content supply Accept: header with 'accept_content' as the value
* @param string $cookiejar Path to cookie jar file
+ * @param int $redirects The recursion counter for internal use - default 0
*
* @return CurlResult With all relevant information, 'body' contains the actual fetched content.
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
- public static function fetchUrlFull($url, $binary = false, &$redirects = 0, $timeout = 0, $accept_content = null, $cookiejar = '')
+ public static function fetchUrlFull(string $url, bool $binary = false, int $timeout = 0, string $accept_content = '', string $cookiejar = '', int &$redirects = 0)
{
return self::curl(
$url,
$binary,
- $redirects,
- ['timeout'=>$timeout,
- 'accept_content'=>$accept_content,
- 'cookiejar'=>$cookiejar
- ]
+ [
+ 'timeout' => $timeout,
+ 'accept_content' => $accept_content,
+ 'cookiejar' => $cookiejar
+ ],
+ $redirects
);
}
* @brief fetches an URL.
*
* @param string $url URL to fetch
- * @param boolean $binary default false
+ * @param bool $binary default false
* TRUE if asked to return binary results (file download)
- * @param int $redirects The recursion counter for internal use - default 0
* @param array $opts (optional parameters) assoziative array with:
* 'accept_content' => supply Accept: header with 'accept_content' as the value
* 'timeout' => int Timeout in seconds, default system config value or 60 seconds
* 'nobody' => only return the header
* 'cookiejar' => path to cookie jar file
* 'header' => header array
+ * @param int $redirects The recursion counter for internal use - default 0
*
* @return CurlResult
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
- public static function curl($url, $binary = false, &$redirects = 0, $opts = [])
+ public static function curl(string $url, bool $binary = false, array $opts = [], int &$redirects = 0)
{
$stamp1 = microtime(true);
$redirects++;
Logger::log('curl: redirect ' . $url . ' to ' . $curlResponse->getRedirectUrl());
@curl_close($ch);
- return self::curl($curlResponse->getRedirectUrl(), $binary, $redirects, $opts);
+ return self::curl($curlResponse->getRedirectUrl(), $binary, $opts, $redirects);
}
@curl_close($ch);
*
* @param string $url URL to post
* @param mixed $params array of POST variables
- * @param string $headers HTTP headers
- * @param integer $redirects Recursion counter for internal use - default = 0
- * @param integer $timeout The timeout in seconds, default system config value or 60 seconds
+ * @param array $headers HTTP headers
+ * @param int $redirects Recursion counter for internal use - default = 0
+ * @param int $timeout The timeout in seconds, default system config value or 60 seconds
*
* @return CurlResult The content
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
- public static function post($url, $params, $headers = null, &$redirects = 0, $timeout = 0)
+ public static function post(string $url, $params, array $headers = [], int $timeout = 0, int &$redirects = 0)
{
$stamp1 = microtime(true);
}
if (defined('LIGHTTPD')) {
- if (!is_array($headers)) {
+ if (empty($headers)) {
$headers = ['Expect:'];
} else {
if (!in_array('Expect:', $headers)) {
}
}
- if ($headers) {
+ if (!empty($headers)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
* @return string|boolean The actual working URL, false else
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
- public static function isUrlValid($url)
+ public static function isUrlValid(string $url)
{
if (Config::get('system', 'disable_url_validation')) {
return $url;
*
* @param string $addr The email address
* @return boolean True if it's a valid email address, false if it's not
- * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
- public static function isEmailDomainValid($addr)
+ public static function isEmailDomainValid(string $addr)
{
if (Config::get('system', 'disable_email_validation')) {
return true;
*
* @param string $url URL which get tested
* @return boolean True if url is allowed otherwise return false
- * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
- public static function isUrlAllowed($url)
+ public static function isUrlAllowed(string $url)
{
$h = @parse_url($url);
*
* @return boolean
*/
- public static function isUrlBlocked($url)
+ public static function isUrlBlocked(string $url)
{
$host = @parse_url($url, PHP_URL_HOST);
if (!$host) {
* or if allowed list is not configured
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
- public static function isEmailDomainAllowed($email)
+ public static function isEmailDomainAllowed(string $email)
{
$domain = strtolower(substr($email, strpos($email, '@') + 1));
if (!$domain) {
* @param array $domain_list
* @return boolean
*/
- public static function isDomainAllowed($domain, array $domain_list)
+ public static function isDomainAllowed(string $domain, array $domain_list)
{
$found = false;
return $found;
}
- public static function lookupAvatarByEmail($email)
+ public static function lookupAvatarByEmail(string $email)
{
$avatar['size'] = 300;
$avatar['email'] = $email;
* @param string $url Any user-submitted URL that may contain tracking params
* @return string The same URL stripped of tracking parameters
*/
- public static function stripTrackingQueryParams($url)
+ public static function stripTrackingQueryParams(string $url)
{
$urldata = parse_url($url);
if (!empty($urldata["query"])) {
* @return string A canonical URL
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
- public static function finalUrl($url, $depth = 1, $fetchbody = false)
+ public static function finalUrl(string $url, int $depth = 1, bool $fetchbody = false)
{
$a = \get_app();
* @param string $url2
* @return string The matching part
*/
- public static function getUrlMatch($url1, $url2)
+ public static function getUrlMatch(string $url1, string $url2)
{
if (($url1 == "") || ($url2 == "")) {
return "";
*
* @return string The glued URL
*/
- public static function unparseURL($parsed)
+ public static function unparseURL(array $parsed)
{
$get = function ($key) use ($parsed) {
return isset($parsed[$key]) ? $parsed[$key] : null;
*
* @return string switched URL
*/
- public static function switchScheme($url)
+ public static function switchScheme(string $url)
{
$scheme = parse_url($url, PHP_URL_SCHEME);
if (empty($scheme)) {
*/
if (!$remote_verified) {
- if (DBA::exists('contact', ['id' => $remote_user, 'uid' => $owner_id, 'blocked' => false])) {
+ $cid = 0;
+
+ foreach (\Friendica\Core\Session::get('remote', []) as $visitor) {
+ if ($visitor['uid'] == $owner_id) {
+ $cid = $visitor['cid'];
+ break;
+ }
+ }
+
+ if ($cid && DBA::exists('contact', ['id' => $cid, 'uid' => $owner_id, 'blocked' => false])) {
$remote_verified = true;
- $groups = Group::getIdsByContactId($remote_user);
+ $groups = Group::getIdsByContactId($cid);
}
}
AND ( allow_cid REGEXP '<%d>' OR allow_gid REGEXP '%s' OR ( allow_cid = '' AND allow_gid = '') )
)
",
- intval($remote_user),
+ intval($cid),
DBA::escape($gs),
- intval($remote_user),
+ intval($cid),
DBA::escape($gs)
);
}
$data = ActivityPub\Transmitter::createCachedActivityFromItem($target_id);
if (!empty($data)) {
$success = HTTPSignature::transmit($data, $inbox, $uid);
- if ($success && in_array($cmd, [Delivery::POST, Delivery::COMMENT])) {
+ if ($success && in_array($cmd, [Delivery::POST])) {
ItemDeliveryData::incrementQueueDone($target_id);
}
}
const DELETION = 'drop';
const POST = 'wall-new';
const POKE = 'poke';
- const COMMENT = 'comment-new';
- const ACTIVITY = 'activity-new';
+ const UPLINK = 'uplink';
const REMOVAL = 'removeme';
const PROFILEUPDATE = 'profileupdate';
// We successfully delivered a message, the contact is alive
Model\Contact::unmarkForArchival($contact);
- if (in_array($cmd, [Delivery::POST, Delivery::COMMENT])) {
+ if (in_array($cmd, [Delivery::POST, Delivery::POKE])) {
Model\ItemDeliveryData::incrementQueueDone($target_item['id']);
}
} else {
// We successfully delivered a message, the contact is alive
Model\Contact::unmarkForArchival($contact);
- if (in_array($cmd, [Delivery::POST, Delivery::COMMENT])) {
+ if (in_array($cmd, [Delivery::POST, Delivery::POKE])) {
Model\ItemDeliveryData::incrementQueueDone($target_item['id']);
}
} else {
Logger::info('Delivery failed: defer message', ['id' => defaults($target_item, 'guid', $target_item['id'])]);
// defer message for redelivery
Worker::defer();
- } elseif (in_array($cmd, [Delivery::POST, Delivery::COMMENT])) {
+ } elseif (in_array($cmd, [Delivery::POST, Delivery::POKE])) {
Model\ItemDeliveryData::incrementQueueDone($target_item['id']);
}
}
return;
}
- if (!in_array($cmd, [self::POST, self::COMMENT])) {
+ if (!in_array($cmd, [self::POST, self::POKE])) {
return;
}
*
* Worker::add(PRIORITY_HIGH, "Notifier", COMMAND, ITEM_ID);
*
- * where COMMAND is one of the following:
- *
- * activity (in diaspora.php, dfrn_confirm.php, profiles.php)
- * comment-import (in diaspora.php, items.php)
- * comment-new (in item.php)
- * drop (in diaspora.php, items.php, photos.php)
- * edit_post (in item.php)
- * event (in events.php)
- * like (in like.php, poke.php)
- * mail (in message.php)
- * suggest (in fsuggest.php)
- * tag (in photos.php, poke.php, tagger.php)
- * tgroup (in items.php)
- * wall-new (in photos.php, item.php)
- * removeme (in Contact.php)
- * relocate (in uimport.php)
- *
+ * where COMMAND is one of the constants that are defined in Worker/Delivery.php
* and ITEM_ID is the id of the item in the database that needs to be sent to others.
*/
}
- if (($cmd === 'uplink') && (intval($parent['forum_mode']) == 1) && !$top_level) {
+ if (($cmd === Delivery::UPLINK) && (intval($parent['forum_mode']) == 1) && !$top_level) {
$relay_to_owner = true;
}
// if our parent is a public forum (forum_mode == 1), uplink to the origional author causing
// a delivery fork. private groups (forum_mode == 2) do not uplink
- if ((intval($parent['forum_mode']) == 1) && !$top_level && ($cmd !== 'uplink')) {
- Worker::add($a->queue['priority'], 'Notifier', 'uplink', $target_id);
+ if ((intval($parent['forum_mode']) == 1) && !$top_level && ($cmd !== Delivery::UPLINK)) {
+ Worker::add($a->queue['priority'], 'Notifier', Delivery::UPLINK, $target_id);
}
foreach ($items as $item) {
if (!empty($target_item)) {
Logger::log('Calling hooks for ' . $cmd . ' ' . $target_id, Logger::DEBUG);
- if (in_array($cmd, [Delivery::POST, Delivery::COMMENT])) {
- ItemDeliveryData::update($target_item['id'], ['queue_count' => $delivery_queue_count]);
- }
-
Hook::fork($a->queue['priority'], 'notifier_normal', $target_item);
Hook::callAll('notifier_end', $target_item);
+
+ // Workaround for pure connector posts
+ if ($delivery_queue_count == 0) {
+ ItemDeliveryData::incrementQueueDone($target_item['id']);
+ $delivery_queue_count = 1;
+ }
+
+ if (in_array($cmd, [Delivery::POST, Delivery::POKE])) {
+ ItemDeliveryData::update($target_item['id'], ['queue_count' => $delivery_queue_count]);
+ }
}
return;
}
$cookiejar = tempnam(get_temppath(), 'cookiejar-onepoll-');
- $curlResult = Network::curl($contact['poll'], false, $redirects, ['cookiejar' => $cookiejar]);
+ $curlResult = Network::curl($contact['poll'], false, ['cookiejar' => $cookiejar]);
unlink($cookiejar);
if ($curlResult->isTimeout()) {
$this->assertEmpty($configCache->keyDiff($diffConfig));
}
+
+ /**
+ * Test the default hiding of passwords inside the cache
+ */
+ public function testPasswordHide()
+ {
+ $configCache = new ConfigCache([
+ 'database' => [
+ 'password' => 'supersecure',
+ 'username' => 'notsecured',
+ ],
+ ]);
+
+ $this->assertEquals('supersecure', $configCache->get('database', 'password'));
+ $this->assertNotEquals('supersecure', print_r($configCache->get('database', 'password'), true));
+ $this->assertEquals('notsecured', print_r($configCache->get('database', 'username'), true));
+ }
+
+ /**
+ * Test disabling the hiding of passwords inside the cache
+ */
+ public function testPasswordShow()
+ {
+ $configCache = new ConfigCache([
+ 'database' => [
+ 'password' => 'supersecure',
+ 'username' => 'notsecured',
+ ],
+ ], false);
+
+ $this->assertEquals('supersecure', $configCache->get('database', 'password'));
+ $this->assertEquals('supersecure', print_r($configCache->get('database', 'password'), true));
+ $this->assertEquals('notsecured', print_r($configCache->get('database', 'username'), true));
+ }
+
+ /**
+ * Test a empty password
+ */
+ public function testEmptyPassword()
+ {
+ $configCache = new ConfigCache([
+ 'database' => [
+ 'password' => '',
+ 'username' => '',
+ ]
+ ]);
+
+ $this->assertEmpty($configCache->get('database', 'password'));
+ $this->assertEmpty($configCache->get('database', 'username'));
+ }
+
+ public function testWrongTypePassword()
+ {
+ $configCache = new ConfigCache([
+ 'database' => [
+ 'password' => new \stdClass(),
+ 'username' => '',
+ ]
+ ]);
+
+ $this->assertNotEmpty($configCache->get('database', 'password'));
+ $this->assertEmpty($configCache->get('database', 'username'));
+
+ $configCache = new ConfigCache([
+ 'database' => [
+ 'password' => 23,
+ 'username' => '',
+ ]
+ ]);
+
+ $this->assertEquals(23, $configCache->get('database', 'password'));
+ $this->assertEmpty($configCache->get('database', 'username'));
+ }
}
continue;
}
- if ($item['gravity'] == GRAVITY_PARENT) {
- $cmd = Delivery::POST;
- } else {
- $cmd = Delivery::COMMENT;
- }
-
$deliver_options = ['priority' => PRIORITY_MEDIUM, 'dont_fork' => true];
- Worker::add($deliver_options, 'Delivery', $cmd, $item['id'], $entry['cid']);
+ Worker::add($deliver_options, 'Delivery', Delivery::POST, $item['id'], $entry['cid']);
Logger::info('Added delivery worker', ['command' => $cmd, 'item' => $item['id'], 'contact' => $entry['cid']]);
DBA::delete('queue', ['id' => $entry['id']]);
}