]> git.mxchange.org Git - friendica.git/commitdiff
cron.php is reworked, other worker files had been moved temporarily
authorMichael <heluecht@pirati.ca>
Tue, 14 Nov 2017 21:50:16 +0000 (21:50 +0000)
committerMichael <heluecht@pirati.ca>
Tue, 14 Nov 2017 21:50:16 +0000 (21:50 +0000)
44 files changed:
include/checkversion.php [deleted file]
include/cli_startup.php [deleted file]
include/create_shadowentry.php [deleted file]
include/cron.php [deleted file]
include/cronjobs.php [deleted file]
include/dbclean.php [deleted file]
include/dbupdate.php [deleted file]
include/delivery.php [deleted file]
include/directory.php [deleted file]
include/discover_poco.php [deleted file]
include/expire.php [deleted file]
include/gprobe.php [deleted file]
include/notifier.php [deleted file]
include/profile_update.php [deleted file]
include/pubsubpublish.php [deleted file]
include/queue.php [deleted file]
include/remove_contact.php [deleted file]
include/shadowupdate.php [deleted file]
include/spool_post.php [deleted file]
include/tagupdate.php [deleted file]
include/threadupdate.php [deleted file]
include/update_gcontact.php [deleted file]
src/Core/Worker.php
src/Worker/Cron.php [new file with mode: 0644]
worker/checkversion.php [new file with mode: 0644]
worker/create_shadowentry.php [new file with mode: 0644]
worker/cronjobs.php [new file with mode: 0644]
worker/dbclean.php [new file with mode: 0644]
worker/dbupdate.php [new file with mode: 0644]
worker/delivery.php [new file with mode: 0644]
worker/directory.php [new file with mode: 0644]
worker/discover_poco.php [new file with mode: 0644]
worker/expire.php [new file with mode: 0644]
worker/gprobe.php [new file with mode: 0644]
worker/notifier.php [new file with mode: 0644]
worker/profile_update.php [new file with mode: 0644]
worker/pubsubpublish.php [new file with mode: 0644]
worker/queue.php [new file with mode: 0644]
worker/remove_contact.php [new file with mode: 0644]
worker/shadowupdate.php [new file with mode: 0644]
worker/spool_post.php [new file with mode: 0644]
worker/tagupdate.php [new file with mode: 0644]
worker/threadupdate.php [new file with mode: 0644]
worker/update_gcontact.php [new file with mode: 0644]

diff --git a/include/checkversion.php b/include/checkversion.php
deleted file mode 100644 (file)
index 7d3c2de..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-
-/**
- * @file include/checkversion.php
- *
- * @brief save Friendica upstream version to the DB
- **/
-
-use Friendica\Core\Config;
-
-/**
- * @brief check the git repository VERSION file and save the version to the DB
- *
- * Checking the upstream version is optional (opt-in) and can be done to either
- * the master or the develop branch in the repository.
- */
-function checkversion_run () {
-       global $a;
-
-       logger('checkversion: start');
-
-       $checkurl = Config::get('system', 'check_new_version_url', 'none');
-
-       switch ($checkurl) {
-       case 'master': 
-               $checked_url = 'https://raw.githubusercontent.com/friendica/friendica/master/VERSION'; 
-               break;
-       case 'develop': 
-               $checked_url = 'https://raw.githubusercontent.com/friendica/friendica/develop/VERSION'; 
-               break;
-       default: 
-               // don't check
-               return;
-}
-       logger("Checking VERSION from: ".$checked_url, LOGGER_DEBUG);
-
-       // fetch the VERSION file
-       $gitversion = dbesc(trim(fetch_url($checked_url)));
-       logger("Upstream VERSION is: ".$gitversion, LOGGER_DEBUG);
-
-       Config::set('system', 'git_friendica_version', $gitversion);
-
-       logger('checkversion: end');
-
-       return;
-}
diff --git a/include/cli_startup.php b/include/cli_startup.php
deleted file mode 100644 (file)
index 8cbc7db..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-<?php /** @file */
-
-use Friendica\App;
-use Friendica\Core\Config;
-
-require_once('boot.php');
-
-// Everything we need to boot standalone 'background' processes
-
-function cli_startup() {
-       global $a;
-
-       if (empty($a)) {
-               $a = new App(dirname(__DIR__));
-       }
-
-       @include(".htconfig.php");
-       require_once("dba.php");
-       dba::connect($db_host, $db_user, $db_pass, $db_data);
-       unset($db_host, $db_user, $db_pass, $db_data);
-
-       require_once('include/session.php');
-
-       Config::load();
-
-       $a->set_baseurl(Config::get('system','url'));
-
-       load_hooks();
-}
diff --git a/include/create_shadowentry.php b/include/create_shadowentry.php
deleted file mode 100644 (file)
index 29222de..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-/**
- * @file include/create_shadowentry.php
- * @brief This script creates posts with UID = 0 for a given public post.
- *
- * This script is started from mod/item.php to save some time when doing a post.
- */
-
-require_once("include/threads.php");
-
-function create_shadowentry_run($argv, $argc) {
-       if ($argc != 2) {
-               return;
-       }
-
-       $message_id = intval($argv[1]);
-
-       add_shadow_entry($message_id);
-}
diff --git a/include/cron.php b/include/cron.php
deleted file mode 100644 (file)
index 0198982..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-<?php
-
-use Friendica\Core\Config;
-use Friendica\Core\Worker;
-use Friendica\Database\DBM;
-
-function cron_run(&$argv, &$argc){
-       global $a;
-
-       require_once 'include/datetime.php';
-
-       // Poll contacts with specific parameters
-       if ($argc > 1) {
-               cron_poll_contacts($argc, $argv);
-               return;
-       }
-
-       $last = Config::get('system', 'last_cron');
-
-       $poll_interval = intval(Config::get('system', 'cron_interval'));
-       if (! $poll_interval) {
-               $poll_interval = 10;
-       }
-
-       if ($last) {
-               $next = $last + ($poll_interval * 60);
-               if ($next > time()) {
-                       logger('cron intervall not reached');
-                       return;
-               }
-       }
-
-       logger('cron: start');
-
-       // run queue delivery process in the background
-       Worker::add(PRIORITY_NEGLIGIBLE, "queue");
-
-       // run the process to discover global contacts in the background
-       Worker::add(PRIORITY_LOW, "discover_poco");
-
-       // run the process to update locally stored global contacts in the background
-       Worker::add(PRIORITY_LOW, "discover_poco", "checkcontact");
-
-       // Expire and remove user entries
-       Worker::add(PRIORITY_MEDIUM, "cronjobs", "expire_and_remove_users");
-
-       // Call possible post update functions
-       Worker::add(PRIORITY_LOW, "cronjobs", "post_update");
-
-       // update nodeinfo data
-       Worker::add(PRIORITY_LOW, "cronjobs", "nodeinfo");
-
-       // Clear cache entries
-       Worker::add(PRIORITY_LOW, "cronjobs", "clear_cache");
-
-       // Repair missing Diaspora values in contacts
-       Worker::add(PRIORITY_LOW, "cronjobs", "repair_diaspora");
-
-       // Repair entries in the database
-       Worker::add(PRIORITY_LOW, "cronjobs", "repair_database");
-
-       // once daily run birthday_updates and then expire in background
-       $d1 = Config::get('system', 'last_expire_day');
-       $d2 = intval(datetime_convert('UTC', 'UTC', 'now', 'd'));
-
-       if ($d2 != intval($d1)) {
-
-               Worker::add(PRIORITY_LOW, "cronjobs", "update_contact_birthdays");
-
-               Worker::add(PRIORITY_LOW, "discover_poco", "update_server");
-
-               Worker::add(PRIORITY_LOW, "discover_poco", "suggestions");
-
-               Config::set('system', 'last_expire_day', $d2);
-
-               Worker::add(PRIORITY_LOW, 'expire');
-
-               Worker::add(PRIORITY_MEDIUM, 'dbclean');
-
-               Worker::add(PRIORITY_LOW, "cronjobs", "update_photo_albums");
-
-               // Delete all done workerqueue entries
-               dba::delete('workerqueue', array('`done` AND `executed` < UTC_TIMESTAMP() - INTERVAL 12 HOUR'));
-
-               // check upstream version?
-               Worker::add(PRIORITY_LOW, 'checkversion');
-       }
-
-       // Poll contacts
-       cron_poll_contacts($argc, $argv);
-
-       logger('cron: end');
-
-       Config::set('system', 'last_cron', time());
-
-       return;
-}
-
-/**
- * @brief Poll contacts for unreceived messages
- *
- * @param Integer $argc Number of command line arguments
- * @param Array $argv Array of command line arguments
- */
-function cron_poll_contacts($argc, $argv) {
-       $manual_id  = 0;
-       $generation = 0;
-       $force      = false;
-       $restart    = false;
-
-       if (($argc > 1) && ($argv[1] == 'force')) {
-               $force = true;
-       }
-       if (($argc > 1) && ($argv[1] == 'restart')) {
-               $restart = true;
-               $generation = intval($argv[2]);
-               if (!$generation) {
-                       killme();
-               }
-       }
-
-       if (($argc > 1) && intval($argv[1])) {
-               $manual_id = intval($argv[1]);
-               $force     = true;
-       }
-
-       $min_poll_interval = Config::get('system', 'min_poll_interval', 1);
-
-       $sql_extra = (($manual_id) ? " AND `id` = $manual_id " : "");
-
-       reload_plugins();
-
-       $d = datetime_convert();
-
-       // Only poll from those with suitable relationships,
-       // and which have a polling address and ignore Diaspora since
-       // we are unable to match those posts with a Diaspora GUID and prevent duplicates.
-
-       $abandon_days = intval(Config::get('system', 'account_abandon_days'));
-       if ($abandon_days < 1) {
-               $abandon_days = 0;
-       }
-       $abandon_sql = (($abandon_days)
-               ? sprintf(" AND `user`.`login_date` > UTC_TIMESTAMP() - INTERVAL %d DAY ", intval($abandon_days))
-               : ''
-       );
-
-       $contacts = q("SELECT `contact`.`id` FROM `user`
-                       STRAIGHT_JOIN `contact`
-                       ON `contact`.`uid` = `user`.`uid` AND `contact`.`rel` IN (%d, %d) AND `contact`.`poll` != ''
-                               AND `contact`.`network` IN ('%s', '%s', '%s', '%s', '%s', '%s') $sql_extra
-                               AND NOT `contact`.`self` AND NOT `contact`.`blocked` AND NOT `contact`.`readonly`
-                               AND NOT `contact`.`archive`
-                       WHERE NOT `user`.`account_expired` AND NOT `user`.`account_removed` $abandon_sql ORDER BY RAND()",
-               intval(CONTACT_IS_SHARING),
-               intval(CONTACT_IS_FRIEND),
-               dbesc(NETWORK_DFRN),
-               dbesc(NETWORK_ZOT),
-               dbesc(NETWORK_OSTATUS),
-               dbesc(NETWORK_FEED),
-               dbesc(NETWORK_MAIL),
-               dbesc(NETWORK_MAIL2)
-       );
-
-       if (!DBM::is_result($contacts)) {
-               return;
-       }
-
-       foreach ($contacts as $c) {
-
-               $res = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1",
-                       intval($c['id'])
-               );
-
-               if (!DBM::is_result($res)) {
-                       continue;
-               }
-
-               foreach ($res as $contact) {
-
-                       $xml = false;
-
-                       if ($manual_id) {
-                               $contact['last-update'] = NULL_DATE;
-                       }
-
-                       if (in_array($contact['network'], array(NETWORK_DFRN, NETWORK_ZOT, NETWORK_OSTATUS))) {
-                               $contact['priority'] = 2;
-                       }
-
-                       if ($contact['subhub'] && in_array($contact['network'], array(NETWORK_DFRN, NETWORK_ZOT, NETWORK_OSTATUS))) {
-                               /*
-                                * We should be getting everything via a hub. But just to be sure, let's check once a day.
-                                * (You can make this more or less frequent if desired by setting 'pushpoll_frequency' appropriately)
-                                * This also lets us update our subscription to the hub, and add or replace hubs in case it
-                                * changed. We will only update hubs once a day, regardless of 'pushpoll_frequency'.
-                                */
-                               $poll_interval = Config::get('system', 'pushpoll_frequency');
-                               $contact['priority'] = (($poll_interval !== false) ? intval($poll_interval) : 3);
-                       }
-
-                       if (($contact['priority'] >= 0) && !$force) {
-                               $update = false;
-
-                               $t = $contact['last-update'];
-
-                               /*
-                                * Based on $contact['priority'], should we poll this site now? Or later?
-                                */
-                               switch ($contact['priority']) {
-                                       case 5:
-                                               if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 month")) {
-                                                       $update = true;
-                                               }
-                                               break;
-                                       case 4:
-                                               if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 week")) {
-                                                       $update = true;
-                                               }
-                                               break;
-                                       case 3:
-                                               if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 day")) {
-                                                       $update = true;
-                                               }
-                                               break;
-                                       case 2:
-                                               if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 12 hour")) {
-                                                       $update = true;
-                                               }
-                                               break;
-                                       case 1:
-                                               if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 hour")) {
-                                                       $update = true;
-                                               }
-                                               break;
-                                       case 0:
-                                       default:
-                                               if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + ".$min_poll_interval." minute")) {
-                                                       $update = true;
-                                               }
-                                               break;
-                               }
-                               if (!$update) {
-                                       continue;
-                               }
-                       }
-
-                       logger("Polling " . $contact["network"] . " " . $contact["id"] . " " . $contact["nick"] . " " . $contact["name"]);
-
-                       if (($contact['network'] == NETWORK_FEED) && ($contact['priority'] <= 3)) {
-                               $priority = PRIORITY_MEDIUM;
-                       } else {
-                               $priority = PRIORITY_LOW;
-                       }
-                       Worker::add(array('priority' => $priority, 'dont_fork' => true), 'OnePoll', (int)$contact['id']);
-               }
-       }
-}
diff --git a/include/cronjobs.php b/include/cronjobs.php
deleted file mode 100644 (file)
index 00064b1..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-<?php
-
-use Friendica\App;
-use Friendica\Core\Cache;
-use Friendica\Core\Config;
-use Friendica\Database\DBM;
-use Friendica\Network\Probe;
-
-function cronjobs_run(&$argv, &$argc){
-       global $a;
-
-       require_once 'include/datetime.php';
-       require_once 'include/post_update.php';
-       require_once 'mod/nodeinfo.php';
-       require_once 'include/photos.php';
-       require_once 'include/user.php';
-       require_once 'include/socgraph.php';
-
-       // No parameter set? So return
-       if ($argc <= 1) {
-               return;
-       }
-
-       logger("Starting cronjob ".$argv[1], LOGGER_DEBUG);
-
-       // Call possible post update functions
-       // see include/post_update.php for more details
-       if ($argv[1] == 'post_update') {
-               post_update();
-               return;
-       }
-
-       // update nodeinfo data
-       if ($argv[1] == 'nodeinfo') {
-               nodeinfo_cron();
-               return;
-       }
-
-       // Expire and remove user entries
-       if ($argv[1] == 'expire_and_remove_users') {
-               cron_expire_and_remove_users();
-               return;
-       }
-
-       if ($argv[1] == 'update_contact_birthdays') {
-               update_contact_birthdays();
-               return;
-       }
-
-       if ($argv[1] == 'update_photo_albums') {
-               cron_update_photo_albums();
-               return;
-       }
-
-       // Clear cache entries
-       if ($argv[1] == 'clear_cache') {
-               cron_clear_cache($a);
-               return;
-       }
-
-       // Repair missing Diaspora values in contacts
-       if ($argv[1] == 'repair_diaspora') {
-               cron_repair_diaspora($a);
-               return;
-       }
-
-       // Repair entries in the database
-       if ($argv[1] == 'repair_database') {
-               cron_repair_database();
-               return;
-       }
-
-       logger("Xronjob ".$argv[1]." is unknown.", LOGGER_DEBUG);
-
-       return;
-}
-
-/**
- * @brief Update the cached values for the number of photo albums per user
- */
-function cron_update_photo_albums() {
-       $r = q("SELECT `uid` FROM `user` WHERE NOT `account_expired` AND NOT `account_removed`");
-       if (!DBM::is_result($r)) {
-               return;
-       }
-
-       foreach ($r AS $user) {
-               photo_albums($user['uid'], true);
-       }
-}
-
-/**
- * @brief Expire and remove user entries
- */
-function cron_expire_and_remove_users() {
-       // expire any expired accounts
-       q("UPDATE user SET `account_expired` = 1 where `account_expired` = 0
-               AND `account_expires_on` > '%s'
-               AND `account_expires_on` < UTC_TIMESTAMP()", dbesc(NULL_DATE));
-
-       // delete user records for recently removed accounts
-       $r = q("SELECT * FROM `user` WHERE `account_removed` AND `account_expires_on` < UTC_TIMESTAMP() - INTERVAL 3 DAY");
-       if (DBM::is_result($r)) {
-               foreach ($r as $user) {
-                       dba::delete('user', array('uid' => $user['uid']));
-               }
-       }
-}
-
-/**
- * @brief Clear cache entries
- *
- * @param App $a
- */
-function cron_clear_cache(App $a) {
-
-       $last = Config::get('system','cache_last_cleared');
-
-       if ($last) {
-               $next = $last + (3600); // Once per hour
-               $clear_cache = ($next <= time());
-       } else {
-               $clear_cache = true;
-       }
-
-       if (!$clear_cache) {
-               return;
-       }
-
-       // clear old cache
-       Cache::clear();
-
-       // clear old item cache files
-       clear_cache();
-
-       // clear cache for photos
-       clear_cache($a->get_basepath(), $a->get_basepath()."/photo");
-
-       // clear smarty cache
-       clear_cache($a->get_basepath()."/view/smarty3/compiled", $a->get_basepath()."/view/smarty3/compiled");
-
-       // clear cache for image proxy
-       if (!Config::get("system", "proxy_disabled")) {
-               clear_cache($a->get_basepath(), $a->get_basepath()."/proxy");
-
-               $cachetime = Config::get('system','proxy_cache_time');
-               if (!$cachetime) {
-                       $cachetime = PROXY_DEFAULT_TIME;
-               }
-               q('DELETE FROM `photo` WHERE `uid` = 0 AND `resource-id` LIKE "pic:%%" AND `created` < NOW() - INTERVAL %d SECOND', $cachetime);
-       }
-
-       // Delete the cached OEmbed entries that are older than one year
-       q("DELETE FROM `oembed` WHERE `created` < NOW() - INTERVAL 3 MONTH");
-
-       // Delete the cached "parse_url" entries that are older than one year
-       q("DELETE FROM `parsed_url` WHERE `created` < NOW() - INTERVAL 3 MONTH");
-
-       // Maximum table size in megabyte
-       $max_tablesize = intval(Config::get('system','optimize_max_tablesize')) * 1000000;
-       if ($max_tablesize == 0) {
-               $max_tablesize = 100 * 1000000; // Default are 100 MB
-       }
-       if ($max_tablesize > 0) {
-               // Minimum fragmentation level in percent
-               $fragmentation_level = intval(Config::get('system','optimize_fragmentation')) / 100;
-               if ($fragmentation_level == 0) {
-                       $fragmentation_level = 0.3; // Default value is 30%
-               }
-
-               // Optimize some tables that need to be optimized
-               $r = q("SHOW TABLE STATUS");
-               foreach ($r as $table) {
-
-                       // Don't optimize tables that are too large
-                       if ($table["Data_length"] > $max_tablesize) {
-                               continue;
-                       }
-
-                       // Don't optimize empty tables
-                       if ($table["Data_length"] == 0) {
-                               continue;
-                       }
-
-                       // Calculate fragmentation
-                       $fragmentation = $table["Data_free"] / ($table["Data_length"] + $table["Index_length"]);
-
-                       logger("Table ".$table["Name"]." - Fragmentation level: ".round($fragmentation * 100, 2), LOGGER_DEBUG);
-
-                       // Don't optimize tables that needn't to be optimized
-                       if ($fragmentation < $fragmentation_level) {
-                               continue;
-                       }
-
-                       // So optimize it
-                       logger("Optimize Table ".$table["Name"], LOGGER_DEBUG);
-                       q("OPTIMIZE TABLE `%s`", dbesc($table["Name"]));
-               }
-       }
-
-       Config::set('system','cache_last_cleared', time());
-}
-
-/**
- * @brief Repair missing values in Diaspora contacts
- *
- * @param App $a
- */
-function cron_repair_diaspora(App $a) {
-
-        $starttime = time();
-
-       $r = q("SELECT `id`, `url` FROM `contact`
-               WHERE `network` = '%s' AND (`batch` = '' OR `notify` = '' OR `poll` = '' OR pubkey = '')
-                       ORDER BY RAND() LIMIT 50", dbesc(NETWORK_DIASPORA));
-       if (!DBM::is_result($r)) {
-               return;
-       }
-
-       foreach ($r AS $contact) {
-               // Quit the loop after 3 minutes
-               if (time() > ($starttime + 180)) {
-                       return;
-               }
-
-               if (!poco_reachable($contact["url"])) {
-                       continue;
-               }
-
-               $data = Probe::uri($contact["url"]);
-               if ($data["network"] != NETWORK_DIASPORA) {
-                       continue;
-               }
-
-               logger("Repair contact ".$contact["id"]." ".$contact["url"], LOGGER_DEBUG);
-               q("UPDATE `contact` SET `batch` = '%s', `notify` = '%s', `poll` = '%s', pubkey = '%s' WHERE `id` = %d",
-                       dbesc($data["batch"]), dbesc($data["notify"]), dbesc($data["poll"]), dbesc($data["pubkey"]),
-                       intval($contact["id"]));
-       }
-}
-
-/**
- * @brief Do some repairs in database entries
- *
- */
-function cron_repair_database() {
-
-       // Sometimes there seem to be issues where the "self" contact vanishes.
-       // We haven't found the origin of the problem by now.
-       $r = q("SELECT `uid` FROM `user` WHERE NOT EXISTS (SELECT `uid` FROM `contact` WHERE `contact`.`uid` = `user`.`uid` AND `contact`.`self`)");
-       if (DBM::is_result($r)) {
-               foreach ($r AS $user) {
-                       logger('Create missing self contact for user '.$user['uid']);
-                       user_create_self_contact($user['uid']);
-               }
-       }
-
-       // Set the parent if it wasn't set. (Shouldn't happen - but does sometimes)
-       // This call is very "cheap" so we can do it at any time without a problem
-       q("UPDATE `item` INNER JOIN `item` AS `parent` ON `parent`.`uri` = `item`.`parent-uri` AND `parent`.`uid` = `item`.`uid` SET `item`.`parent` = `parent`.`id` WHERE `item`.`parent` = 0");
-
-       // There was an issue where the nick vanishes from the contact table
-       q("UPDATE `contact` INNER JOIN `user` ON `contact`.`uid` = `user`.`uid` SET `nick` = `nickname` WHERE `self` AND `nick`=''");
-
-       // Update the global contacts for local users
-       $r = q("SELECT `uid` FROM `user` WHERE `verified` AND NOT `blocked` AND NOT `account_removed` AND NOT `account_expired`");
-       if (DBM::is_result($r)) {
-               foreach ($r AS $user) {
-                       update_gcontact_for_user($user["uid"]);
-               }
-       }
-
-       /// @todo
-       /// - remove thread entries without item
-       /// - remove sign entries without item
-       /// - remove children when parent got lost
-       /// - set contact-id in item when not present
-}
diff --git a/include/dbclean.php b/include/dbclean.php
deleted file mode 100644 (file)
index 1e1dd90..0000000
+++ /dev/null
@@ -1,303 +0,0 @@
-<?php
-/**
- * @file include/dbclean.php
- * @brief The script is called from time to time to clean the database entries and remove orphaned data.
- */
-
-use Friendica\Core\Config;
-use Friendica\Core\Worker;
-
-function dbclean_run(&$argv, &$argc) {
-       if (!Config::get('system', 'dbclean', false)) {
-               return;
-       }
-
-       if ($argc == 2) {
-               $stage = intval($argv[1]);
-       } else {
-               $stage = 0;
-       }
-
-       // Get the expire days for step 8 and 9
-       $days = Config::get('system', 'dbclean-expire-days', 0);
-
-       if ($stage == 0) {
-               for ($i = 1; $i <= 9; $i++) {
-                       // Execute the background script for a step when it isn't finished.
-                       // Execute step 8 and 9 only when $days is defined.
-                       if (!Config::get('system', 'finished-dbclean-'.$i, false) && (($i < 8) || ($days > 0))) {
-                               Worker::add(PRIORITY_LOW, 'dbclean', $i);
-                       }
-               }
-       } else {
-               remove_orphans($stage);
-       }
-}
-
-/**
- * @brief Remove orphaned database entries
- * @param integer $stage What should be deleted?
- *
- * Values for $stage:
- * ------------------
- * 1:  Old global item entries from item table without user copy.
- * 2:  Items without parents.
- * 3:  Orphaned data from thread table.
- * 4:  Orphaned data from notify table.
- * 5:  Orphaned data from notify-threads table.
- * 6:  Orphaned data from sign table.
- * 7:  Orphaned data from term table.
- * 8:  Expired threads.
- * 9:  Old global item entries from expired threads
- */
-function remove_orphans($stage = 0) {
-       global $db;
-
-       $count = 0;
-
-       // We split the deletion in many small tasks
-       $limit = 1000;
-
-       // Get the expire days for step 8 and 9
-       $days = Config::get('system', 'dbclean-expire-days', 0);
-
-       if ($stage == 1) {
-               $last_id = Config::get('system', 'dbclean-last-id-1', 0);
-
-               logger("Deleting old global item entries from item table without user copy. Last ID: ".$last_id);
-               $r = dba::p("SELECT `id` FROM `item` WHERE `uid` = 0 AND
-                                       NOT EXISTS (SELECT `guid` FROM `item` AS `i` WHERE `item`.`guid` = `i`.`guid` AND `i`.`uid` != 0) AND
-                                       `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY AND `id` >= ?
-                               ORDER BY `id` LIMIT ".intval($limit), $last_id);
-               $count = dba::num_rows($r);
-               if ($count > 0) {
-                       logger("found global item orphans: ".$count);
-                       while ($orphan = dba::fetch($r)) {
-                               $last_id = $orphan["id"];
-                               dba::delete('item', array('id' => $orphan["id"]));
-                       }
-               } else {
-                       logger("No global item orphans found");
-               }
-               dba::close($r);
-               logger("Done deleting ".$count." old global item entries from item table without user copy. Last ID: ".$last_id);
-
-               Config::set('system', 'dbclean-last-id-1', $last_id);
-       } elseif ($stage == 2) {
-               $last_id = Config::get('system', 'dbclean-last-id-2', 0);
-
-               logger("Deleting items without parents. Last ID: ".$last_id);
-               $r = dba::p("SELECT `id` FROM `item`
-                               WHERE NOT EXISTS (SELECT `id` FROM `item` AS `i` WHERE `item`.`parent` = `i`.`id`)
-                               AND `id` >= ? ORDER BY `id` LIMIT ".intval($limit), $last_id);
-               $count = dba::num_rows($r);
-               if ($count > 0) {
-                       logger("found item orphans without parents: ".$count);
-                       while ($orphan = dba::fetch($r)) {
-                               $last_id = $orphan["id"];
-                               dba::delete('item', array('id' => $orphan["id"]));
-                       }
-               } else {
-                       logger("No item orphans without parents found");
-               }
-               dba::close($r);
-               logger("Done deleting ".$count." items without parents. Last ID: ".$last_id);
-
-               Config::set('system', 'dbclean-last-id-2', $last_id);
-
-               if ($count < $limit) {
-                       Config::set('system', 'finished-dbclean-2', true);
-               }
-       } elseif ($stage == 3) {
-               $last_id = Config::get('system', 'dbclean-last-id-3', 0);
-
-               logger("Deleting orphaned data from thread table. Last ID: ".$last_id);
-               $r = dba::p("SELECT `iid` FROM `thread`
-                               WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `thread`.`iid`) AND `iid` >= ?
-                               ORDER BY `iid` LIMIT ".intval($limit), $last_id);
-               $count = dba::num_rows($r);
-               if ($count > 0) {
-                       logger("found thread orphans: ".$count);
-                       while ($orphan = dba::fetch($r)) {
-                               $last_id = $orphan["iid"];
-                               dba::delete('thread', array('iid' => $orphan["iid"]));
-                       }
-               } else {
-                       logger("No thread orphans found");
-               }
-               dba::close($r);
-               logger("Done deleting ".$count." orphaned data from thread table. Last ID: ".$last_id);
-
-               Config::set('system', 'dbclean-last-id-3', $last_id);
-
-               if ($count < $limit) {
-                       Config::set('system', 'finished-dbclean-3', true);
-               }
-       } elseif ($stage == 4) {
-               $last_id = Config::get('system', 'dbclean-last-id-4', 0);
-
-               logger("Deleting orphaned data from notify table. Last ID: ".$last_id);
-               $r = dba::p("SELECT `iid`, `id` FROM `notify`
-                               WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `notify`.`iid`) AND `id` >= ?
-                               ORDER BY `id` LIMIT ".intval($limit), $last_id);
-               $count = dba::num_rows($r);
-               if ($count > 0) {
-                       logger("found notify orphans: ".$count);
-                       while ($orphan = dba::fetch($r)) {
-                               $last_id = $orphan["id"];
-                               dba::delete('notify', array('iid' => $orphan["iid"]));
-                       }
-               } else {
-                       logger("No notify orphans found");
-               }
-               dba::close($r);
-               logger("Done deleting ".$count." orphaned data from notify table. Last ID: ".$last_id);
-
-               Config::set('system', 'dbclean-last-id-4', $last_id);
-
-               if ($count < $limit) {
-                       Config::set('system', 'finished-dbclean-4', true);
-               }
-       } elseif ($stage == 5) {
-               $last_id = Config::get('system', 'dbclean-last-id-5', 0);
-
-               logger("Deleting orphaned data from notify-threads table. Last ID: ".$last_id);
-               $r = dba::p("SELECT `id` FROM `notify-threads`
-                               WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `notify-threads`.`master-parent-item`) AND `id` >= ?
-                               ORDER BY `id` LIMIT ".intval($limit), $last_id);
-               $count = dba::num_rows($r);
-               if ($count > 0) {
-                       logger("found notify-threads orphans: ".$count);
-                       while ($orphan = dba::fetch($r)) {
-                               $last_id = $orphan["id"];
-                               dba::delete('notify-threads', array('id' => $orphan["id"]));
-                       }
-               } else {
-                       logger("No notify-threads orphans found");
-               }
-               dba::close($r);
-               logger("Done deleting ".$count." orphaned data from notify-threads table. Last ID: ".$last_id);
-
-               Config::set('system', 'dbclean-last-id-5', $last_id);
-
-               if ($count < $limit) {
-                       Config::set('system', 'finished-dbclean-5', true);
-               }
-       } elseif ($stage == 6) {
-               $last_id = Config::get('system', 'dbclean-last-id-6', 0);
-
-               logger("Deleting orphaned data from sign table. Last ID: ".$last_id);
-               $r = dba::p("SELECT `iid`, `id` FROM `sign`
-                               WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `sign`.`iid`) AND `id` >= ?
-                               ORDER BY `id` LIMIT ".intval($limit), $last_id);
-               $count = dba::num_rows($r);
-               if ($count > 0) {
-                       logger("found sign orphans: ".$count);
-                       while ($orphan = dba::fetch($r)) {
-                               $last_id = $orphan["id"];
-                               dba::delete('sign', array('iid' => $orphan["iid"]));
-                       }
-               } else {
-                       logger("No sign orphans found");
-               }
-               dba::close($r);
-               logger("Done deleting ".$count." orphaned data from sign table. Last ID: ".$last_id);
-
-               Config::set('system', 'dbclean-last-id-6', $last_id);
-
-               if ($count < $limit) {
-                       Config::set('system', 'finished-dbclean-6', true);
-               }
-       } elseif ($stage == 7) {
-               $last_id = Config::get('system', 'dbclean-last-id-7', 0);
-
-               logger("Deleting orphaned data from term table. Last ID: ".$last_id);
-               $r = dba::p("SELECT `oid`, `tid` FROM `term`
-                               WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `term`.`oid`) AND `tid` >= ?
-                               ORDER BY `tid` LIMIT ".intval($limit), $last_id);
-               $count = dba::num_rows($r);
-               if ($count > 0) {
-                       logger("found term orphans: ".$count);
-                       while ($orphan = dba::fetch($r)) {
-                               $last_id = $orphan["tid"];
-                               dba::delete('term', array('oid' => $orphan["oid"]));
-                       }
-               } else {
-                       logger("No term orphans found");
-               }
-               dba::close($r);
-               logger("Done deleting ".$count." orphaned data from term table. Last ID: ".$last_id);
-
-               Config::set('system', 'dbclean-last-id-7', $last_id);
-
-               if ($count < $limit) {
-                       Config::set('system', 'finished-dbclean-7', true);
-               }
-       } elseif ($stage == 8) {
-               if ($days <= 0) {
-                       return;
-               }
-
-               $last_id = Config::get('system', 'dbclean-last-id-8', 0);
-
-               logger("Deleting expired threads. Last ID: ".$last_id);
-               $r = dba::p("SELECT `thread`.`iid` FROM `thread`
-                                INNER JOIN `contact` ON `thread`.`contact-id` = `contact`.`id` AND NOT `notify_new_posts`
-                                WHERE `thread`.`received` < UTC_TIMESTAMP() - INTERVAL ? DAY
-                                        AND NOT `thread`.`mention` AND NOT `thread`.`starred`
-                                        AND NOT `thread`.`wall` AND NOT `thread`.`origin`
-                                        AND `thread`.`uid` != 0 AND `thread`.`iid` >= ?
-                                        AND NOT `thread`.`iid` IN (SELECT `parent` FROM `item`
-                                                        WHERE (`item`.`starred` OR (`item`.`resource-id` != '')
-                                                                OR (`item`.`file` != '') OR (`item`.`event-id` != '')
-                                                                OR (`item`.`attach` != '') OR `item`.`wall` OR `item`.`origin`)
-                                                                AND `item`.`parent` = `thread`.`iid`)
-                                ORDER BY `thread`.`iid` LIMIT 1000", $days, $last_id);
-               $count = dba::num_rows($r);
-               if ($count > 0) {
-                       logger("found expired threads: ".$count);
-                       while ($thread = dba::fetch($r)) {
-                               $last_id = $thread["iid"];
-                               dba::delete('thread', array('iid' => $thread["iid"]));
-                       }
-               } else {
-                       logger("No expired threads found");
-               }
-               dba::close($r);
-               logger("Done deleting ".$count." expired threads. Last ID: ".$last_id);
-
-               Config::set('system', 'dbclean-last-id-8', $last_id);
-       } elseif ($stage == 9) {
-               if ($days <= 0) {
-                       return;
-               }
-
-               $last_id = Config::get('system', 'dbclean-last-id-9', 0);
-               $till_id = Config::get('system', 'dbclean-last-id-8', 0);
-
-               logger("Deleting old global item entries from expired threads from ID ".$last_id." to ID ".$till_id);
-               $r = dba::p("SELECT `id` FROM `item` WHERE `uid` = 0 AND
-                                       NOT EXISTS (SELECT `guid` FROM `item` AS `i` WHERE `item`.`guid` = `i`.`guid` AND `i`.`uid` != 0) AND
-                                       `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY AND `id` >= ? AND `id` <= ?
-                               ORDER BY `id` LIMIT ".intval($limit), $last_id, $till_id);
-               $count = dba::num_rows($r);
-               if ($count > 0) {
-                       logger("found global item entries from expired threads: ".$count);
-                       while ($orphan = dba::fetch($r)) {
-                               $last_id = $orphan["id"];
-                               dba::delete('item', array('id' => $orphan["id"]));
-                       }
-               } else {
-                       logger("No global item entries from expired threads");
-               }
-               dba::close($r);
-               logger("Done deleting ".$count." old global item entries from expired threads. Last ID: ".$last_id);
-
-               Config::set('system', 'dbclean-last-id-9', $last_id);
-       }
-
-       // Call it again if not all entries were purged
-       if (($stage != 0) && ($count > 0)) {
-               Worker::add(PRIORITY_MEDIUM, 'dbclean');
-       }
-}
diff --git a/include/dbupdate.php b/include/dbupdate.php
deleted file mode 100644 (file)
index 799ca26..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-<?php
-
-use Friendica\Core\Config;
-
-function dbupdate_run(&$argv, &$argc) {
-       global $a;
-
-       // We are deleting the latest dbupdate entry.
-       // This is done to avoid endless loops because the update was interupted.
-       Config::delete('database', 'dbupdate_'.DB_UPDATE_VERSION);
-
-       update_db($a);
-}
diff --git a/include/delivery.php b/include/delivery.php
deleted file mode 100644 (file)
index 7c5f464..0000000
+++ /dev/null
@@ -1,541 +0,0 @@
-<?php
-
-use Friendica\App;
-use Friendica\Core\System;
-use Friendica\Core\Config;
-use Friendica\Database\DBM;
-use Friendica\Protocol\Diaspora;
-use Friendica\Protocol\DFRN;
-
-require_once 'include/queue_fn.php';
-require_once 'include/html2plain.php';
-require_once 'include/ostatus.php';
-
-function delivery_run(&$argv, &$argc){
-       global $a;
-
-       require_once 'include/datetime.php';
-       require_once 'include/items.php';
-       require_once 'include/bbcode.php';
-       require_once 'include/email.php';
-
-       if ($argc < 3) {
-               return;
-       }
-
-       logger('delivery: invoked: '. print_r($argv,true), LOGGER_DEBUG);
-
-       $cmd        = $argv[1];
-       $item_id    = intval($argv[2]);
-
-       for ($x = 3; $x < $argc; $x ++) {
-
-               $contact_id = intval($argv[$x]);
-
-               if (!$item_id || !$contact_id) {
-                       continue;
-               }
-
-               $expire = false;
-               $mail = false;
-               $fsuggest = false;
-               $relocate = false;
-               $top_level = false;
-               $recipients = array();
-               $url_recipients = array();
-               $followup = false;
-
-               $normal_mode = true;
-
-               $recipients[] = $contact_id;
-
-               if ($cmd === 'mail') {
-                       $normal_mode = false;
-                       $mail = true;
-                       $message = q("SELECT * FROM `mail` WHERE `id` = %d LIMIT 1",
-                                       intval($item_id)
-                       );
-                       if (!count($message)) {
-                               return;
-                       }
-                       $uid = $message[0]['uid'];
-                       $recipients[] = $message[0]['contact-id'];
-                       $item = $message[0];
-               } elseif ($cmd === 'expire') {
-                       $normal_mode = false;
-                       $expire = true;
-                       $items = q("SELECT * FROM `item` WHERE `uid` = %d AND `wall` = 1
-                               AND `deleted` = 1 AND `changed` > UTC_TIMESTAMP() - INTERVAL 30 MINUTE",
-                               intval($item_id)
-                       );
-                       $uid = $item_id;
-                       $item_id = 0;
-                       if (!count($items)) {
-                               continue;
-                       }
-               } elseif ($cmd === 'suggest') {
-                       $normal_mode = false;
-                       $fsuggest = true;
-
-                       $suggest = q("SELECT * FROM `fsuggest` WHERE `id` = %d LIMIT 1",
-                               intval($item_id)
-                       );
-                       if (!count($suggest)) {
-                               return;
-                       }
-                       $uid = $suggest[0]['uid'];
-                       $recipients[] = $suggest[0]['cid'];
-                       $item = $suggest[0];
-               } elseif ($cmd === 'relocate') {
-                       $normal_mode = false;
-                       $relocate = true;
-                       $uid = $item_id;
-               } else {
-                       // find ancestors
-                       $r = q("SELECT * FROM `item` WHERE `id` = %d AND visible = 1 AND moderated = 0 LIMIT 1",
-                               intval($item_id)
-                       );
-
-                       if ((!DBM::is_result($r)) || (!intval($r[0]['parent']))) {
-                               continue;
-                       }
-
-                       $target_item = $r[0];
-                       $parent_id = intval($r[0]['parent']);
-                       $uid = $r[0]['uid'];
-                       $updated = $r[0]['edited'];
-
-                       $items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer`
-                               FROM `item` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` WHERE `parent` = %d AND visible = 1 AND moderated = 0 ORDER BY `id` ASC",
-                               intval($parent_id)
-                       );
-
-                       if (!count($items)) {
-                               continue;
-                       }
-
-                       $icontacts = null;
-                       $contacts_arr = array();
-                       foreach ($items as $item) {
-                               if (!in_array($item['contact-id'],$contacts_arr)) {
-                                       $contacts_arr[] = intval($item['contact-id']);
-                               }
-                       }
-                       if (count($contacts_arr)) {
-                               $str_contacts = implode(',',$contacts_arr);
-                               $icontacts = q("SELECT * FROM `contact`
-                                       WHERE `id` IN ( $str_contacts ) "
-                               );
-                       }
-                       if ( !($icontacts && count($icontacts))) {
-                               continue;
-                       }
-
-                       // avoid race condition with deleting entries
-
-                       if ($items[0]['deleted']) {
-                               foreach ($items as $item) {
-                                       $item['deleted'] = 1;
-                               }
-                       }
-
-                       // When commenting too fast after delivery, a post wasn't recognized as top level post.
-                       // The count then showed more than one entry. The additional check should help.
-                       // The check for the "count" should be superfluous, but I'm not totally sure by now, so we keep it.
-                       if ((($items[0]['id'] == $item_id) || (count($items) == 1)) && ($items[0]['uri'] === $items[0]['parent-uri'])) {
-                               logger('delivery: top level post');
-                               $top_level = true;
-                       }
-               }
-
-               $r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`,
-                       `user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`,
-                       `user`.`page-flags`, `user`.`account-type`, `user`.`prvnets`
-                       FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
-                       WHERE `contact`.`uid` = %d AND `contact`.`self` = 1 LIMIT 1",
-                       intval($uid)
-               );
-
-               if (!DBM::is_result($r)) {
-                       continue;
-               }
-
-               $owner = $r[0];
-
-               $walltowall = ((($top_level) && ($owner['id'] != $items[0]['contact-id'])) ? true : false);
-
-               $public_message = true;
-
-               if (!($mail || $fsuggest || $relocate)) {
-                       require_once 'include/group.php';
-
-                       $parent = $items[0];
-
-                       // This is IMPORTANT!!!!
-
-                       // We will only send a "notify owner to relay" or followup message if the referenced post
-                       // originated on our system by virtue of having our hostname somewhere
-                       // in the URI, AND it was a comment (not top_level) AND the parent originated elsewhere.
-                       // if $parent['wall'] == 1 we will already have the parent message in our array
-                       // and we will relay the whole lot.
-
-                       // expire sends an entire group of expire messages and cannot be forwarded.
-                       // However the conversation owner will be a part of the conversation and will
-                       // be notified during this run.
-                       // Other DFRN conversation members will be alerted during polled updates.
-
-                       // Diaspora members currently are not notified of expirations, and other networks have
-                       // either limited or no ability to process deletions. We should at least fix Diaspora
-                       // by stringing togther an array of retractions and sending them onward.
-
-
-                       $localhost = $a->get_hostname();
-                       if (strpos($localhost,':')) {
-                               $localhost = substr($localhost,0,strpos($localhost,':'));
-                       }
-                       /**
-                        *
-                        * Be VERY CAREFUL if you make any changes to the following line. Seemingly innocuous changes
-                        * have been known to cause runaway conditions which affected several servers, along with
-                        * permissions issues.
-                        *
-                        */
-
-                       $relay_to_owner = false;
-
-                       if (!$top_level && ($parent['wall'] == 0) && !$expire && stristr($target_item['uri'],$localhost)) {
-                               $relay_to_owner = true;
-                       }
-
-                       if ($relay_to_owner) {
-                               logger('followup '.$target_item["guid"], LOGGER_DEBUG);
-                               // local followup to remote post
-                               $followup = true;
-                       }
-
-                       if ((strlen($parent['allow_cid']))
-                               || (strlen($parent['allow_gid']))
-                               || (strlen($parent['deny_cid']))
-                               || (strlen($parent['deny_gid']))
-                               || $parent["private"]) {
-                               $public_message = false; // private recipients, not public
-                       }
-
-               }
-
-               $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `blocked` = 0 AND `pending` = 0",
-                       intval($contact_id)
-               );
-
-               if (DBM::is_result($r)) {
-                       $contact = $r[0];
-               }
-               if ($contact['self']) {
-                       continue;
-               }
-               $deliver_status = 0;
-
-               logger("main delivery by delivery: followup=$followup mail=$mail fsuggest=$fsuggest relocate=$relocate - network ".$contact['network']);
-
-               switch($contact['network']) {
-
-                       case NETWORK_DFRN:
-                               logger('notifier: '.$target_item["guid"].' dfrndelivery: '.$contact['name']);
-
-                               if ($mail) {
-                                       $item['body'] = fix_private_photos($item['body'],$owner['uid'],null,$message[0]['contact-id']);
-                                       $atom = DFRN::mail($item, $owner);
-                               } elseif ($fsuggest) {
-                                       $atom = DFRN::fsuggest($item, $owner);
-                                       q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item['id']));
-                               } elseif ($relocate) {
-                                       $atom = DFRN::relocate($owner, $uid);
-                               } elseif ($followup) {
-                                       $msgitems = array();
-                                       foreach ($items as $item) {  // there is only one item
-                                               if (!$item['parent']) {
-                                                       continue;
-                                               }
-                                               if ($item['id'] == $item_id) {
-                                                       logger('followup: item: '. print_r($item,true), LOGGER_DATA);
-                                                       $msgitems[] = $item;
-                                               }
-                                       }
-                                       $atom = DFRN::entries($msgitems,$owner);
-                               } else {
-                                       $msgitems = array();
-                                       foreach ($items as $item) {
-                                               if (!$item['parent']) {
-                                                       continue;
-                                               }
-
-                                               // private emails may be in included in public conversations. Filter them.
-                                               if ($public_message && $item['private']) {
-                                                       continue;
-                                               }
-
-                                               $item_contact = get_item_contact($item,$icontacts);
-                                               if (!$item_contact) {
-                                                       continue;
-                                               }
-
-                                               if ($normal_mode) {
-                                                       if ($item_id == $item['id'] || $item['id'] == $item['parent']) {
-                                                               $item["entry:comment-allow"] = true;
-                                                               $item["entry:cid"] = (($top_level) ? $contact['id'] : 0);
-                                                               $msgitems[] = $item;
-                                                       }
-                                               } else {
-                                                       $item["entry:comment-allow"] = true;
-                                                       $msgitems[] = $item;
-                                               }
-                                       }
-                                       $atom = DFRN::entries($msgitems,$owner);
-                               }
-
-                               logger('notifier entry: '.$contact["url"].' '.$target_item["guid"].' entry: '.$atom, LOGGER_DEBUG);
-
-                               logger('notifier: '.$atom, LOGGER_DATA);
-                               $basepath =  implode('/', array_slice(explode('/',$contact['url']),0,3));
-
-                               // perform local delivery if we are on the same site
-
-                               if (link_compare($basepath,System::baseUrl())) {
-
-                                       $nickname = basename($contact['url']);
-                                       if ($contact['issued-id']) {
-                                               $sql_extra = sprintf(" AND `dfrn-id` = '%s' ", dbesc($contact['issued-id']));
-                                       } else {
-                                               $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($contact['dfrn-id']));
-                                       }
-
-                                       $x = q("SELECT  `contact`.*, `contact`.`uid` AS `importer_uid`,
-                                               `contact`.`pubkey` AS `cpubkey`,
-                                               `contact`.`prvkey` AS `cprvkey`,
-                                               `contact`.`thumb` AS `thumb`,
-                                               `contact`.`url` as `url`,
-                                               `contact`.`name` as `senderName`,
-                                               `user`.*
-                                               FROM `contact`
-                                               INNER JOIN `user` ON `contact`.`uid` = `user`.`uid`
-                                               WHERE `contact`.`blocked` = 0 AND `contact`.`pending` = 0
-                                               AND `contact`.`network` = '%s' AND `user`.`nickname` = '%s'
-                                               $sql_extra
-                                               AND `user`.`account_expired` = 0 AND `user`.`account_removed` = 0 LIMIT 1",
-                                               dbesc(NETWORK_DFRN),
-                                               dbesc($nickname)
-                                       );
-
-                                       if ($x && count($x)) {
-                                               $write_flag = ((($x[0]['rel']) && ($x[0]['rel'] != CONTACT_IS_SHARING)) ? true : false);
-                                               if ((($owner['page-flags'] == PAGE_COMMUNITY) || $write_flag) && !$x[0]['writable']) {
-                                                       q("UPDATE `contact` SET `writable` = 1 WHERE `id` = %d",
-                                                               intval($x[0]['id'])
-                                                       );
-                                                       $x[0]['writable'] = 1;
-                                               }
-
-                                               $ssl_policy = Config::get('system','ssl_policy');
-                                               fix_contact_ssl_policy($x[0],$ssl_policy);
-
-                                               // If we are setup as a soapbox we aren't accepting top level posts from this person
-
-                                               if (($x[0]['page-flags'] == PAGE_SOAPBOX) && $top_level) {
-                                                       break;
-                                               }
-                                               logger('mod-delivery: local delivery');
-                                               DFRN::import($atom, $x[0]);
-                                               break;
-                                       }
-                               }
-
-                               if (!was_recently_delayed($contact['id'])) {
-                                       $deliver_status = DFRN::deliver($owner,$contact,$atom);
-                               } else {
-                                       $deliver_status = (-1);
-                               }
-
-                               logger('notifier: dfrn_delivery to '.$contact["url"].' with guid '.$target_item["guid"].' returns '.$deliver_status);
-
-                               if ($deliver_status < 0) {
-                                       logger('notifier: delivery failed: queuing message');
-                                       add_to_queue($contact['id'],NETWORK_DFRN,$atom);
-
-                                       // The message could not be delivered. We mark the contact as "dead"
-                                       mark_for_death($contact);
-                               } else {
-                                       // We successfully delivered a message, the contact is alive
-                                       unmark_for_death($contact);
-                               }
-
-                               break;
-
-                       case NETWORK_OSTATUS:
-                               // Do not send to otatus if we are not configured to send to public networks
-                               if ($owner['prvnets']) {
-                                       break;
-                               }
-                               if (Config::get('system','ostatus_disabled') || Config::get('system','dfrn_only')) {
-                                       break;
-                               }
-
-                               // There is currently no code here to distribute anything to OStatus.
-                               // This is done in "notifier.php" (See "url_recipients" and "push_notify")
-                               break;
-
-                       case NETWORK_MAIL:
-                       case NETWORK_MAIL2:
-
-                               if (Config::get('system','dfrn_only')) {
-                                       break;
-                               }
-                               // WARNING: does not currently convert to RFC2047 header encodings, etc.
-
-                               $addr = $contact['addr'];
-                               if (!strlen($addr)) {
-                                       break;
-                               }
-
-                               if ($cmd === 'wall-new' || $cmd === 'comment-new') {
-
-                                       $it = null;
-                                       if ($cmd === 'wall-new') {
-                                               $it = $items[0];
-                                       } else {
-                                               $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1",
-                                                       intval($argv[2]),
-                                                       intval($uid)
-                                               );
-                                               if (DBM::is_result($r))
-                                                       $it = $r[0];
-                                       }
-                                       if (!$it)
-                                               break;
-
-
-                                       $local_user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
-                                               intval($uid)
-                                       );
-                                       if (!count($local_user))
-                                               break;
-
-                                       $reply_to = '';
-                                       $r1 = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1",
-                                               intval($uid)
-                                       );
-                                       if ($r1 && $r1[0]['reply_to'])
-                                               $reply_to = $r1[0]['reply_to'];
-
-                                       $subject  = (($it['title']) ? email_header_encode($it['title'],'UTF-8') : t("\x28no subject\x29")) ;
-
-                                       // only expose our real email address to true friends
-
-                                       if (($contact['rel'] == CONTACT_IS_FRIEND) && !$contact['blocked']) {
-                                               if ($reply_to) {
-                                                       $headers  = 'From: '.email_header_encode($local_user[0]['username'],'UTF-8').' <'.$reply_to.'>'."\n";
-                                                       $headers .= 'Sender: '.$local_user[0]['email']."\n";
-                                               } else {
-                                                       $headers  = 'From: '.email_header_encode($local_user[0]['username'],'UTF-8').' <'.$local_user[0]['email'].'>'."\n";
-                                               }
-                                       } else {
-                                               $headers  = 'From: '. email_header_encode($local_user[0]['username'],'UTF-8') .' <'. t('noreply') .'@'.$a->get_hostname() .'>'. "\n";
-                                       }
-
-                                       //if ($reply_to)
-                                       //      $headers .= 'Reply-to: '.$reply_to . "\n";
-
-                                       $headers .= 'Message-Id: <'. iri2msgid($it['uri']).'>'. "\n";
-
-                                       //logger("Mail: uri: ".$it['uri']." parent-uri ".$it['parent-uri'], LOGGER_DEBUG);
-                                       //logger("Mail: Data: ".print_r($it, true), LOGGER_DEBUG);
-                                       //logger("Mail: Data: ".print_r($it, true), LOGGER_DATA);
-
-                                       if ($it['uri'] !== $it['parent-uri']) {
-                                               $headers .= "References: <".iri2msgid($it["parent-uri"]).">";
-
-                                               // If Threading is enabled, write down the correct parent
-                                               if (($it["thr-parent"] != "") && ($it["thr-parent"] != $it["parent-uri"]))
-                                                       $headers .= " <".iri2msgid($it["thr-parent"]).">";
-                                               $headers .= "\n";
-
-                                               if (!$it['title']) {
-                                                       $r = q("SELECT `title` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
-                                                               dbesc($it['parent-uri']),
-                                                               intval($uid));
-
-                                                       if (DBM::is_result($r) && ($r[0]['title'] != '')) {
-                                                               $subject = $r[0]['title'];
-                                                       } else {
-                                                               $r = q("SELECT `title` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d LIMIT 1",
-                                                                       dbesc($it['parent-uri']),
-                                                                       intval($uid));
-
-                                                               if (DBM::is_result($r) && ($r[0]['title'] != ''))
-                                                                       $subject = $r[0]['title'];
-                                                       }
-                                               }
-                                               if (strncasecmp($subject,'RE:',3))
-                                                       $subject = 'Re: '.$subject;
-                                       }
-                                       email_send($addr, $subject, $headers, $it);
-                               }
-                               break;
-
-                       case NETWORK_DIASPORA:
-                               if ($public_message)
-                                       $loc = 'public batch '.$contact['batch'];
-                               else
-                                       $loc = $contact['name'];
-
-                               logger('delivery: diaspora batch deliver: '.$loc);
-
-                               if (Config::get('system','dfrn_only') || (!Config::get('system','diaspora_enabled')))
-                                       break;
-
-                               if ($mail) {
-                                       Diaspora::send_mail($item,$owner,$contact);
-                                       break;
-                               }
-
-                               if (!$normal_mode)
-                                       break;
-
-                               if (!$contact['pubkey'] && !$public_message)
-                                       break;
-
-                               if (($target_item['deleted']) && (($target_item['uri'] === $target_item['parent-uri']) || $followup)) {
-                                       // top-level retraction
-                                       logger('diaspora retract: '.$loc);
-                                       Diaspora::send_retraction($target_item,$owner,$contact,$public_message);
-                                       break;
-                               } elseif ($relocate) {
-                                       Diaspora::sendAccountMigration($owner, $contact, $uid);
-                                       break;
-                               } elseif ($followup) {
-                                       // send comments and likes to owner to relay
-                                       logger('diaspora followup: '.$loc);
-                                       Diaspora::send_followup($target_item,$owner,$contact,$public_message);
-                                       break;
-                               } elseif ($target_item['uri'] !== $target_item['parent-uri']) {
-                                       // we are the relay - send comments, likes and relayable_retractions to our conversants
-                                       logger('diaspora relay: '.$loc);
-                                       Diaspora::send_relay($target_item,$owner,$contact,$public_message);
-                                       break;
-                               } elseif ($top_level && !$walltowall) {
-                                       // currently no workable solution for sending walltowall
-                                       logger('diaspora status: '.$loc);
-                                       Diaspora::send_status($target_item,$owner,$contact,$public_message);
-                                       break;
-                               }
-
-                               logger('delivery: diaspora unknown mode: '.$contact['name']);
-
-                               break;
-
-                       default:
-                               break;
-               }
-       }
-
-       return;
-}
diff --git a/include/directory.php b/include/directory.php
deleted file mode 100644 (file)
index f56e8db..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-<?php
-
-use Friendica\Core\Config;
-use Friendica\Core\Worker;
-use Friendica\Database\DBM;
-
-function directory_run(&$argv, &$argc){
-       $dir = Config::get('system', 'directory');
-
-       if (!strlen($dir)) {
-               return;
-       }
-
-       if ($argc < 2) {
-               directory_update_all();
-               return;
-       }
-
-       $dir .= "/submit";
-
-       $arr = array('url' => $argv[1]);
-
-       call_hooks('globaldir_update', $arr);
-
-       logger('Updating directory: ' . $arr['url'], LOGGER_DEBUG);
-       if (strlen($arr['url'])) {
-               fetch_url($dir . '?url=' . bin2hex($arr['url']));
-       }
-
-       return;
-}
-
-function directory_update_all() {
-       $r = q("SELECT `url` FROM `contact`
-               INNER JOIN `profile` ON `profile`.`uid` = `contact`.`uid`
-               INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
-                       WHERE `contact`.`self` AND `profile`.`net-publish` AND `profile`.`is-default` AND
-                               NOT `user`.`account_expired` AND `user`.`verified`");
-
-       if (DBM::is_result($r)) {
-               foreach ($r AS $user) {
-                       Worker::add(PRIORITY_LOW, 'directory', $user['url']);
-               }
-       }
-}
diff --git a/include/discover_poco.php b/include/discover_poco.php
deleted file mode 100644 (file)
index bb8daad..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-<?php
-use Friendica\Core\Cache;
-use Friendica\Core\Config;
-use Friendica\Core\Worker;
-use Friendica\Database\DBM;
-use Friendica\Network\Probe;
-
-require_once 'include/socgraph.php';
-require_once 'include/datetime.php';
-
-function discover_poco_run(&$argv, &$argc) {
-
-       /*
-       This function can be called in these ways:
-       - dirsearch <search pattern>: Searches for "search pattern" in the directory. "search pattern" is url encoded.
-       - checkcontact: Updates gcontact entries
-       - suggestions: Discover other servers for their contacts.
-       - server <poco url>: Searches for the poco server list. "poco url" is base64 encoded.
-       - update_server: Frequently check the first 250 servers for vitality.
-       - update_server_directory: Discover the given server id for their contacts
-       - poco_load: Load POCO data from a given POCO address
-       - check_profile: Update remote profile data
-       */
-
-       if (($argc > 2) && ($argv[1] == "dirsearch")) {
-               $search = urldecode($argv[2]);
-               $mode = 1;
-       } elseif (($argc == 2) && ($argv[1] == "checkcontact")) {
-               $mode = 2;
-       } elseif (($argc == 2) && ($argv[1] == "suggestions")) {
-               $mode = 3;
-       } elseif (($argc == 3) && ($argv[1] == "server")) {
-               $mode = 4;
-       } elseif (($argc == 2) && ($argv[1] == "update_server")) {
-               $mode = 5;
-       } elseif (($argc == 3) && ($argv[1] == "update_server_directory")) {
-               $mode = 6;
-       } elseif (($argc > 5) && ($argv[1] == "poco_load")) {
-               $mode = 7;
-       } elseif (($argc == 3) && ($argv[1] == "check_profile")) {
-               $mode = 8;
-       } elseif ($argc == 1) {
-               $search = "";
-               $mode = 0;
-       } else {
-               die("Unknown or missing parameter ".$argv[1]."\n");
-       }
-
-       logger('start '.$search);
-
-       if ($mode == 8) {
-               if ($argv[2] != "") {
-                       poco_last_updated($argv[2], true);
-               }
-       } elseif ($mode == 7) {
-               if ($argc == 6) {
-                       $url = $argv[5];
-               } else {
-                       $url = '';
-               }
-               poco_load_worker(intval($argv[2]), intval($argv[3]), intval($argv[4]), $url);
-       } elseif ($mode == 6) {
-               poco_discover_single_server(intval($argv[2]));
-       } elseif ($mode == 5) {
-               update_server();
-       } elseif ($mode == 4) {
-               $server_url = $argv[2];
-               if ($server_url == "") {
-                       return;
-               }
-               $server_url = filter_var($server_url, FILTER_SANITIZE_URL);
-               if (substr(normalise_link($server_url), 0, 7) != "http://") {
-                       return;
-               }
-               $result = "Checking server ".$server_url." - ";
-               $ret = poco_check_server($server_url);
-               if ($ret) {
-                       $result .= "success";
-               } else {
-                       $result .= "failed";
-               }
-               logger($result, LOGGER_DEBUG);
-       } elseif ($mode == 3) {
-               update_suggestions();
-       } elseif (($mode == 2) && Config::get('system','poco_completion')) {
-               discover_users();
-       } elseif (($mode == 1) && ($search != "") && Config::get('system','poco_local_search')) {
-               discover_directory($search);
-               gs_search_user($search);
-       } elseif (($mode == 0) && ($search == "") && (Config::get('system','poco_discovery') > 0)) {
-               // Query Friendica and Hubzilla servers for their users
-               poco_discover();
-
-               // Query GNU Social servers for their users ("statistics" addon has to be enabled on the GS server)
-               if (!Config::get('system','ostatus_disabled'))
-                       gs_discover();
-       }
-
-       logger('end '.$search);
-
-       return;
-}
-
-/**
- * @brief Updates the first 250 servers
- *
- */
-function update_server() {
-       $r = q("SELECT `url`, `created`, `last_failure`, `last_contact` FROM `gserver` ORDER BY rand()");
-
-       if (!DBM::is_result($r)) {
-               return;
-       }
-
-       $updated = 0;
-
-       foreach ($r AS $server) {
-               if (!poco_do_update($server["created"], "", $server["last_failure"], $server["last_contact"])) {
-                       continue;
-               }
-               logger('Update server status for server '.$server["url"], LOGGER_DEBUG);
-
-               Worker::add(PRIORITY_LOW, "discover_poco", "server", $server["url"]);
-
-               if (++$updated > 250) {
-                       return;
-               }
-       }
-}
-
-function discover_users() {
-       logger("Discover users", LOGGER_DEBUG);
-
-       $starttime = time();
-
-       $users = q("SELECT `url`, `created`, `updated`, `last_failure`, `last_contact`, `server_url`, `network` FROM `gcontact`
-                       WHERE `last_contact` < UTC_TIMESTAMP - INTERVAL 1 MONTH AND
-                               `last_failure` < UTC_TIMESTAMP - INTERVAL 1 MONTH AND
-                               `network` IN ('%s', '%s', '%s', '%s', '') ORDER BY rand()",
-                       dbesc(NETWORK_DFRN), dbesc(NETWORK_DIASPORA),
-                       dbesc(NETWORK_OSTATUS), dbesc(NETWORK_FEED));
-
-       if (!$users) {
-               return;
-       }
-       $checked = 0;
-
-       foreach ($users AS $user) {
-
-               $urlparts = parse_url($user["url"]);
-               if (!isset($urlparts["scheme"])) {
-                       q("UPDATE `gcontact` SET `network` = '%s' WHERE `nurl` = '%s'",
-                               dbesc(NETWORK_PHANTOM), dbesc(normalise_link($user["url"])));
-                       continue;
-                }
-
-               if (in_array($urlparts["host"], array("www.facebook.com", "facebook.com", "twitter.com",
-                                                       "identi.ca", "alpha.app.net"))) {
-                       $networks = array("www.facebook.com" => NETWORK_FACEBOOK,
-                                       "facebook.com" => NETWORK_FACEBOOK,
-                                       "twitter.com" => NETWORK_TWITTER,
-                                       "identi.ca" => NETWORK_PUMPIO,
-                                       "alpha.app.net" => NETWORK_APPNET);
-
-                       q("UPDATE `gcontact` SET `network` = '%s' WHERE `nurl` = '%s'",
-                               dbesc($networks[$urlparts["host"]]), dbesc(normalise_link($user["url"])));
-                       continue;
-               }
-
-               $server_url = poco_detect_server($user["url"]);
-               $force_update = false;
-
-               if ($user["server_url"] != "") {
-
-                       $force_update = (normalise_link($user["server_url"]) != normalise_link($server_url));
-
-                       $server_url = $user["server_url"];
-               }
-
-               if ((($server_url == "") && ($user["network"] == NETWORK_FEED)) || $force_update || poco_check_server($server_url, $user["network"])) {
-                       logger('Check profile '.$user["url"]);
-                       Worker::add(PRIORITY_LOW, "discover_poco", "check_profile", $user["url"]);
-
-                       if (++$checked > 100) {
-                               return;
-                       }
-               } else {
-                       q("UPDATE `gcontact` SET `last_failure` = '%s' WHERE `nurl` = '%s'",
-                               dbesc(datetime_convert()), dbesc(normalise_link($user["url"])));
-               }
-
-               // Quit the loop after 3 minutes
-               if (time() > ($starttime + 180)) {
-                       return;
-               }
-       }
-}
-
-function discover_directory($search) {
-
-       $data = Cache::get("dirsearch:".$search);
-       if (!is_null($data)) {
-               // Only search for the same item every 24 hours
-               if (time() < $data + (60 * 60 * 24)) {
-                       logger("Already searched for ".$search." in the last 24 hours", LOGGER_DEBUG);
-                       return;
-               }
-       }
-
-       $x = fetch_url(get_server()."/lsearch?p=1&n=500&search=".urlencode($search));
-       $j = json_decode($x);
-
-       if (count($j->results)) {
-               foreach ($j->results as $jj) {
-                       // Check if the contact already exists
-                       $exists = q("SELECT `id`, `last_contact`, `last_failure`, `updated` FROM `gcontact` WHERE `nurl` = '%s'", normalise_link($jj->url));
-                       if (DBM::is_result($exists)) {
-                               logger("Profile ".$jj->url." already exists (".$search.")", LOGGER_DEBUG);
-
-                               if (($exists[0]["last_contact"] < $exists[0]["last_failure"]) &&
-                                       ($exists[0]["updated"] < $exists[0]["last_failure"])) {
-                                       continue;
-                               }
-                               // Update the contact
-                               poco_last_updated($jj->url);
-                               continue;
-                       }
-
-                       $server_url = poco_detect_server($jj->url);
-                       if ($server_url != '') {
-                               if (!poco_check_server($server_url)) {
-                                       logger("Friendica server ".$server_url." doesn't answer.", LOGGER_DEBUG);
-                                       continue;
-                               }
-                               logger("Friendica server ".$server_url." seems to be okay.", LOGGER_DEBUG);
-                       }
-
-                       $data = Probe::uri($jj->url);
-                       if ($data["network"] == NETWORK_DFRN) {
-                               logger("Profile ".$jj->url." is reachable (".$search.")", LOGGER_DEBUG);
-                               logger("Add profile ".$jj->url." to local directory (".$search.")", LOGGER_DEBUG);
-
-                               if ($jj->tags != "") {
-                                       $data["keywords"] = $jj->tags;
-                               }
-
-                               $data["server_url"] = $data["baseurl"];
-
-                               update_gcontact($data);
-                       } else {
-                               logger("Profile ".$jj->url." is not responding or no Friendica contact - but network ".$data["network"], LOGGER_DEBUG);
-                       }
-               }
-       }
-       Cache::set("dirsearch:".$search, time(), CACHE_DAY);
-}
-
-/**
- * @brief Search for GNU Social user with gstools.org
- *
- * @param str $search User name
- */
-function gs_search_user($search) {
-
-       // Currently disabled, since the service isn't available anymore.
-       // It is not removed since I hope that there will be a successor.
-       return false;
-
-       $a = get_app();
-
-       $url = "http://gstools.org/api/users_search/".urlencode($search);
-
-       $result = z_fetch_url($url);
-       if (!$result["success"]) {
-               return false;
-       }
-
-       $contacts = json_decode($result["body"]);
-
-       if ($contacts->status == 'ERROR') {
-               return false;
-       }
-
-       /// @TODO AS is considered as a notation for constants (as they usually being written all upper-case)
-       /// @TODO find all those and convert to all lower-case which is a keyword then
-       foreach ($contacts->data AS $user) {
-               $contact = Probe::uri($user->site_address."/".$user->name);
-               if ($contact["network"] != NETWORK_PHANTOM) {
-                       $contact["about"] = $user->description;
-                       update_gcontact($contact);
-               }
-       }
-}
diff --git a/include/expire.php b/include/expire.php
deleted file mode 100644 (file)
index 7a3549a..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-
-use Friendica\Core\Config;
-use Friendica\Core\Worker;
-use Friendica\Database\DBM;
-
-function expire_run(&$argv, &$argc){
-       global $a;
-
-       require_once('include/datetime.php');
-       require_once('include/items.php');
-       require_once('include/Contact.php');
-
-       load_hooks();
-
-       if (($argc == 2) && ($argv[1] == 'delete')) {
-               logger('Delete expired items', LOGGER_DEBUG);
-               // physically remove anything that has been deleted for more than two months
-               $r = dba::p("SELECT `id` FROM `item` WHERE `deleted` AND `changed` < UTC_TIMESTAMP() - INTERVAL 60 DAY");
-               while ($row = dba::fetch($r)) {
-                       dba::delete('item', array('id' => $row['id']));
-               }
-               dba::close($r);
-
-               logger('Delete expired items - done', LOGGER_DEBUG);
-
-               // make this optional as it could have a performance impact on large sites
-               if (intval(Config::get('system', 'optimize_items'))) {
-                       q("OPTIMIZE TABLE `item`");
-               }
-               return;
-       } elseif (($argc == 2) && (intval($argv[1]) > 0)) {
-               $user = dba::select('user', array('uid', 'username', 'expire'), array('uid' => $argv[1]), array('limit' => 1));
-               if (DBM::is_result($user)) {
-                       logger('Expire items for user '.$user['uid'].' ('.$user['username'].') - interval: '.$user['expire'], LOGGER_DEBUG);
-                       item_expire($user['uid'], $user['expire']);
-                       logger('Expire items for user '.$user['uid'].' ('.$user['username'].') - done ', LOGGER_DEBUG);
-               }
-               return;
-       } elseif (($argc == 3) && ($argv[1] == 'hook') && is_array($a->hooks) && array_key_exists("expire", $a->hooks)) {
-               foreach ($a->hooks["expire"] as $hook) {
-                       if ($hook[1] == $argv[2]) {
-                               logger("Calling expire hook '" . $hook[1] . "'", LOGGER_DEBUG);
-                               call_single_hook($a, $name, $hook, $data);
-                       }
-               }
-               return;
-       }
-
-       logger('expire: start');
-
-       Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true),
-                       'expire', 'delete');
-
-       $r = dba::p("SELECT `uid`, `username` FROM `user` WHERE `expire` != 0");
-       while ($row = dba::fetch($r)) {
-               logger('Calling expiry for user '.$row['uid'].' ('.$row['username'].')', LOGGER_DEBUG);
-               Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true),
-                               'expire', (int)$row['uid']);
-       }
-       dba::close($r);
-
-       logger('expire: calling hooks');
-
-       if (is_array($a->hooks) && array_key_exists('expire', $a->hooks)) {
-               foreach ($a->hooks['expire'] as $hook) {
-                       logger("Calling expire hook for '" . $hook[1] . "'", LOGGER_DEBUG);
-                       Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true),
-                                       'expire', 'hook', $hook[1]);
-               }
-       }
-
-       logger('expire: end');
-
-       return;
-}
diff --git a/include/gprobe.php b/include/gprobe.php
deleted file mode 100644 (file)
index 7003051..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-use Friendica\Core\Cache;
-use Friendica\Core\Config;
-use Friendica\Database\DBM;
-use Friendica\Network\Probe;
-
-require_once 'include/socgraph.php';
-require_once 'include/datetime.php';
-
-function gprobe_run(&$argv, &$argc){
-       if ($argc != 2) {
-               return;
-       }
-       $url = $argv[1];
-
-       $r = q("SELECT `id`, `url`, `network` FROM `gcontact` WHERE `nurl` = '%s' ORDER BY `id` LIMIT 1",
-               dbesc(normalise_link($url))
-       );
-
-       logger("gprobe start for ".normalise_link($url), LOGGER_DEBUG);
-
-       if (!DBM::is_result($r)) {
-
-               // Is it a DDoS attempt?
-               $urlparts = parse_url($url);
-
-               $result = Cache::get("gprobe:".$urlparts["host"]);
-               if (!is_null($result)) {
-                       if (in_array($result["network"], array(NETWORK_FEED, NETWORK_PHANTOM))) {
-                               logger("DDoS attempt detected for ".$urlparts["host"]." by ".$_SERVER["REMOTE_ADDR"].". server data: ".print_r($_SERVER, true), LOGGER_DEBUG);
-                               return;
-                       }
-               }
-
-               $arr = Probe::uri($url);
-
-               if (is_null($result)) {
-                       Cache::set("gprobe:".$urlparts["host"], $arr);
-               }
-
-               if (!in_array($arr["network"], array(NETWORK_FEED, NETWORK_PHANTOM))) {
-                       update_gcontact($arr);
-               }
-
-               $r = q("SELECT `id`, `url`, `network` FROM `gcontact` WHERE `nurl` = '%s' ORDER BY `id` LIMIT 1",
-                       dbesc(normalise_link($url))
-               );
-       }
-       if (DBM::is_result($r)) {
-               // Check for accessibility and do a poco discovery
-               if (poco_last_updated($r[0]['url'], true) && ($r[0]["network"] == NETWORK_DFRN))
-                       poco_load(0,0,$r[0]['id'], str_replace('/profile/','/poco/',$r[0]['url']));
-       }
-
-       logger("gprobe end for ".normalise_link($url), LOGGER_DEBUG);
-       return;
-}
diff --git a/include/notifier.php b/include/notifier.php
deleted file mode 100644 (file)
index 3e9ea66..0000000
+++ /dev/null
@@ -1,617 +0,0 @@
-<?php
-
-use Friendica\App;
-use Friendica\Core\Config;
-use Friendica\Core\Worker;
-use Friendica\Database\DBM;
-use Friendica\Network\Probe;
-use Friendica\Protocol\Diaspora;
-
-require_once 'include/queue_fn.php';
-require_once 'include/html2plain.php';
-require_once 'include/ostatus.php';
-require_once 'include/salmon.php';
-
-/*
- * This file was at one time responsible for doing all deliveries, but this caused
- * big problems when the process was killed or stalled during the delivery process.
- * It now invokes separate queues that are delivering via delivery.php and pubsubpublish.php.
- */
-
-/*
- * The notifier is typically called with:
- *
- *             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)
- *             expire                                  (in items.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)
- *
- * and ITEM_ID is the id of the item in the database that needs to be sent to others.
- */
-
-
-function notifier_run(&$argv, &$argc){
-       global $a;
-
-       require_once 'include/datetime.php';
-       require_once 'include/items.php';
-       require_once 'include/bbcode.php';
-       require_once 'include/email.php';
-
-       if ($argc < 3) {
-               return;
-       }
-
-       logger('notifier: invoked: ' . print_r($argv,true), LOGGER_DEBUG);
-
-       $cmd = $argv[1];
-
-       switch($cmd) {
-               case 'mail':
-               default:
-                       $item_id = intval($argv[2]);
-                       if (! $item_id) {
-                               return;
-                       }
-                       break;
-       }
-
-       $expire = false;
-       $mail = false;
-       $fsuggest = false;
-       $relocate = false;
-       $top_level = false;
-       $recipients = array();
-       $url_recipients = array();
-
-       $normal_mode = true;
-
-       if ($cmd === 'mail') {
-               $normal_mode = false;
-               $mail = true;
-               $message = q("SELECT * FROM `mail` WHERE `id` = %d LIMIT 1",
-                               intval($item_id)
-               );
-               if (! count($message)) {
-                       return;
-               }
-               $uid = $message[0]['uid'];
-               $recipients[] = $message[0]['contact-id'];
-               $item = $message[0];
-
-       } elseif ($cmd === 'expire') {
-               $normal_mode = false;
-               $expire = true;
-               $items = q("SELECT * FROM `item` WHERE `uid` = %d AND `wall` = 1
-                       AND `deleted` = 1 AND `changed` > UTC_TIMESTAMP() - INTERVAL 10 MINUTE",
-                       intval($item_id)
-               );
-               $uid = $item_id;
-               $item_id = 0;
-               if (! count($items)) {
-                       return;
-               }
-       } elseif ($cmd === 'suggest') {
-               $normal_mode = false;
-               $fsuggest = true;
-
-               $suggest = q("SELECT * FROM `fsuggest` WHERE `id` = %d LIMIT 1",
-                       intval($item_id)
-               );
-               if (! count($suggest)) {
-                       return;
-               }
-               $uid = $suggest[0]['uid'];
-               $recipients[] = $suggest[0]['cid'];
-               $item = $suggest[0];
-       } elseif ($cmd === 'removeme') {
-               $r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`,
-                               `user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`,
-                               `user`.`page-flags`, `user`.`prvnets`, `user`.`account-type`, `user`.`guid`
-                       FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
-                               WHERE `contact`.`uid` = %d AND `contact`.`self` LIMIT 1",
-                               intval($item_id));
-               if (!$r)
-                       return;
-
-               $user = $r[0];
-
-               $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1", intval($item_id));
-               if (!$r)
-                       return;
-
-               $self = $r[0];
-
-               $r = q("SELECT * FROM `contact` WHERE NOT `self` AND `uid` = %d", intval($item_id));
-               if (!$r) {
-                       return;
-               }
-               require_once 'include/Contact.php';
-               foreach ($r as $contact) {
-                       terminate_friendship($user, $self, $contact);
-               }
-               return;
-       } elseif ($cmd === 'relocate') {
-               $normal_mode = false;
-               $relocate = true;
-               $uid = $item_id;
-
-               $recipients_relocate = q("SELECT * FROM `contact` WHERE `uid` = %d AND NOT `self` AND `network` IN ('%s', '%s')",
-                                       intval($uid), NETWORK_DFRN, NETWORK_DIASPORA);
-       } else {
-               // find ancestors
-               $r = q("SELECT * FROM `item` WHERE `id` = %d AND visible = 1 AND moderated = 0 LIMIT 1",
-                       intval($item_id)
-               );
-
-               if ((! DBM::is_result($r)) || (! intval($r[0]['parent']))) {
-                       return;
-               }
-
-               $target_item = $r[0];
-               $parent_id = intval($r[0]['parent']);
-               $uid = $r[0]['uid'];
-               $updated = $r[0]['edited'];
-
-               $items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer`
-                       FROM `item` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` WHERE `parent` = %d AND visible = 1 AND moderated = 0 ORDER BY `id` ASC",
-                       intval($parent_id)
-               );
-
-               if (! count($items)) {
-                       return;
-               }
-
-               // avoid race condition with deleting entries
-
-               if ($items[0]['deleted']) {
-                       foreach ($items as $item) {
-                               $item['deleted'] = 1;
-                       }
-               }
-
-               if ((count($items) == 1) && ($items[0]['id'] === $target_item['id']) && ($items[0]['uri'] === $items[0]['parent-uri'])) {
-                       logger('notifier: top level post');
-                       $top_level = true;
-               }
-
-       }
-
-       $r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`,
-               `user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`,
-               `user`.`page-flags`, `user`.`prvnets`, `user`.`account-type`
-               FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
-               WHERE `contact`.`uid` = %d AND `contact`.`self` = 1 LIMIT 1",
-               intval($uid)
-       );
-
-       if (! DBM::is_result($r)) {
-               return;
-       }
-
-       $owner = $r[0];
-
-       $walltowall = ((($top_level) && ($owner['id'] != $items[0]['contact-id'])) ? true : false);
-
-       // Should the post be transmitted to Diaspora?
-       $diaspora_delivery = true;
-
-       // If this is a public conversation, notify the feed hub
-       $public_message = true;
-
-       // Do a PuSH
-       $push_notify = false;
-
-       // Deliver directly to a forum, don't PuSH
-       $direct_forum_delivery = false;
-
-       // fill this in with a single salmon slap if applicable
-       $slap = '';
-
-       if (! ($mail || $fsuggest || $relocate)) {
-
-               $slap = ostatus::salmon($target_item,$owner);
-
-               require_once 'include/group.php';
-
-               $parent = $items[0];
-
-               $thr_parent = q("SELECT `network`, `author-link`, `owner-link` FROM `item` WHERE `uri` = '%s' AND `uid` = %d",
-                       dbesc($target_item["thr-parent"]), intval($target_item["uid"]));
-
-               logger('GUID: '.$target_item["guid"].': Parent is '.$parent['network'].'. Thread parent is '.$thr_parent[0]['network'], LOGGER_DEBUG);
-
-               // This is IMPORTANT!!!!
-
-               // We will only send a "notify owner to relay" or followup message if the referenced post
-               // originated on our system by virtue of having our hostname somewhere
-               // in the URI, AND it was a comment (not top_level) AND the parent originated elsewhere.
-
-               // if $parent['wall'] == 1 we will already have the parent message in our array
-               // and we will relay the whole lot.
-
-               // expire sends an entire group of expire messages and cannot be forwarded.
-               // However the conversation owner will be a part of the conversation and will
-               // be notified during this run.
-               // Other DFRN conversation members will be alerted during polled updates.
-
-
-
-               // Diaspora members currently are not notified of expirations, and other networks have
-               // either limited or no ability to process deletions. We should at least fix Diaspora
-               // by stringing togther an array of retractions and sending them onward.
-
-
-               $localhost = str_replace('www.','',$a->get_hostname());
-               if (strpos($localhost,':')) {
-                       $localhost = substr($localhost,0,strpos($localhost,':'));
-               }
-               /**
-                *
-                * Be VERY CAREFUL if you make any changes to the following several lines. Seemingly innocuous changes
-                * have been known to cause runaway conditions which affected several servers, along with
-                * permissions issues.
-                *
-                */
-
-               $relay_to_owner = false;
-
-               if (!$top_level && ($parent['wall'] == 0) && !$expire && (stristr($target_item['uri'],$localhost))) {
-                       $relay_to_owner = true;
-               }
-
-
-               if (($cmd === 'uplink') && (intval($parent['forum_mode']) == 1) && !$top_level) {
-                       $relay_to_owner = true;
-               }
-
-               // until the 'origin' flag has been in use for several months
-               // we will just use it as a fallback test
-               // later we will be able to use it as the primary test of whether or not to relay.
-
-               if (! $target_item['origin']) {
-                       $relay_to_owner = false;
-               }
-               if ($parent['origin']) {
-                       $relay_to_owner = false;
-               }
-
-               // Special treatment for forum posts
-               if (($target_item['author-link'] != $target_item['owner-link']) &&
-                       ($owner['id'] != $target_item['contact-id']) &&
-                       ($target_item['uri'] === $target_item['parent-uri'])) {
-
-                       $fields = array('forum', 'prv');
-                       $condition = array('id' => $target_item['contact-id']);
-                       $contact = dba::select('contact', $fields, $condition, array('limit' => 1));
-                       if (!DBM::is_result($contact)) {
-                               // Should never happen
-                               return false;
-                       }
-
-                       // Is the post from a forum?
-                       if ($contact['forum'] || $contact['prv']) {
-                               $relay_to_owner = true;
-                               $direct_forum_delivery = true;
-                       }
-               }
-               if ($relay_to_owner) {
-                       logger('notifier: followup '.$target_item["guid"], LOGGER_DEBUG);
-                       // local followup to remote post
-                       $followup = true;
-                       $public_message = false; // not public
-                       $conversant_str = dbesc($parent['contact-id']);
-                       $recipients = array($parent['contact-id']);
-                       $recipients_followup  = array($parent['contact-id']);
-
-                       //if (!$target_item['private'] && $target_item['wall'] &&
-                       if (!$target_item['private'] &&
-                               (strlen($target_item['allow_cid'].$target_item['allow_gid'].
-                                       $target_item['deny_cid'].$target_item['deny_gid']) == 0))
-                               $push_notify = true;
-
-                       if (($thr_parent && ($thr_parent[0]['network'] == NETWORK_OSTATUS)) || ($parent['network'] == NETWORK_OSTATUS)) {
-
-                               $push_notify = true;
-
-                               if ($parent["network"] == NETWORK_OSTATUS) {
-                                       // Distribute the message to the DFRN contacts as if this wasn't a followup since OStatus can't relay comments
-                                       // Currently it is work at progress
-                                       $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `network` = '%s' AND NOT `blocked` AND NOT `pending` AND NOT `archive`",
-                                               intval($uid),
-                                               dbesc(NETWORK_DFRN)
-                                       );
-                                       if (DBM::is_result($r)) {
-                                               foreach ($r as $rr) {
-                                                       $recipients_followup[] = $rr['id'];
-                                               }
-                                       }
-                               }
-                       }
-
-                       if ($direct_forum_delivery) {
-                               $push_notify = false;
-                       }
-
-                       logger("Notify ".$target_item["guid"]." via PuSH: ".($push_notify?"Yes":"No"), LOGGER_DEBUG);
-               } else {
-                       $followup = false;
-
-                       logger('Distributing directly '.$target_item["guid"], LOGGER_DEBUG);
-
-                       // don't send deletions onward for other people's stuff
-
-                       if ($target_item['deleted'] && (! intval($target_item['wall']))) {
-                               logger('notifier: ignoring delete notification for non-wall item');
-                               return;
-                       }
-
-                       if ((strlen($parent['allow_cid']))
-                               || (strlen($parent['allow_gid']))
-                               || (strlen($parent['deny_cid']))
-                               || (strlen($parent['deny_gid']))) {
-                               $public_message = false; // private recipients, not public
-                       }
-
-                       $allow_people = expand_acl($parent['allow_cid']);
-                       $allow_groups = expand_groups(expand_acl($parent['allow_gid']),true);
-                       $deny_people  = expand_acl($parent['deny_cid']);
-                       $deny_groups  = expand_groups(expand_acl($parent['deny_gid']));
-
-                       // 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', $item_id);
-                       }
-
-                       $conversants = array();
-
-                       foreach ($items as $item) {
-                               $recipients[] = $item['contact-id'];
-                               $conversants[] = $item['contact-id'];
-                               // pull out additional tagged people to notify (if public message)
-                               if ($public_message && strlen($item['inform'])) {
-                                       $people = explode(',',$item['inform']);
-                                       foreach ($people as $person) {
-                                               if (substr($person,0,4) === 'cid:') {
-                                                       $recipients[] = intval(substr($person,4));
-                                                       $conversants[] = intval(substr($person,4));
-                                               } else {
-                                                       $url_recipients[] = substr($person,4);
-                                               }
-                                       }
-                               }
-                       }
-
-                       if (count($url_recipients))
-                               logger('notifier: '.$target_item["guid"].' url_recipients ' . print_r($url_recipients,true));
-
-                       $conversants = array_unique($conversants);
-
-
-                       $recipients = array_unique(array_merge($recipients,$allow_people,$allow_groups));
-                       $deny = array_unique(array_merge($deny_people,$deny_groups));
-                       $recipients = array_diff($recipients,$deny);
-
-                       $conversant_str = dbesc(implode(', ',$conversants));
-               }
-
-               // If the thread parent is OStatus then do some magic to distribute the messages.
-               // We have not only to look at the parent, since it could be a Friendica thread.
-               if (($thr_parent && ($thr_parent[0]['network'] == NETWORK_OSTATUS)) || ($parent['network'] == NETWORK_OSTATUS)) {
-
-                       $diaspora_delivery = false;
-
-                       logger('Some parent is OStatus for '.$target_item["guid"]." - Author: ".$thr_parent[0]['author-link']." - Owner: ".$thr_parent[0]['owner-link'], LOGGER_DEBUG);
-
-                       // Send a salmon to the parent author
-                       $r = q("SELECT `url`, `notify` FROM `contact` WHERE `nurl`='%s' AND `uid` IN (0, %d) AND `notify` != ''",
-                               dbesc(normalise_link($thr_parent[0]['author-link'])),
-                               intval($uid));
-                       if (DBM::is_result($r)) {
-                               $probed_contact = $r[0];
-                       } else {
-                               $probed_contact = Probe::uri($thr_parent[0]['author-link']);
-                       }
-
-                       if ($probed_contact["notify"] != "") {
-                               logger('Notify parent author '.$probed_contact["url"].': '.$probed_contact["notify"]);
-                               $url_recipients[$probed_contact["notify"]] = $probed_contact["notify"];
-                       }
-
-                       // Send a salmon to the parent owner
-                       $r = q("SELECT `url`, `notify` FROM `contact` WHERE `nurl`='%s' AND `uid` IN (0, %d) AND `notify` != ''",
-                               dbesc(normalise_link($thr_parent[0]['owner-link'])),
-                               intval($uid));
-                       if (DBM::is_result($r)) {
-                               $probed_contact = $r[0];
-                       } else {
-                               $probed_contact = Probe::uri($thr_parent[0]['owner-link']);
-                       }
-
-                       if ($probed_contact["notify"] != "") {
-                               logger('Notify parent owner '.$probed_contact["url"].': '.$probed_contact["notify"]);
-                               $url_recipients[$probed_contact["notify"]] = $probed_contact["notify"];
-                       }
-
-                       // Send a salmon notification to every person we mentioned in the post
-                       $arr = explode(',',$target_item['tag']);
-                       foreach ($arr as $x) {
-                               //logger('Checking tag '.$x, LOGGER_DEBUG);
-                               $matches = null;
-                               if (preg_match('/@\[url=([^\]]*)\]/',$x,$matches)) {
-                                               $probed_contact = Probe::uri($matches[1]);
-                                       if ($probed_contact["notify"] != "") {
-                                               logger('Notify mentioned user '.$probed_contact["url"].': '.$probed_contact["notify"]);
-                                               $url_recipients[$probed_contact["notify"]] = $probed_contact["notify"];
-                                       }
-                               }
-                       }
-
-                       // It only makes sense to distribute answers to OStatus messages to Friendica and OStatus - but not Diaspora
-                       $sql_extra = " AND `network` IN ('".NETWORK_OSTATUS."', '".NETWORK_DFRN."')";
-               } else {
-                       $sql_extra = " AND `network` IN ('".NETWORK_OSTATUS."', '".NETWORK_DFRN."', '".NETWORK_DIASPORA."', '".NETWORK_MAIL."', '".NETWORK_MAIL2."')";
-               }
-       } else {
-               $public_message = false;
-       }
-
-       // If this is a public message and pubmail is set on the parent, include all your email contacts
-
-       $mail_disabled = ((function_exists('imap_open') && (!Config::get('system','imap_disabled'))) ? 0 : 1);
-
-       if (! $mail_disabled) {
-               if ((! strlen($target_item['allow_cid'])) && (! strlen($target_item['allow_gid']))
-                       && (! strlen($target_item['deny_cid'])) && (! strlen($target_item['deny_gid']))
-                       && (intval($target_item['pubmail']))) {
-                       $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `network` = '%s'",
-                               intval($uid),
-                               dbesc(NETWORK_MAIL)
-                       );
-                       if (DBM::is_result($r)) {
-                               foreach ($r as $rr) {
-                                       $recipients[] = $rr['id'];
-                               }
-                       }
-               }
-       }
-
-       if ($followup) {
-               $recip_str = implode(', ', $recipients_followup);
-       } else {
-               $recip_str = implode(', ', $recipients);
-       }
-       if ($relocate) {
-               $r = $recipients_relocate;
-       } else {
-               $r = q("SELECT `id`, `url`, `network`, `self` FROM `contact`
-                       WHERE `id` IN (%s) AND NOT `blocked` AND NOT `pending` AND NOT `archive`".$sql_extra,
-                       dbesc($recip_str)
-               );
-       }
-
-       // delivery loop
-
-       if (DBM::is_result($r)) {
-               foreach ($r as $contact) {
-                       if ($contact['self']) {
-                               continue;
-                       }
-                       logger("Deliver ".$target_item["guid"]." to ".$contact['url']." via network ".$contact['network'], LOGGER_DEBUG);
-
-                       Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true),
-                                       'delivery', $cmd, $item_id, (int)$contact['id']);
-               }
-       }
-
-       // send salmon slaps to mentioned remote tags (@foo@example.com) in OStatus posts
-       // They are especially used for notifications to OStatus users that don't follow us.
-
-       if ($slap && count($url_recipients) && ($public_message || $push_notify) && $normal_mode) {
-               if (!Config::get('system','dfrn_only')) {
-                       foreach ($url_recipients as $url) {
-                               if ($url) {
-                                       logger('notifier: urldelivery: ' . $url);
-                                       $deliver_status = slapper($owner,$url,$slap);
-                                       /// @TODO Redeliver/queue these items on failure, though there is no contact record
-                               }
-                       }
-               }
-       }
-
-
-       if ($public_message) {
-
-               $r0 = array();
-               $r1 = array();
-
-               if ($diaspora_delivery) {
-                       if (!$followup) {
-                               $r0 = Diaspora::relay_list();
-                       }
-
-                       $r1 = q("SELECT `batch`, ANY_VALUE(`id`) AS `id`, ANY_VALUE(`name`) AS `name`, ANY_VALUE(`network`) AS `network`
-                               FROM `contact` WHERE `network` = '%s' AND `batch` != ''
-                               AND `uid` = %d AND `rel` != %d AND NOT `blocked` AND NOT `pending` AND NOT `archive` GROUP BY `batch`",
-                               dbesc(NETWORK_DIASPORA),
-                               intval($owner['uid']),
-                               intval(CONTACT_IS_SHARING)
-                       );
-               }
-
-               $r2 = q("SELECT `id`, `name`,`network` FROM `contact`
-                       WHERE `network` in ('%s', '%s') AND `uid` = %d AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `rel` != %d",
-                       dbesc(NETWORK_DFRN),
-                       dbesc(NETWORK_MAIL2),
-                       intval($owner['uid']),
-                       intval(CONTACT_IS_SHARING)
-               );
-
-               $r = array_merge($r2,$r1,$r0);
-
-               if (DBM::is_result($r)) {
-                       logger('pubdeliver '.$target_item["guid"].': '.print_r($r,true), LOGGER_DEBUG);
-
-                       foreach ($r as $rr) {
-
-                               // except for Diaspora batch jobs
-                               // Don't deliver to folks who have already been delivered to
-
-                               if (($rr['network'] !== NETWORK_DIASPORA) && (in_array($rr['id'],$conversants))) {
-                                       logger('notifier: already delivered id=' . $rr['id']);
-                                       continue;
-                               }
-
-                               if ((! $mail) && (! $fsuggest) && (! $followup)) {
-                                       logger('notifier: delivery agent: '.$rr['name'].' '.$rr['id'].' '.$rr['network'].' '.$target_item["guid"]);
-                                       Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true),
-                                                       'delivery', $cmd, $item_id, (int)$rr['id']);
-                               }
-                       }
-               }
-
-               $push_notify = true;
-
-       }
-
-       // Notify PuSH subscribers (Used for OStatus distribution of regular posts)
-       if ($push_notify) {
-               // Set push flag for PuSH subscribers to this topic,
-               // they will be notified in queue.php
-               q("UPDATE `push_subscriber` SET `push` = 1 ".
-                 "WHERE `nickname` = '%s' AND `push` = 0", dbesc($owner['nickname']));
-
-               logger('Activating internal PuSH for item '.$item_id, LOGGER_DEBUG);
-
-               // Handling the pubsubhubbub requests
-               Worker::add(array('priority' => PRIORITY_HIGH, 'created' => $a->queue['created'], 'dont_fork' => true),
-                               'pubsubpublish');
-       }
-
-       logger('notifier: calling hooks', LOGGER_DEBUG);
-
-       if ($normal_mode) {
-               call_hooks('notifier_normal',$target_item);
-       }
-
-       call_hooks('notifier_end',$target_item);
-
-       return;
-}
diff --git a/include/profile_update.php b/include/profile_update.php
deleted file mode 100644 (file)
index 0c5de01..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<?php
-use Friendica\Protocol\Diaspora;
-
-function profile_update_run(&$argv, &$argc) {
-       if ($argc != 2) {
-               return;
-       }
-
-       $uid = intval($argv[1]);
-
-       Diaspora::send_profile($uid);
-}
diff --git a/include/pubsubpublish.php b/include/pubsubpublish.php
deleted file mode 100644 (file)
index 52a707b..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-<?php
-
-use Friendica\App;
-use Friendica\Core\System;
-use Friendica\Core\Config;
-use Friendica\Core\Worker;
-use Friendica\Database\DBM;
-
-require_once('include/items.php');
-require_once('include/ostatus.php');
-
-function pubsubpublish_run(&$argv, &$argc){
-       global $a;
-
-       if ($argc > 1) {
-               $pubsubpublish_id = intval($argv[1]);
-       } else {
-               // We'll push to each subscriber that has push > 0,
-               // i.e. there has been an update (set in notifier.php).
-               $r = q("SELECT `id`, `callback_url` FROM `push_subscriber` WHERE `push` > 0 ORDER BY `last_update` DESC");
-
-               foreach ($r as $rr) {
-                       logger("Publish feed to ".$rr["callback_url"], LOGGER_DEBUG);
-                       Worker::add(array('priority' => PRIORITY_HIGH, 'created' => $a->queue['created'], 'dont_fork' => true),
-                                       'pubsubpublish', (int)$rr["id"]);
-               }
-       }
-
-       handle_pubsubhubbub($pubsubpublish_id);
-
-       return;
-}
-
-function handle_pubsubhubbub($id) {
-       global $a;
-
-       $r = q("SELECT * FROM `push_subscriber` WHERE `id` = %d", intval($id));
-       if (!DBM::is_result($r)) {
-               return;
-       }
-
-       $rr = $r[0];
-
-       /// @todo Check server status with poco_check_server()
-       // Before this can be done we need a way to safely detect the server url.
-
-       logger("Generate feed of user ".$rr['nickname']." to ".$rr['callback_url']." - last updated ".$rr['last_update'], LOGGER_DEBUG);
-
-       $last_update = $rr['last_update'];
-       $params = ostatus::feed($a, $rr['nickname'], $last_update);
-
-       if (!$params) {
-               return;
-       }
-
-       $hmac_sig = hash_hmac("sha1", $params, $rr['secret']);
-
-       $headers = array("Content-type: application/atom+xml",
-                       sprintf("Link: <%s>;rel=hub,<%s>;rel=self",
-                               System::baseUrl().'/pubsubhubbub/'.$rr['nickname'],
-                               $rr['topic']),
-                       "X-Hub-Signature: sha1=".$hmac_sig);
-
-       logger('POST '.print_r($headers, true)."\n".$params, LOGGER_DEBUG);
-
-       post_url($rr['callback_url'], $params, $headers);
-       $ret = $a->get_curl_code();
-
-       if ($ret >= 200 && $ret <= 299) {
-               logger('successfully pushed to '.$rr['callback_url']);
-
-               // set last_update to the "created" date of the last item, and reset push=0
-               q("UPDATE `push_subscriber` SET `push` = 0, last_update = '%s' WHERE id = %d",
-                       dbesc($last_update),
-                       intval($rr['id']));
-
-       } else {
-               logger('error when pushing to '.$rr['callback_url'].' HTTP: '.$ret);
-
-               // we use the push variable also as a counter, if we failed we
-               // increment this until some upper limit where we give up
-               $new_push = intval($rr['push']) + 1;
-
-               if ($new_push > 30) // OK, let's give up
-                       $new_push = 0;
-
-               q("UPDATE `push_subscriber` SET `push` = %d WHERE id = %d",
-                       $new_push,
-                       intval($rr['id']));
-       }
-}
diff --git a/include/queue.php b/include/queue.php
deleted file mode 100644 (file)
index a56c41d..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-<?php
-/**
- * @file include/queue.php
- */
-use Friendica\Core\Cache;
-use Friendica\Core\Config;
-use Friendica\Core\Worker;
-use Friendica\Database\DBM;
-use Friendica\Protocol\Diaspora;
-use Friendica\Protocol\DFRN;
-
-require_once 'include/queue_fn.php';
-require_once 'include/datetime.php';
-require_once 'include/items.php';
-require_once 'include/bbcode.php';
-require_once 'include/socgraph.php';
-
-function queue_run(&$argv, &$argc)
-{
-       global $a;
-
-       if ($argc > 1) {
-               $queue_id = intval($argv[1]);
-       } else {
-               $queue_id = 0;
-       }
-
-       $cachekey_deadguy = 'queue_run:deadguy:';
-       $cachekey_server = 'queue_run:server:';
-
-       if (!$queue_id) {
-               logger('queue: start');
-
-               // Handling the pubsubhubbub requests
-               Worker::add(array('priority' => PRIORITY_HIGH, 'dont_fork' => true), 'pubsubpublish');
-
-               $r = q(
-                       "SELECT `queue`.*, `contact`.`name`, `contact`.`uid` FROM `queue`
-                       INNER JOIN `contact` ON `queue`.`cid` = `contact`.`id`
-                       WHERE `queue`.`created` < UTC_TIMESTAMP() - INTERVAL 3 DAY"
-               );
-
-               if (DBM::is_result($r)) {
-                       foreach ($r as $rr) {
-                               logger('Removing expired queue item for ' . $rr['name'] . ', uid=' . $rr['uid']);
-                               logger('Expired queue data: ' . $rr['content'], LOGGER_DATA);
-                       }
-                       q("DELETE FROM `queue` WHERE `created` < UTC_TIMESTAMP() - INTERVAL 3 DAY");
-               }
-
-               /*
-                * For the first 12 hours we'll try to deliver every 15 minutes
-                * After that, we'll only attempt delivery once per hour.
-                */
-               $r = q("SELECT `id` FROM `queue` WHERE ((`created` > UTC_TIMESTAMP() - INTERVAL 12 HOUR AND `last` < UTC_TIMESTAMP() - INTERVAL 15 MINUTE) OR (`last` < UTC_TIMESTAMP() - INTERVAL 1 HOUR)) ORDER BY `cid`, `created`");
-
-               call_hooks('queue_predeliver', $a, $r);
-
-               if (DBM::is_result($r)) {
-                       foreach ($r as $q_item) {
-                               logger('Call queue for id '.$q_item['id']);
-                               Worker::add(array('priority' => PRIORITY_LOW, 'dont_fork' => true), "queue", (int)$q_item['id']);
-                       }
-               }
-               return;
-       }
-
-
-       // delivering
-
-       require_once 'include/salmon.php';
-
-       $r = q(
-               "SELECT * FROM `queue` WHERE `id` = %d LIMIT 1",
-               intval($queue_id)
-       );
-
-       if (!DBM::is_result($r)) {
-               return;
-       }
-
-       $q_item = $r[0];
-
-       $c = q(
-               "SELECT * FROM `contact` WHERE `id` = %d LIMIT 1",
-               intval($q_item['cid'])
-       );
-
-       if (!DBM::is_result($c)) {
-               remove_queue_item($q_item['id']);
-               return;
-       }
-
-       $dead = Cache::get($cachekey_deadguy.$c[0]['notify']);
-
-       if (!is_null($dead) && $dead) {
-               logger('queue: skipping known dead url: '.$c[0]['notify']);
-               update_queue_time($q_item['id']);
-               return;
-       }
-
-       $server = poco_detect_server($c[0]['url']);
-
-       if ($server != "") {
-               $vital = Cache::get($cachekey_server.$server);
-
-               if (is_null($vital)) {
-                       logger("Check server ".$server." (".$c[0]["network"].")");
-
-                       $vital = poco_check_server($server, $c[0]["network"], true);
-                       Cache::set($cachekey_server.$server, $vital, CACHE_QUARTER_HOUR);
-               }
-
-               if (!is_null($vital) && !$vital) {
-                       logger('queue: skipping dead server: '.$server);
-                       update_queue_time($q_item['id']);
-                       return;
-               }
-       }
-
-       $u = q(
-               "SELECT `user`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`
-               FROM `user` WHERE `uid` = %d LIMIT 1",
-               intval($c[0]['uid'])
-       );
-       if (!DBM::is_result($u)) {
-               remove_queue_item($q_item['id']);
-               return;
-       }
-
-       $data      = $q_item['content'];
-       $public    = $q_item['batch'];
-       $contact   = $c[0];
-       $owner     = $u[0];
-
-       $deliver_status = 0;
-
-       switch ($contact['network']) {
-               case NETWORK_DFRN:
-                       logger('queue: dfrndelivery: item '.$q_item['id'].' for '.$contact['name'].' <'.$contact['url'].'>');
-                       $deliver_status = DFRN::deliver($owner, $contact, $data);
-
-                       if ($deliver_status == (-1)) {
-                               update_queue_time($q_item['id']);
-                               Cache::set($cachekey_deadguy.$contact['notify'], true, CACHE_QUARTER_HOUR);
-                       } else {
-                               remove_queue_item($q_item['id']);
-                       }
-                       break;
-               case NETWORK_OSTATUS:
-                       if ($contact['notify']) {
-                               logger('queue: slapdelivery: item '.$q_item['id'].' for '.$contact['name'].' <'.$contact['url'].'>');
-                               $deliver_status = slapper($owner, $contact['notify'], $data);
-
-                               if ($deliver_status == (-1)) {
-                                       update_queue_time($q_item['id']);
-                                       Cache::set($cachekey_deadguy.$contact['notify'], true, CACHE_QUARTER_HOUR);
-                               } else {
-                                       remove_queue_item($q_item['id']);
-                               }
-                       }
-                       break;
-               case NETWORK_DIASPORA:
-                       if ($contact['notify']) {
-                               logger('queue: diaspora_delivery: item '.$q_item['id'].' for '.$contact['name'].' <'.$contact['url'].'>');
-                               $deliver_status = Diaspora::transmit($owner, $contact, $data, $public, true);
-
-                               if ($deliver_status == (-1)) {
-                                       update_queue_time($q_item['id']);
-                                       Cache::set($cachekey_deadguy.$contact['notify'], true, CACHE_QUARTER_HOUR);
-                               } else {
-                                       remove_queue_item($q_item['id']);
-                               }
-                       }
-                       break;
-
-               default:
-                       $params = array('owner' => $owner, 'contact' => $contact, 'queue' => $q_item, 'result' => false);
-                       call_hooks('queue_deliver', $a, $params);
-
-                       if ($params['result']) {
-                               remove_queue_item($q_item['id']);
-                       } else {
-                               update_queue_time($q_item['id']);
-                       }
-                       break;
-       }
-       logger('Deliver status '.(int)$deliver_status.' for item '.$q_item['id'].' to '.$contact['name'].' <'.$contact['url'].'>');
-
-       return;
-}
diff --git a/include/remove_contact.php b/include/remove_contact.php
deleted file mode 100644 (file)
index 9d4b1e4..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-/**
- * @file include/remove_contact.php
- * @brief Removes orphaned data from deleted contacts
- */
-
-use Friendica\Core\Config;
-
-function remove_contact_run($argv, $argc) {
-       if ($argc != 2) {
-               return;
-       }
-
-       $id = intval($argv[1]);
-
-       // Only delete if the contact doesn't exist (anymore)
-       $r = dba::exists('contact', array('id' => $id));
-       if ($r) {
-               return;
-       }
-
-       // Now we delete all the depending table entries
-       dba::delete('contact', array('id' => $id));
-}
diff --git a/include/shadowupdate.php b/include/shadowupdate.php
deleted file mode 100644 (file)
index c41b231..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-<?php
-
-use Friendica\App;
-use Friendica\Core\Config;
-
-require_once("boot.php");
-require_once("include/threads.php");
-
-function shadowupdate_run(&$argv, &$argc){
-       global $a;
-
-       if (empty($a)) {
-               $a = new App(dirname(__DIR__));
-       }
-
-       @include(".htconfig.php");
-       require_once("include/dba.php");
-       dba::connect($db_host, $db_user, $db_pass, $db_data);
-       unset($db_host, $db_user, $db_pass, $db_data);
-
-       Config::load();
-
-       update_shadow_copy();
-}
-
-if (array_search(__file__,get_included_files())===0){
-       shadowupdate_run($_SERVER["argv"],$_SERVER["argc"]);
-       killme();
-}
diff --git a/include/spool_post.php b/include/spool_post.php
deleted file mode 100644 (file)
index b7b8de3..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-/**
- * @file include/spool_post.php
- * @brief Posts items that wer spooled because they couldn't be posted.
- */
-
-use Friendica\Core\Config;
-
-require_once("include/items.php");
-
-function spool_post_run($argv, $argc) {
-       global $a;
-
-       $path = get_spoolpath();
-
-       if (($path != '') && is_writable($path)){
-               if ($dh = opendir($path)) {
-                       while (($file = readdir($dh)) !== false) {
-
-                               // It is not named like a spool file, so we don't care.
-                               if (substr($file, 0, 5) != "item-") {
-                                       continue;
-                               }
-
-                               $fullfile = $path."/".$file;
-
-                               // We don't care about directories either
-                               if (filetype($fullfile) != "file") {
-                                       continue;
-                               }
-
-                               // We can't read or write the file? So we don't care about it.
-                               if (!is_writable($fullfile) || !is_readable($fullfile)) {
-                                       continue;
-                               }
-
-                               $arr = json_decode(file_get_contents($fullfile), true);
-
-                               // If it isn't an array then it is no spool file
-                               if (!is_array($arr)) {
-                                       continue;
-                               }
-
-                               // Skip if it doesn't seem to be an item array
-                               if (!isset($arr['uid']) && !isset($arr['uri']) && !isset($arr['network'])) {
-                                       continue;
-                               }
-
-                               $result = item_store($arr);
-
-                               logger("Spool file ".$file." stored: ".$result, LOGGER_DEBUG);
-                               unlink($fullfile);
-                       }
-                       closedir($dh);
-               }
-       }
-}
diff --git a/include/tagupdate.php b/include/tagupdate.php
deleted file mode 100644 (file)
index 1e97135..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<?php
-require_once("include/tags.php");
-
-function tagupdate_run(&$argv, &$argc){
-       update_items();
-}
diff --git a/include/threadupdate.php b/include/threadupdate.php
deleted file mode 100644 (file)
index 3a40286..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?php
-require_once("include/threads.php");
-
-function threadupdate_run(&$argv, &$argc){
-       update_threads();
-       update_threads_mention();
-}
diff --git a/include/update_gcontact.php b/include/update_gcontact.php
deleted file mode 100644 (file)
index cd7a936..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-
-use Friendica\Core\Config;
-use Friendica\Network\Probe;
-use Friendica\Database\DBM;
-
-function update_gcontact_run(&$argv, &$argc) {
-       global $a;
-
-       require_once 'include/socgraph.php';
-
-       logger('update_gcontact: start');
-
-       if (($argc > 1) && (intval($argv[1]))) {
-               $contact_id = intval($argv[1]);
-       }
-
-       if (!$contact_id) {
-               logger('update_gcontact: no contact');
-               return;
-       }
-
-       $r = q("SELECT * FROM `gcontact` WHERE `id` = %d", intval($contact_id));
-
-       if (!DBM::is_result($r)) {
-               return;
-       }
-
-       if (!in_array($r[0]["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS))) {
-               return;
-       }
-
-       $data = Probe::uri($r[0]["url"]);
-
-       if (!in_array($data["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS))) {
-               if ($r[0]["server_url"] != "")
-                       poco_check_server($r[0]["server_url"], $r[0]["network"]);
-
-               q("UPDATE `gcontact` SET `last_failure` = '%s' WHERE `id` = %d",
-                       dbesc(datetime_convert()), intval($contact_id));
-               return;
-       }
-
-       if (($data["name"] == "") && ($r[0]['name'] != ""))
-               $data["name"] = $r[0]['name'];
-
-       if (($data["nick"] == "") && ($r[0]['nick'] != ""))
-               $data["nick"] = $r[0]['nick'];
-
-       if (($data["addr"] == "") && ($r[0]['addr'] != ""))
-               $data["addr"] = $r[0]['addr'];
-
-       if (($data["photo"] == "") && ($r[0]['photo'] != ""))
-               $data["photo"] = $r[0]['photo'];
-
-
-       q("UPDATE `gcontact` SET `name` = '%s', `nick` = '%s', `addr` = '%s', `photo` = '%s'
-                               WHERE `id` = %d",
-                               dbesc($data["name"]),
-                               dbesc($data["nick"]),
-                               dbesc($data["addr"]),
-                               dbesc($data["photo"]),
-                               intval($contact_id)
-                       );
-
-       q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `addr` = '%s', `photo` = '%s'
-                               WHERE `uid` = 0 AND `addr` = '' AND `nurl` = '%s'",
-                               dbesc($data["name"]),
-                               dbesc($data["nick"]),
-                               dbesc($data["addr"]),
-                               dbesc($data["photo"]),
-                               dbesc(normalise_link($data["url"]))
-                       );
-
-       q("UPDATE `contact` SET `addr` = '%s'
-                               WHERE `uid` != 0 AND `addr` = '' AND `nurl` = '%s'",
-                               dbesc($data["addr"]),
-                               dbesc(normalise_link($data["url"]))
-                       );
-}
index ffc6b29db207279b9d0a7b33ab604df78cef6ade..db93adddaa79deba57710618b98d03893fb853e4 100644 (file)
@@ -241,7 +241,7 @@ class Worker {
 
                // The script could be provided as full path or only with the function name
                if ($include == basename($include)) {
-                       $include = "include/".$include.".php";
+                       $include = "worker/".$include.".php";
                }
 
                if (!validate_include($include)) {
@@ -902,7 +902,7 @@ class Worker {
                self::add(PRIORITY_HIGH, "spool_post");
 
                // Run the cron job that calls all other jobs
-               self::add(PRIORITY_MEDIUM, "cron");
+               self::add(PRIORITY_MEDIUM, "Cron");
 
                // Run the cronhooks job separately from cron for being able to use a different timing
                self::add(PRIORITY_MEDIUM, "CronHooks");
diff --git a/src/Worker/Cron.php b/src/Worker/Cron.php
new file mode 100644 (file)
index 0000000..c859824
--- /dev/null
@@ -0,0 +1,263 @@
+<?php
+namespace Friendica\Worker;
+
+use Friendica\Core\Config;
+use Friendica\Core\Worker;
+use Friendica\Database\DBM;
+
+Class Cron {
+       public static function execute($parameter = '', $generation = 0) {
+               global $a;
+
+               require_once 'include/datetime.php';
+
+               // Poll contacts with specific parameters
+               if (!empty($parameter)) {
+                       self::pollContacts($parameter, $generation);
+                       return;
+               }
+
+               $last = Config::get('system', 'last_cron');
+
+               $poll_interval = intval(Config::get('system', 'cron_interval'));
+               if (! $poll_interval) {
+                       $poll_interval = 10;
+               }
+
+               if ($last) {
+                       $next = $last + ($poll_interval * 60);
+                       if ($next > time()) {
+                               logger('cron intervall not reached');
+                               return;
+                       }
+               }
+
+               logger('cron: start');
+
+               // run queue delivery process in the background
+               Worker::add(PRIORITY_NEGLIGIBLE, "queue");
+
+               // run the process to discover global contacts in the background
+               Worker::add(PRIORITY_LOW, "discover_poco");
+
+               // run the process to update locally stored global contacts in the background
+               Worker::add(PRIORITY_LOW, "discover_poco", "checkcontact");
+
+               // Expire and remove user entries
+               Worker::add(PRIORITY_MEDIUM, "cronjobs", "expire_and_remove_users");
+
+               // Call possible post update functions
+               Worker::add(PRIORITY_LOW, "cronjobs", "post_update");
+
+               // update nodeinfo data
+               Worker::add(PRIORITY_LOW, "cronjobs", "nodeinfo");
+
+               // Clear cache entries
+               Worker::add(PRIORITY_LOW, "cronjobs", "clear_cache");
+
+               // Repair missing Diaspora values in contacts
+               Worker::add(PRIORITY_LOW, "cronjobs", "repair_diaspora");
+
+               // Repair entries in the database
+               Worker::add(PRIORITY_LOW, "cronjobs", "repair_database");
+
+               // once daily run birthday_updates and then expire in background
+               $d1 = Config::get('system', 'last_expire_day');
+               $d2 = intval(datetime_convert('UTC', 'UTC', 'now', 'd'));
+
+               if ($d2 != intval($d1)) {
+
+                       Worker::add(PRIORITY_LOW, "cronjobs", "update_contact_birthdays");
+
+                       Worker::add(PRIORITY_LOW, "discover_poco", "update_server");
+
+                       Worker::add(PRIORITY_LOW, "discover_poco", "suggestions");
+
+                       Config::set('system', 'last_expire_day', $d2);
+
+                       Worker::add(PRIORITY_LOW, 'expire');
+
+                       Worker::add(PRIORITY_MEDIUM, 'dbclean');
+
+                       Worker::add(PRIORITY_LOW, "cronjobs", "update_photo_albums");
+
+                       // Delete all done workerqueue entries
+                       dba::delete('workerqueue', array('`done` AND `executed` < UTC_TIMESTAMP() - INTERVAL 12 HOUR'));
+
+                       // check upstream version?
+                       Worker::add(PRIORITY_LOW, 'checkversion');
+               }
+
+               // Poll contacts
+               self::pollContacts($parameter, $generation);
+
+               logger('cron: end');
+
+               Config::set('system', 'last_cron', time());
+
+               return;
+       }
+
+       /**
+        * @brief Poll contacts for unreceived messages
+        *
+        * @todo Currently it seems as if the following parameter aren't used at all ...
+        *
+        * @param string $parameter Parameter (force, restart, ...) for the contact polling
+        * @param integer $generation
+        */
+       private static function pollContacts($parameter, $generation) {
+               $manual_id  = 0;
+               $generation = 0;
+               $force      = false;
+               $restart    = false;
+
+               if ($parameter == 'force') {
+                       $force = true;
+               }
+               if ($parameter == 'restart') {
+                       $restart = true;
+                       $generation = intval($generation);
+                       if (!$generation) {
+                               killme();
+                       }
+               }
+
+               if (intval($parameter)) {
+                       $manual_id = intval($parameter);
+                       $force     = true;
+               }
+
+               $min_poll_interval = Config::get('system', 'min_poll_interval', 1);
+
+               $sql_extra = (($manual_id) ? " AND `id` = $manual_id " : "");
+
+               reload_plugins();
+
+               $d = datetime_convert();
+
+               // Only poll from those with suitable relationships,
+               // and which have a polling address and ignore Diaspora since
+               // we are unable to match those posts with a Diaspora GUID and prevent duplicates.
+
+               $abandon_days = intval(Config::get('system', 'account_abandon_days'));
+               if ($abandon_days < 1) {
+                       $abandon_days = 0;
+               }
+               $abandon_sql = (($abandon_days)
+                       ? sprintf(" AND `user`.`login_date` > UTC_TIMESTAMP() - INTERVAL %d DAY ", intval($abandon_days))
+                       : ''
+               );
+
+               $contacts = q("SELECT `contact`.`id` FROM `user`
+                               STRAIGHT_JOIN `contact`
+                               ON `contact`.`uid` = `user`.`uid` AND `contact`.`rel` IN (%d, %d) AND `contact`.`poll` != ''
+                                       AND `contact`.`network` IN ('%s', '%s', '%s', '%s', '%s', '%s') $sql_extra
+                                       AND NOT `contact`.`self` AND NOT `contact`.`blocked` AND NOT `contact`.`readonly`
+                                       AND NOT `contact`.`archive`
+                               WHERE NOT `user`.`account_expired` AND NOT `user`.`account_removed` $abandon_sql ORDER BY RAND()",
+                       intval(CONTACT_IS_SHARING),
+                       intval(CONTACT_IS_FRIEND),
+                       dbesc(NETWORK_DFRN),
+                       dbesc(NETWORK_ZOT),
+                       dbesc(NETWORK_OSTATUS),
+                       dbesc(NETWORK_FEED),
+                       dbesc(NETWORK_MAIL),
+                       dbesc(NETWORK_MAIL2)
+               );
+
+               if (!DBM::is_result($contacts)) {
+                       return;
+               }
+
+               foreach ($contacts as $c) {
+
+                       $res = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1",
+                               intval($c['id'])
+                       );
+
+                       if (!DBM::is_result($res)) {
+                               continue;
+                       }
+
+                       foreach ($res as $contact) {
+
+                               $xml = false;
+
+                               if ($manual_id) {
+                                       $contact['last-update'] = NULL_DATE;
+                               }
+
+                               if (in_array($contact['network'], array(NETWORK_DFRN, NETWORK_ZOT, NETWORK_OSTATUS))) {
+                                       $contact['priority'] = 2;
+                               }
+
+                               if ($contact['subhub'] && in_array($contact['network'], array(NETWORK_DFRN, NETWORK_ZOT, NETWORK_OSTATUS))) {
+                                       /*
+                                        * We should be getting everything via a hub. But just to be sure, let's check once a day.
+                                        * (You can make this more or less frequent if desired by setting 'pushpoll_frequency' appropriately)
+                                        * This also lets us update our subscription to the hub, and add or replace hubs in case it
+                                        * changed. We will only update hubs once a day, regardless of 'pushpoll_frequency'.
+                                        */
+                                       $poll_interval = Config::get('system', 'pushpoll_frequency');
+                                       $contact['priority'] = (($poll_interval !== false) ? intval($poll_interval) : 3);
+                               }
+
+                               if (($contact['priority'] >= 0) && !$force) {
+                                       $update = false;
+
+                                       $t = $contact['last-update'];
+
+                                       /*
+                                        * Based on $contact['priority'], should we poll this site now? Or later?
+                                        */
+                                       switch ($contact['priority']) {
+                                               case 5:
+                                                       if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 month")) {
+                                                               $update = true;
+                                                       }
+                                                       break;
+                                               case 4:
+                                                       if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 week")) {
+                                                               $update = true;
+                                                       }
+                                                       break;
+                                               case 3:
+                                                       if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 day")) {
+                                                               $update = true;
+                                                       }
+                                                       break;
+                                               case 2:
+                                                       if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 12 hour")) {
+                                                               $update = true;
+                                                       }
+                                                       break;
+                                               case 1:
+                                                       if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 hour")) {
+                                                               $update = true;
+                                                       }
+                                                       break;
+                                               case 0:
+                                               default:
+                                                       if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + ".$min_poll_interval." minute")) {
+                                                               $update = true;
+                                                       }
+                                                       break;
+                                       }
+                                       if (!$update) {
+                                               continue;
+                                       }
+                               }
+
+                               logger("Polling " . $contact["network"] . " " . $contact["id"] . " " . $contact["nick"] . " " . $contact["name"]);
+
+                               if (($contact['network'] == NETWORK_FEED) && ($contact['priority'] <= 3)) {
+                                       $priority = PRIORITY_MEDIUM;
+                               } else {
+                                       $priority = PRIORITY_LOW;
+                               }
+                               Worker::add(array('priority' => $priority, 'dont_fork' => true), 'OnePoll', (int)$contact['id']);
+                       }
+               }
+       }
+}
diff --git a/worker/checkversion.php b/worker/checkversion.php
new file mode 100644 (file)
index 0000000..7d3c2de
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * @file include/checkversion.php
+ *
+ * @brief save Friendica upstream version to the DB
+ **/
+
+use Friendica\Core\Config;
+
+/**
+ * @brief check the git repository VERSION file and save the version to the DB
+ *
+ * Checking the upstream version is optional (opt-in) and can be done to either
+ * the master or the develop branch in the repository.
+ */
+function checkversion_run () {
+       global $a;
+
+       logger('checkversion: start');
+
+       $checkurl = Config::get('system', 'check_new_version_url', 'none');
+
+       switch ($checkurl) {
+       case 'master': 
+               $checked_url = 'https://raw.githubusercontent.com/friendica/friendica/master/VERSION'; 
+               break;
+       case 'develop': 
+               $checked_url = 'https://raw.githubusercontent.com/friendica/friendica/develop/VERSION'; 
+               break;
+       default: 
+               // don't check
+               return;
+}
+       logger("Checking VERSION from: ".$checked_url, LOGGER_DEBUG);
+
+       // fetch the VERSION file
+       $gitversion = dbesc(trim(fetch_url($checked_url)));
+       logger("Upstream VERSION is: ".$gitversion, LOGGER_DEBUG);
+
+       Config::set('system', 'git_friendica_version', $gitversion);
+
+       logger('checkversion: end');
+
+       return;
+}
diff --git a/worker/create_shadowentry.php b/worker/create_shadowentry.php
new file mode 100644 (file)
index 0000000..29222de
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+/**
+ * @file include/create_shadowentry.php
+ * @brief This script creates posts with UID = 0 for a given public post.
+ *
+ * This script is started from mod/item.php to save some time when doing a post.
+ */
+
+require_once("include/threads.php");
+
+function create_shadowentry_run($argv, $argc) {
+       if ($argc != 2) {
+               return;
+       }
+
+       $message_id = intval($argv[1]);
+
+       add_shadow_entry($message_id);
+}
diff --git a/worker/cronjobs.php b/worker/cronjobs.php
new file mode 100644 (file)
index 0000000..00064b1
--- /dev/null
@@ -0,0 +1,278 @@
+<?php
+
+use Friendica\App;
+use Friendica\Core\Cache;
+use Friendica\Core\Config;
+use Friendica\Database\DBM;
+use Friendica\Network\Probe;
+
+function cronjobs_run(&$argv, &$argc){
+       global $a;
+
+       require_once 'include/datetime.php';
+       require_once 'include/post_update.php';
+       require_once 'mod/nodeinfo.php';
+       require_once 'include/photos.php';
+       require_once 'include/user.php';
+       require_once 'include/socgraph.php';
+
+       // No parameter set? So return
+       if ($argc <= 1) {
+               return;
+       }
+
+       logger("Starting cronjob ".$argv[1], LOGGER_DEBUG);
+
+       // Call possible post update functions
+       // see include/post_update.php for more details
+       if ($argv[1] == 'post_update') {
+               post_update();
+               return;
+       }
+
+       // update nodeinfo data
+       if ($argv[1] == 'nodeinfo') {
+               nodeinfo_cron();
+               return;
+       }
+
+       // Expire and remove user entries
+       if ($argv[1] == 'expire_and_remove_users') {
+               cron_expire_and_remove_users();
+               return;
+       }
+
+       if ($argv[1] == 'update_contact_birthdays') {
+               update_contact_birthdays();
+               return;
+       }
+
+       if ($argv[1] == 'update_photo_albums') {
+               cron_update_photo_albums();
+               return;
+       }
+
+       // Clear cache entries
+       if ($argv[1] == 'clear_cache') {
+               cron_clear_cache($a);
+               return;
+       }
+
+       // Repair missing Diaspora values in contacts
+       if ($argv[1] == 'repair_diaspora') {
+               cron_repair_diaspora($a);
+               return;
+       }
+
+       // Repair entries in the database
+       if ($argv[1] == 'repair_database') {
+               cron_repair_database();
+               return;
+       }
+
+       logger("Xronjob ".$argv[1]." is unknown.", LOGGER_DEBUG);
+
+       return;
+}
+
+/**
+ * @brief Update the cached values for the number of photo albums per user
+ */
+function cron_update_photo_albums() {
+       $r = q("SELECT `uid` FROM `user` WHERE NOT `account_expired` AND NOT `account_removed`");
+       if (!DBM::is_result($r)) {
+               return;
+       }
+
+       foreach ($r AS $user) {
+               photo_albums($user['uid'], true);
+       }
+}
+
+/**
+ * @brief Expire and remove user entries
+ */
+function cron_expire_and_remove_users() {
+       // expire any expired accounts
+       q("UPDATE user SET `account_expired` = 1 where `account_expired` = 0
+               AND `account_expires_on` > '%s'
+               AND `account_expires_on` < UTC_TIMESTAMP()", dbesc(NULL_DATE));
+
+       // delete user records for recently removed accounts
+       $r = q("SELECT * FROM `user` WHERE `account_removed` AND `account_expires_on` < UTC_TIMESTAMP() - INTERVAL 3 DAY");
+       if (DBM::is_result($r)) {
+               foreach ($r as $user) {
+                       dba::delete('user', array('uid' => $user['uid']));
+               }
+       }
+}
+
+/**
+ * @brief Clear cache entries
+ *
+ * @param App $a
+ */
+function cron_clear_cache(App $a) {
+
+       $last = Config::get('system','cache_last_cleared');
+
+       if ($last) {
+               $next = $last + (3600); // Once per hour
+               $clear_cache = ($next <= time());
+       } else {
+               $clear_cache = true;
+       }
+
+       if (!$clear_cache) {
+               return;
+       }
+
+       // clear old cache
+       Cache::clear();
+
+       // clear old item cache files
+       clear_cache();
+
+       // clear cache for photos
+       clear_cache($a->get_basepath(), $a->get_basepath()."/photo");
+
+       // clear smarty cache
+       clear_cache($a->get_basepath()."/view/smarty3/compiled", $a->get_basepath()."/view/smarty3/compiled");
+
+       // clear cache for image proxy
+       if (!Config::get("system", "proxy_disabled")) {
+               clear_cache($a->get_basepath(), $a->get_basepath()."/proxy");
+
+               $cachetime = Config::get('system','proxy_cache_time');
+               if (!$cachetime) {
+                       $cachetime = PROXY_DEFAULT_TIME;
+               }
+               q('DELETE FROM `photo` WHERE `uid` = 0 AND `resource-id` LIKE "pic:%%" AND `created` < NOW() - INTERVAL %d SECOND', $cachetime);
+       }
+
+       // Delete the cached OEmbed entries that are older than one year
+       q("DELETE FROM `oembed` WHERE `created` < NOW() - INTERVAL 3 MONTH");
+
+       // Delete the cached "parse_url" entries that are older than one year
+       q("DELETE FROM `parsed_url` WHERE `created` < NOW() - INTERVAL 3 MONTH");
+
+       // Maximum table size in megabyte
+       $max_tablesize = intval(Config::get('system','optimize_max_tablesize')) * 1000000;
+       if ($max_tablesize == 0) {
+               $max_tablesize = 100 * 1000000; // Default are 100 MB
+       }
+       if ($max_tablesize > 0) {
+               // Minimum fragmentation level in percent
+               $fragmentation_level = intval(Config::get('system','optimize_fragmentation')) / 100;
+               if ($fragmentation_level == 0) {
+                       $fragmentation_level = 0.3; // Default value is 30%
+               }
+
+               // Optimize some tables that need to be optimized
+               $r = q("SHOW TABLE STATUS");
+               foreach ($r as $table) {
+
+                       // Don't optimize tables that are too large
+                       if ($table["Data_length"] > $max_tablesize) {
+                               continue;
+                       }
+
+                       // Don't optimize empty tables
+                       if ($table["Data_length"] == 0) {
+                               continue;
+                       }
+
+                       // Calculate fragmentation
+                       $fragmentation = $table["Data_free"] / ($table["Data_length"] + $table["Index_length"]);
+
+                       logger("Table ".$table["Name"]." - Fragmentation level: ".round($fragmentation * 100, 2), LOGGER_DEBUG);
+
+                       // Don't optimize tables that needn't to be optimized
+                       if ($fragmentation < $fragmentation_level) {
+                               continue;
+                       }
+
+                       // So optimize it
+                       logger("Optimize Table ".$table["Name"], LOGGER_DEBUG);
+                       q("OPTIMIZE TABLE `%s`", dbesc($table["Name"]));
+               }
+       }
+
+       Config::set('system','cache_last_cleared', time());
+}
+
+/**
+ * @brief Repair missing values in Diaspora contacts
+ *
+ * @param App $a
+ */
+function cron_repair_diaspora(App $a) {
+
+        $starttime = time();
+
+       $r = q("SELECT `id`, `url` FROM `contact`
+               WHERE `network` = '%s' AND (`batch` = '' OR `notify` = '' OR `poll` = '' OR pubkey = '')
+                       ORDER BY RAND() LIMIT 50", dbesc(NETWORK_DIASPORA));
+       if (!DBM::is_result($r)) {
+               return;
+       }
+
+       foreach ($r AS $contact) {
+               // Quit the loop after 3 minutes
+               if (time() > ($starttime + 180)) {
+                       return;
+               }
+
+               if (!poco_reachable($contact["url"])) {
+                       continue;
+               }
+
+               $data = Probe::uri($contact["url"]);
+               if ($data["network"] != NETWORK_DIASPORA) {
+                       continue;
+               }
+
+               logger("Repair contact ".$contact["id"]." ".$contact["url"], LOGGER_DEBUG);
+               q("UPDATE `contact` SET `batch` = '%s', `notify` = '%s', `poll` = '%s', pubkey = '%s' WHERE `id` = %d",
+                       dbesc($data["batch"]), dbesc($data["notify"]), dbesc($data["poll"]), dbesc($data["pubkey"]),
+                       intval($contact["id"]));
+       }
+}
+
+/**
+ * @brief Do some repairs in database entries
+ *
+ */
+function cron_repair_database() {
+
+       // Sometimes there seem to be issues where the "self" contact vanishes.
+       // We haven't found the origin of the problem by now.
+       $r = q("SELECT `uid` FROM `user` WHERE NOT EXISTS (SELECT `uid` FROM `contact` WHERE `contact`.`uid` = `user`.`uid` AND `contact`.`self`)");
+       if (DBM::is_result($r)) {
+               foreach ($r AS $user) {
+                       logger('Create missing self contact for user '.$user['uid']);
+                       user_create_self_contact($user['uid']);
+               }
+       }
+
+       // Set the parent if it wasn't set. (Shouldn't happen - but does sometimes)
+       // This call is very "cheap" so we can do it at any time without a problem
+       q("UPDATE `item` INNER JOIN `item` AS `parent` ON `parent`.`uri` = `item`.`parent-uri` AND `parent`.`uid` = `item`.`uid` SET `item`.`parent` = `parent`.`id` WHERE `item`.`parent` = 0");
+
+       // There was an issue where the nick vanishes from the contact table
+       q("UPDATE `contact` INNER JOIN `user` ON `contact`.`uid` = `user`.`uid` SET `nick` = `nickname` WHERE `self` AND `nick`=''");
+
+       // Update the global contacts for local users
+       $r = q("SELECT `uid` FROM `user` WHERE `verified` AND NOT `blocked` AND NOT `account_removed` AND NOT `account_expired`");
+       if (DBM::is_result($r)) {
+               foreach ($r AS $user) {
+                       update_gcontact_for_user($user["uid"]);
+               }
+       }
+
+       /// @todo
+       /// - remove thread entries without item
+       /// - remove sign entries without item
+       /// - remove children when parent got lost
+       /// - set contact-id in item when not present
+}
diff --git a/worker/dbclean.php b/worker/dbclean.php
new file mode 100644 (file)
index 0000000..1e1dd90
--- /dev/null
@@ -0,0 +1,303 @@
+<?php
+/**
+ * @file include/dbclean.php
+ * @brief The script is called from time to time to clean the database entries and remove orphaned data.
+ */
+
+use Friendica\Core\Config;
+use Friendica\Core\Worker;
+
+function dbclean_run(&$argv, &$argc) {
+       if (!Config::get('system', 'dbclean', false)) {
+               return;
+       }
+
+       if ($argc == 2) {
+               $stage = intval($argv[1]);
+       } else {
+               $stage = 0;
+       }
+
+       // Get the expire days for step 8 and 9
+       $days = Config::get('system', 'dbclean-expire-days', 0);
+
+       if ($stage == 0) {
+               for ($i = 1; $i <= 9; $i++) {
+                       // Execute the background script for a step when it isn't finished.
+                       // Execute step 8 and 9 only when $days is defined.
+                       if (!Config::get('system', 'finished-dbclean-'.$i, false) && (($i < 8) || ($days > 0))) {
+                               Worker::add(PRIORITY_LOW, 'dbclean', $i);
+                       }
+               }
+       } else {
+               remove_orphans($stage);
+       }
+}
+
+/**
+ * @brief Remove orphaned database entries
+ * @param integer $stage What should be deleted?
+ *
+ * Values for $stage:
+ * ------------------
+ * 1:  Old global item entries from item table without user copy.
+ * 2:  Items without parents.
+ * 3:  Orphaned data from thread table.
+ * 4:  Orphaned data from notify table.
+ * 5:  Orphaned data from notify-threads table.
+ * 6:  Orphaned data from sign table.
+ * 7:  Orphaned data from term table.
+ * 8:  Expired threads.
+ * 9:  Old global item entries from expired threads
+ */
+function remove_orphans($stage = 0) {
+       global $db;
+
+       $count = 0;
+
+       // We split the deletion in many small tasks
+       $limit = 1000;
+
+       // Get the expire days for step 8 and 9
+       $days = Config::get('system', 'dbclean-expire-days', 0);
+
+       if ($stage == 1) {
+               $last_id = Config::get('system', 'dbclean-last-id-1', 0);
+
+               logger("Deleting old global item entries from item table without user copy. Last ID: ".$last_id);
+               $r = dba::p("SELECT `id` FROM `item` WHERE `uid` = 0 AND
+                                       NOT EXISTS (SELECT `guid` FROM `item` AS `i` WHERE `item`.`guid` = `i`.`guid` AND `i`.`uid` != 0) AND
+                                       `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY AND `id` >= ?
+                               ORDER BY `id` LIMIT ".intval($limit), $last_id);
+               $count = dba::num_rows($r);
+               if ($count > 0) {
+                       logger("found global item orphans: ".$count);
+                       while ($orphan = dba::fetch($r)) {
+                               $last_id = $orphan["id"];
+                               dba::delete('item', array('id' => $orphan["id"]));
+                       }
+               } else {
+                       logger("No global item orphans found");
+               }
+               dba::close($r);
+               logger("Done deleting ".$count." old global item entries from item table without user copy. Last ID: ".$last_id);
+
+               Config::set('system', 'dbclean-last-id-1', $last_id);
+       } elseif ($stage == 2) {
+               $last_id = Config::get('system', 'dbclean-last-id-2', 0);
+
+               logger("Deleting items without parents. Last ID: ".$last_id);
+               $r = dba::p("SELECT `id` FROM `item`
+                               WHERE NOT EXISTS (SELECT `id` FROM `item` AS `i` WHERE `item`.`parent` = `i`.`id`)
+                               AND `id` >= ? ORDER BY `id` LIMIT ".intval($limit), $last_id);
+               $count = dba::num_rows($r);
+               if ($count > 0) {
+                       logger("found item orphans without parents: ".$count);
+                       while ($orphan = dba::fetch($r)) {
+                               $last_id = $orphan["id"];
+                               dba::delete('item', array('id' => $orphan["id"]));
+                       }
+               } else {
+                       logger("No item orphans without parents found");
+               }
+               dba::close($r);
+               logger("Done deleting ".$count." items without parents. Last ID: ".$last_id);
+
+               Config::set('system', 'dbclean-last-id-2', $last_id);
+
+               if ($count < $limit) {
+                       Config::set('system', 'finished-dbclean-2', true);
+               }
+       } elseif ($stage == 3) {
+               $last_id = Config::get('system', 'dbclean-last-id-3', 0);
+
+               logger("Deleting orphaned data from thread table. Last ID: ".$last_id);
+               $r = dba::p("SELECT `iid` FROM `thread`
+                               WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `thread`.`iid`) AND `iid` >= ?
+                               ORDER BY `iid` LIMIT ".intval($limit), $last_id);
+               $count = dba::num_rows($r);
+               if ($count > 0) {
+                       logger("found thread orphans: ".$count);
+                       while ($orphan = dba::fetch($r)) {
+                               $last_id = $orphan["iid"];
+                               dba::delete('thread', array('iid' => $orphan["iid"]));
+                       }
+               } else {
+                       logger("No thread orphans found");
+               }
+               dba::close($r);
+               logger("Done deleting ".$count." orphaned data from thread table. Last ID: ".$last_id);
+
+               Config::set('system', 'dbclean-last-id-3', $last_id);
+
+               if ($count < $limit) {
+                       Config::set('system', 'finished-dbclean-3', true);
+               }
+       } elseif ($stage == 4) {
+               $last_id = Config::get('system', 'dbclean-last-id-4', 0);
+
+               logger("Deleting orphaned data from notify table. Last ID: ".$last_id);
+               $r = dba::p("SELECT `iid`, `id` FROM `notify`
+                               WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `notify`.`iid`) AND `id` >= ?
+                               ORDER BY `id` LIMIT ".intval($limit), $last_id);
+               $count = dba::num_rows($r);
+               if ($count > 0) {
+                       logger("found notify orphans: ".$count);
+                       while ($orphan = dba::fetch($r)) {
+                               $last_id = $orphan["id"];
+                               dba::delete('notify', array('iid' => $orphan["iid"]));
+                       }
+               } else {
+                       logger("No notify orphans found");
+               }
+               dba::close($r);
+               logger("Done deleting ".$count." orphaned data from notify table. Last ID: ".$last_id);
+
+               Config::set('system', 'dbclean-last-id-4', $last_id);
+
+               if ($count < $limit) {
+                       Config::set('system', 'finished-dbclean-4', true);
+               }
+       } elseif ($stage == 5) {
+               $last_id = Config::get('system', 'dbclean-last-id-5', 0);
+
+               logger("Deleting orphaned data from notify-threads table. Last ID: ".$last_id);
+               $r = dba::p("SELECT `id` FROM `notify-threads`
+                               WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `notify-threads`.`master-parent-item`) AND `id` >= ?
+                               ORDER BY `id` LIMIT ".intval($limit), $last_id);
+               $count = dba::num_rows($r);
+               if ($count > 0) {
+                       logger("found notify-threads orphans: ".$count);
+                       while ($orphan = dba::fetch($r)) {
+                               $last_id = $orphan["id"];
+                               dba::delete('notify-threads', array('id' => $orphan["id"]));
+                       }
+               } else {
+                       logger("No notify-threads orphans found");
+               }
+               dba::close($r);
+               logger("Done deleting ".$count." orphaned data from notify-threads table. Last ID: ".$last_id);
+
+               Config::set('system', 'dbclean-last-id-5', $last_id);
+
+               if ($count < $limit) {
+                       Config::set('system', 'finished-dbclean-5', true);
+               }
+       } elseif ($stage == 6) {
+               $last_id = Config::get('system', 'dbclean-last-id-6', 0);
+
+               logger("Deleting orphaned data from sign table. Last ID: ".$last_id);
+               $r = dba::p("SELECT `iid`, `id` FROM `sign`
+                               WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `sign`.`iid`) AND `id` >= ?
+                               ORDER BY `id` LIMIT ".intval($limit), $last_id);
+               $count = dba::num_rows($r);
+               if ($count > 0) {
+                       logger("found sign orphans: ".$count);
+                       while ($orphan = dba::fetch($r)) {
+                               $last_id = $orphan["id"];
+                               dba::delete('sign', array('iid' => $orphan["iid"]));
+                       }
+               } else {
+                       logger("No sign orphans found");
+               }
+               dba::close($r);
+               logger("Done deleting ".$count." orphaned data from sign table. Last ID: ".$last_id);
+
+               Config::set('system', 'dbclean-last-id-6', $last_id);
+
+               if ($count < $limit) {
+                       Config::set('system', 'finished-dbclean-6', true);
+               }
+       } elseif ($stage == 7) {
+               $last_id = Config::get('system', 'dbclean-last-id-7', 0);
+
+               logger("Deleting orphaned data from term table. Last ID: ".$last_id);
+               $r = dba::p("SELECT `oid`, `tid` FROM `term`
+                               WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `term`.`oid`) AND `tid` >= ?
+                               ORDER BY `tid` LIMIT ".intval($limit), $last_id);
+               $count = dba::num_rows($r);
+               if ($count > 0) {
+                       logger("found term orphans: ".$count);
+                       while ($orphan = dba::fetch($r)) {
+                               $last_id = $orphan["tid"];
+                               dba::delete('term', array('oid' => $orphan["oid"]));
+                       }
+               } else {
+                       logger("No term orphans found");
+               }
+               dba::close($r);
+               logger("Done deleting ".$count." orphaned data from term table. Last ID: ".$last_id);
+
+               Config::set('system', 'dbclean-last-id-7', $last_id);
+
+               if ($count < $limit) {
+                       Config::set('system', 'finished-dbclean-7', true);
+               }
+       } elseif ($stage == 8) {
+               if ($days <= 0) {
+                       return;
+               }
+
+               $last_id = Config::get('system', 'dbclean-last-id-8', 0);
+
+               logger("Deleting expired threads. Last ID: ".$last_id);
+               $r = dba::p("SELECT `thread`.`iid` FROM `thread`
+                                INNER JOIN `contact` ON `thread`.`contact-id` = `contact`.`id` AND NOT `notify_new_posts`
+                                WHERE `thread`.`received` < UTC_TIMESTAMP() - INTERVAL ? DAY
+                                        AND NOT `thread`.`mention` AND NOT `thread`.`starred`
+                                        AND NOT `thread`.`wall` AND NOT `thread`.`origin`
+                                        AND `thread`.`uid` != 0 AND `thread`.`iid` >= ?
+                                        AND NOT `thread`.`iid` IN (SELECT `parent` FROM `item`
+                                                        WHERE (`item`.`starred` OR (`item`.`resource-id` != '')
+                                                                OR (`item`.`file` != '') OR (`item`.`event-id` != '')
+                                                                OR (`item`.`attach` != '') OR `item`.`wall` OR `item`.`origin`)
+                                                                AND `item`.`parent` = `thread`.`iid`)
+                                ORDER BY `thread`.`iid` LIMIT 1000", $days, $last_id);
+               $count = dba::num_rows($r);
+               if ($count > 0) {
+                       logger("found expired threads: ".$count);
+                       while ($thread = dba::fetch($r)) {
+                               $last_id = $thread["iid"];
+                               dba::delete('thread', array('iid' => $thread["iid"]));
+                       }
+               } else {
+                       logger("No expired threads found");
+               }
+               dba::close($r);
+               logger("Done deleting ".$count." expired threads. Last ID: ".$last_id);
+
+               Config::set('system', 'dbclean-last-id-8', $last_id);
+       } elseif ($stage == 9) {
+               if ($days <= 0) {
+                       return;
+               }
+
+               $last_id = Config::get('system', 'dbclean-last-id-9', 0);
+               $till_id = Config::get('system', 'dbclean-last-id-8', 0);
+
+               logger("Deleting old global item entries from expired threads from ID ".$last_id." to ID ".$till_id);
+               $r = dba::p("SELECT `id` FROM `item` WHERE `uid` = 0 AND
+                                       NOT EXISTS (SELECT `guid` FROM `item` AS `i` WHERE `item`.`guid` = `i`.`guid` AND `i`.`uid` != 0) AND
+                                       `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY AND `id` >= ? AND `id` <= ?
+                               ORDER BY `id` LIMIT ".intval($limit), $last_id, $till_id);
+               $count = dba::num_rows($r);
+               if ($count > 0) {
+                       logger("found global item entries from expired threads: ".$count);
+                       while ($orphan = dba::fetch($r)) {
+                               $last_id = $orphan["id"];
+                               dba::delete('item', array('id' => $orphan["id"]));
+                       }
+               } else {
+                       logger("No global item entries from expired threads");
+               }
+               dba::close($r);
+               logger("Done deleting ".$count." old global item entries from expired threads. Last ID: ".$last_id);
+
+               Config::set('system', 'dbclean-last-id-9', $last_id);
+       }
+
+       // Call it again if not all entries were purged
+       if (($stage != 0) && ($count > 0)) {
+               Worker::add(PRIORITY_MEDIUM, 'dbclean');
+       }
+}
diff --git a/worker/dbupdate.php b/worker/dbupdate.php
new file mode 100644 (file)
index 0000000..799ca26
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+
+use Friendica\Core\Config;
+
+function dbupdate_run(&$argv, &$argc) {
+       global $a;
+
+       // We are deleting the latest dbupdate entry.
+       // This is done to avoid endless loops because the update was interupted.
+       Config::delete('database', 'dbupdate_'.DB_UPDATE_VERSION);
+
+       update_db($a);
+}
diff --git a/worker/delivery.php b/worker/delivery.php
new file mode 100644 (file)
index 0000000..7c5f464
--- /dev/null
@@ -0,0 +1,541 @@
+<?php
+
+use Friendica\App;
+use Friendica\Core\System;
+use Friendica\Core\Config;
+use Friendica\Database\DBM;
+use Friendica\Protocol\Diaspora;
+use Friendica\Protocol\DFRN;
+
+require_once 'include/queue_fn.php';
+require_once 'include/html2plain.php';
+require_once 'include/ostatus.php';
+
+function delivery_run(&$argv, &$argc){
+       global $a;
+
+       require_once 'include/datetime.php';
+       require_once 'include/items.php';
+       require_once 'include/bbcode.php';
+       require_once 'include/email.php';
+
+       if ($argc < 3) {
+               return;
+       }
+
+       logger('delivery: invoked: '. print_r($argv,true), LOGGER_DEBUG);
+
+       $cmd        = $argv[1];
+       $item_id    = intval($argv[2]);
+
+       for ($x = 3; $x < $argc; $x ++) {
+
+               $contact_id = intval($argv[$x]);
+
+               if (!$item_id || !$contact_id) {
+                       continue;
+               }
+
+               $expire = false;
+               $mail = false;
+               $fsuggest = false;
+               $relocate = false;
+               $top_level = false;
+               $recipients = array();
+               $url_recipients = array();
+               $followup = false;
+
+               $normal_mode = true;
+
+               $recipients[] = $contact_id;
+
+               if ($cmd === 'mail') {
+                       $normal_mode = false;
+                       $mail = true;
+                       $message = q("SELECT * FROM `mail` WHERE `id` = %d LIMIT 1",
+                                       intval($item_id)
+                       );
+                       if (!count($message)) {
+                               return;
+                       }
+                       $uid = $message[0]['uid'];
+                       $recipients[] = $message[0]['contact-id'];
+                       $item = $message[0];
+               } elseif ($cmd === 'expire') {
+                       $normal_mode = false;
+                       $expire = true;
+                       $items = q("SELECT * FROM `item` WHERE `uid` = %d AND `wall` = 1
+                               AND `deleted` = 1 AND `changed` > UTC_TIMESTAMP() - INTERVAL 30 MINUTE",
+                               intval($item_id)
+                       );
+                       $uid = $item_id;
+                       $item_id = 0;
+                       if (!count($items)) {
+                               continue;
+                       }
+               } elseif ($cmd === 'suggest') {
+                       $normal_mode = false;
+                       $fsuggest = true;
+
+                       $suggest = q("SELECT * FROM `fsuggest` WHERE `id` = %d LIMIT 1",
+                               intval($item_id)
+                       );
+                       if (!count($suggest)) {
+                               return;
+                       }
+                       $uid = $suggest[0]['uid'];
+                       $recipients[] = $suggest[0]['cid'];
+                       $item = $suggest[0];
+               } elseif ($cmd === 'relocate') {
+                       $normal_mode = false;
+                       $relocate = true;
+                       $uid = $item_id;
+               } else {
+                       // find ancestors
+                       $r = q("SELECT * FROM `item` WHERE `id` = %d AND visible = 1 AND moderated = 0 LIMIT 1",
+                               intval($item_id)
+                       );
+
+                       if ((!DBM::is_result($r)) || (!intval($r[0]['parent']))) {
+                               continue;
+                       }
+
+                       $target_item = $r[0];
+                       $parent_id = intval($r[0]['parent']);
+                       $uid = $r[0]['uid'];
+                       $updated = $r[0]['edited'];
+
+                       $items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer`
+                               FROM `item` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` WHERE `parent` = %d AND visible = 1 AND moderated = 0 ORDER BY `id` ASC",
+                               intval($parent_id)
+                       );
+
+                       if (!count($items)) {
+                               continue;
+                       }
+
+                       $icontacts = null;
+                       $contacts_arr = array();
+                       foreach ($items as $item) {
+                               if (!in_array($item['contact-id'],$contacts_arr)) {
+                                       $contacts_arr[] = intval($item['contact-id']);
+                               }
+                       }
+                       if (count($contacts_arr)) {
+                               $str_contacts = implode(',',$contacts_arr);
+                               $icontacts = q("SELECT * FROM `contact`
+                                       WHERE `id` IN ( $str_contacts ) "
+                               );
+                       }
+                       if ( !($icontacts && count($icontacts))) {
+                               continue;
+                       }
+
+                       // avoid race condition with deleting entries
+
+                       if ($items[0]['deleted']) {
+                               foreach ($items as $item) {
+                                       $item['deleted'] = 1;
+                               }
+                       }
+
+                       // When commenting too fast after delivery, a post wasn't recognized as top level post.
+                       // The count then showed more than one entry. The additional check should help.
+                       // The check for the "count" should be superfluous, but I'm not totally sure by now, so we keep it.
+                       if ((($items[0]['id'] == $item_id) || (count($items) == 1)) && ($items[0]['uri'] === $items[0]['parent-uri'])) {
+                               logger('delivery: top level post');
+                               $top_level = true;
+                       }
+               }
+
+               $r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`,
+                       `user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`,
+                       `user`.`page-flags`, `user`.`account-type`, `user`.`prvnets`
+                       FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
+                       WHERE `contact`.`uid` = %d AND `contact`.`self` = 1 LIMIT 1",
+                       intval($uid)
+               );
+
+               if (!DBM::is_result($r)) {
+                       continue;
+               }
+
+               $owner = $r[0];
+
+               $walltowall = ((($top_level) && ($owner['id'] != $items[0]['contact-id'])) ? true : false);
+
+               $public_message = true;
+
+               if (!($mail || $fsuggest || $relocate)) {
+                       require_once 'include/group.php';
+
+                       $parent = $items[0];
+
+                       // This is IMPORTANT!!!!
+
+                       // We will only send a "notify owner to relay" or followup message if the referenced post
+                       // originated on our system by virtue of having our hostname somewhere
+                       // in the URI, AND it was a comment (not top_level) AND the parent originated elsewhere.
+                       // if $parent['wall'] == 1 we will already have the parent message in our array
+                       // and we will relay the whole lot.
+
+                       // expire sends an entire group of expire messages and cannot be forwarded.
+                       // However the conversation owner will be a part of the conversation and will
+                       // be notified during this run.
+                       // Other DFRN conversation members will be alerted during polled updates.
+
+                       // Diaspora members currently are not notified of expirations, and other networks have
+                       // either limited or no ability to process deletions. We should at least fix Diaspora
+                       // by stringing togther an array of retractions and sending them onward.
+
+
+                       $localhost = $a->get_hostname();
+                       if (strpos($localhost,':')) {
+                               $localhost = substr($localhost,0,strpos($localhost,':'));
+                       }
+                       /**
+                        *
+                        * Be VERY CAREFUL if you make any changes to the following line. Seemingly innocuous changes
+                        * have been known to cause runaway conditions which affected several servers, along with
+                        * permissions issues.
+                        *
+                        */
+
+                       $relay_to_owner = false;
+
+                       if (!$top_level && ($parent['wall'] == 0) && !$expire && stristr($target_item['uri'],$localhost)) {
+                               $relay_to_owner = true;
+                       }
+
+                       if ($relay_to_owner) {
+                               logger('followup '.$target_item["guid"], LOGGER_DEBUG);
+                               // local followup to remote post
+                               $followup = true;
+                       }
+
+                       if ((strlen($parent['allow_cid']))
+                               || (strlen($parent['allow_gid']))
+                               || (strlen($parent['deny_cid']))
+                               || (strlen($parent['deny_gid']))
+                               || $parent["private"]) {
+                               $public_message = false; // private recipients, not public
+                       }
+
+               }
+
+               $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `blocked` = 0 AND `pending` = 0",
+                       intval($contact_id)
+               );
+
+               if (DBM::is_result($r)) {
+                       $contact = $r[0];
+               }
+               if ($contact['self']) {
+                       continue;
+               }
+               $deliver_status = 0;
+
+               logger("main delivery by delivery: followup=$followup mail=$mail fsuggest=$fsuggest relocate=$relocate - network ".$contact['network']);
+
+               switch($contact['network']) {
+
+                       case NETWORK_DFRN:
+                               logger('notifier: '.$target_item["guid"].' dfrndelivery: '.$contact['name']);
+
+                               if ($mail) {
+                                       $item['body'] = fix_private_photos($item['body'],$owner['uid'],null,$message[0]['contact-id']);
+                                       $atom = DFRN::mail($item, $owner);
+                               } elseif ($fsuggest) {
+                                       $atom = DFRN::fsuggest($item, $owner);
+                                       q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item['id']));
+                               } elseif ($relocate) {
+                                       $atom = DFRN::relocate($owner, $uid);
+                               } elseif ($followup) {
+                                       $msgitems = array();
+                                       foreach ($items as $item) {  // there is only one item
+                                               if (!$item['parent']) {
+                                                       continue;
+                                               }
+                                               if ($item['id'] == $item_id) {
+                                                       logger('followup: item: '. print_r($item,true), LOGGER_DATA);
+                                                       $msgitems[] = $item;
+                                               }
+                                       }
+                                       $atom = DFRN::entries($msgitems,$owner);
+                               } else {
+                                       $msgitems = array();
+                                       foreach ($items as $item) {
+                                               if (!$item['parent']) {
+                                                       continue;
+                                               }
+
+                                               // private emails may be in included in public conversations. Filter them.
+                                               if ($public_message && $item['private']) {
+                                                       continue;
+                                               }
+
+                                               $item_contact = get_item_contact($item,$icontacts);
+                                               if (!$item_contact) {
+                                                       continue;
+                                               }
+
+                                               if ($normal_mode) {
+                                                       if ($item_id == $item['id'] || $item['id'] == $item['parent']) {
+                                                               $item["entry:comment-allow"] = true;
+                                                               $item["entry:cid"] = (($top_level) ? $contact['id'] : 0);
+                                                               $msgitems[] = $item;
+                                                       }
+                                               } else {
+                                                       $item["entry:comment-allow"] = true;
+                                                       $msgitems[] = $item;
+                                               }
+                                       }
+                                       $atom = DFRN::entries($msgitems,$owner);
+                               }
+
+                               logger('notifier entry: '.$contact["url"].' '.$target_item["guid"].' entry: '.$atom, LOGGER_DEBUG);
+
+                               logger('notifier: '.$atom, LOGGER_DATA);
+                               $basepath =  implode('/', array_slice(explode('/',$contact['url']),0,3));
+
+                               // perform local delivery if we are on the same site
+
+                               if (link_compare($basepath,System::baseUrl())) {
+
+                                       $nickname = basename($contact['url']);
+                                       if ($contact['issued-id']) {
+                                               $sql_extra = sprintf(" AND `dfrn-id` = '%s' ", dbesc($contact['issued-id']));
+                                       } else {
+                                               $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($contact['dfrn-id']));
+                                       }
+
+                                       $x = q("SELECT  `contact`.*, `contact`.`uid` AS `importer_uid`,
+                                               `contact`.`pubkey` AS `cpubkey`,
+                                               `contact`.`prvkey` AS `cprvkey`,
+                                               `contact`.`thumb` AS `thumb`,
+                                               `contact`.`url` as `url`,
+                                               `contact`.`name` as `senderName`,
+                                               `user`.*
+                                               FROM `contact`
+                                               INNER JOIN `user` ON `contact`.`uid` = `user`.`uid`
+                                               WHERE `contact`.`blocked` = 0 AND `contact`.`pending` = 0
+                                               AND `contact`.`network` = '%s' AND `user`.`nickname` = '%s'
+                                               $sql_extra
+                                               AND `user`.`account_expired` = 0 AND `user`.`account_removed` = 0 LIMIT 1",
+                                               dbesc(NETWORK_DFRN),
+                                               dbesc($nickname)
+                                       );
+
+                                       if ($x && count($x)) {
+                                               $write_flag = ((($x[0]['rel']) && ($x[0]['rel'] != CONTACT_IS_SHARING)) ? true : false);
+                                               if ((($owner['page-flags'] == PAGE_COMMUNITY) || $write_flag) && !$x[0]['writable']) {
+                                                       q("UPDATE `contact` SET `writable` = 1 WHERE `id` = %d",
+                                                               intval($x[0]['id'])
+                                                       );
+                                                       $x[0]['writable'] = 1;
+                                               }
+
+                                               $ssl_policy = Config::get('system','ssl_policy');
+                                               fix_contact_ssl_policy($x[0],$ssl_policy);
+
+                                               // If we are setup as a soapbox we aren't accepting top level posts from this person
+
+                                               if (($x[0]['page-flags'] == PAGE_SOAPBOX) && $top_level) {
+                                                       break;
+                                               }
+                                               logger('mod-delivery: local delivery');
+                                               DFRN::import($atom, $x[0]);
+                                               break;
+                                       }
+                               }
+
+                               if (!was_recently_delayed($contact['id'])) {
+                                       $deliver_status = DFRN::deliver($owner,$contact,$atom);
+                               } else {
+                                       $deliver_status = (-1);
+                               }
+
+                               logger('notifier: dfrn_delivery to '.$contact["url"].' with guid '.$target_item["guid"].' returns '.$deliver_status);
+
+                               if ($deliver_status < 0) {
+                                       logger('notifier: delivery failed: queuing message');
+                                       add_to_queue($contact['id'],NETWORK_DFRN,$atom);
+
+                                       // The message could not be delivered. We mark the contact as "dead"
+                                       mark_for_death($contact);
+                               } else {
+                                       // We successfully delivered a message, the contact is alive
+                                       unmark_for_death($contact);
+                               }
+
+                               break;
+
+                       case NETWORK_OSTATUS:
+                               // Do not send to otatus if we are not configured to send to public networks
+                               if ($owner['prvnets']) {
+                                       break;
+                               }
+                               if (Config::get('system','ostatus_disabled') || Config::get('system','dfrn_only')) {
+                                       break;
+                               }
+
+                               // There is currently no code here to distribute anything to OStatus.
+                               // This is done in "notifier.php" (See "url_recipients" and "push_notify")
+                               break;
+
+                       case NETWORK_MAIL:
+                       case NETWORK_MAIL2:
+
+                               if (Config::get('system','dfrn_only')) {
+                                       break;
+                               }
+                               // WARNING: does not currently convert to RFC2047 header encodings, etc.
+
+                               $addr = $contact['addr'];
+                               if (!strlen($addr)) {
+                                       break;
+                               }
+
+                               if ($cmd === 'wall-new' || $cmd === 'comment-new') {
+
+                                       $it = null;
+                                       if ($cmd === 'wall-new') {
+                                               $it = $items[0];
+                                       } else {
+                                               $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1",
+                                                       intval($argv[2]),
+                                                       intval($uid)
+                                               );
+                                               if (DBM::is_result($r))
+                                                       $it = $r[0];
+                                       }
+                                       if (!$it)
+                                               break;
+
+
+                                       $local_user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1",
+                                               intval($uid)
+                                       );
+                                       if (!count($local_user))
+                                               break;
+
+                                       $reply_to = '';
+                                       $r1 = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1",
+                                               intval($uid)
+                                       );
+                                       if ($r1 && $r1[0]['reply_to'])
+                                               $reply_to = $r1[0]['reply_to'];
+
+                                       $subject  = (($it['title']) ? email_header_encode($it['title'],'UTF-8') : t("\x28no subject\x29")) ;
+
+                                       // only expose our real email address to true friends
+
+                                       if (($contact['rel'] == CONTACT_IS_FRIEND) && !$contact['blocked']) {
+                                               if ($reply_to) {
+                                                       $headers  = 'From: '.email_header_encode($local_user[0]['username'],'UTF-8').' <'.$reply_to.'>'."\n";
+                                                       $headers .= 'Sender: '.$local_user[0]['email']."\n";
+                                               } else {
+                                                       $headers  = 'From: '.email_header_encode($local_user[0]['username'],'UTF-8').' <'.$local_user[0]['email'].'>'."\n";
+                                               }
+                                       } else {
+                                               $headers  = 'From: '. email_header_encode($local_user[0]['username'],'UTF-8') .' <'. t('noreply') .'@'.$a->get_hostname() .'>'. "\n";
+                                       }
+
+                                       //if ($reply_to)
+                                       //      $headers .= 'Reply-to: '.$reply_to . "\n";
+
+                                       $headers .= 'Message-Id: <'. iri2msgid($it['uri']).'>'. "\n";
+
+                                       //logger("Mail: uri: ".$it['uri']." parent-uri ".$it['parent-uri'], LOGGER_DEBUG);
+                                       //logger("Mail: Data: ".print_r($it, true), LOGGER_DEBUG);
+                                       //logger("Mail: Data: ".print_r($it, true), LOGGER_DATA);
+
+                                       if ($it['uri'] !== $it['parent-uri']) {
+                                               $headers .= "References: <".iri2msgid($it["parent-uri"]).">";
+
+                                               // If Threading is enabled, write down the correct parent
+                                               if (($it["thr-parent"] != "") && ($it["thr-parent"] != $it["parent-uri"]))
+                                                       $headers .= " <".iri2msgid($it["thr-parent"]).">";
+                                               $headers .= "\n";
+
+                                               if (!$it['title']) {
+                                                       $r = q("SELECT `title` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
+                                                               dbesc($it['parent-uri']),
+                                                               intval($uid));
+
+                                                       if (DBM::is_result($r) && ($r[0]['title'] != '')) {
+                                                               $subject = $r[0]['title'];
+                                                       } else {
+                                                               $r = q("SELECT `title` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d LIMIT 1",
+                                                                       dbesc($it['parent-uri']),
+                                                                       intval($uid));
+
+                                                               if (DBM::is_result($r) && ($r[0]['title'] != ''))
+                                                                       $subject = $r[0]['title'];
+                                                       }
+                                               }
+                                               if (strncasecmp($subject,'RE:',3))
+                                                       $subject = 'Re: '.$subject;
+                                       }
+                                       email_send($addr, $subject, $headers, $it);
+                               }
+                               break;
+
+                       case NETWORK_DIASPORA:
+                               if ($public_message)
+                                       $loc = 'public batch '.$contact['batch'];
+                               else
+                                       $loc = $contact['name'];
+
+                               logger('delivery: diaspora batch deliver: '.$loc);
+
+                               if (Config::get('system','dfrn_only') || (!Config::get('system','diaspora_enabled')))
+                                       break;
+
+                               if ($mail) {
+                                       Diaspora::send_mail($item,$owner,$contact);
+                                       break;
+                               }
+
+                               if (!$normal_mode)
+                                       break;
+
+                               if (!$contact['pubkey'] && !$public_message)
+                                       break;
+
+                               if (($target_item['deleted']) && (($target_item['uri'] === $target_item['parent-uri']) || $followup)) {
+                                       // top-level retraction
+                                       logger('diaspora retract: '.$loc);
+                                       Diaspora::send_retraction($target_item,$owner,$contact,$public_message);
+                                       break;
+                               } elseif ($relocate) {
+                                       Diaspora::sendAccountMigration($owner, $contact, $uid);
+                                       break;
+                               } elseif ($followup) {
+                                       // send comments and likes to owner to relay
+                                       logger('diaspora followup: '.$loc);
+                                       Diaspora::send_followup($target_item,$owner,$contact,$public_message);
+                                       break;
+                               } elseif ($target_item['uri'] !== $target_item['parent-uri']) {
+                                       // we are the relay - send comments, likes and relayable_retractions to our conversants
+                                       logger('diaspora relay: '.$loc);
+                                       Diaspora::send_relay($target_item,$owner,$contact,$public_message);
+                                       break;
+                               } elseif ($top_level && !$walltowall) {
+                                       // currently no workable solution for sending walltowall
+                                       logger('diaspora status: '.$loc);
+                                       Diaspora::send_status($target_item,$owner,$contact,$public_message);
+                                       break;
+                               }
+
+                               logger('delivery: diaspora unknown mode: '.$contact['name']);
+
+                               break;
+
+                       default:
+                               break;
+               }
+       }
+
+       return;
+}
diff --git a/worker/directory.php b/worker/directory.php
new file mode 100644 (file)
index 0000000..f56e8db
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+
+use Friendica\Core\Config;
+use Friendica\Core\Worker;
+use Friendica\Database\DBM;
+
+function directory_run(&$argv, &$argc){
+       $dir = Config::get('system', 'directory');
+
+       if (!strlen($dir)) {
+               return;
+       }
+
+       if ($argc < 2) {
+               directory_update_all();
+               return;
+       }
+
+       $dir .= "/submit";
+
+       $arr = array('url' => $argv[1]);
+
+       call_hooks('globaldir_update', $arr);
+
+       logger('Updating directory: ' . $arr['url'], LOGGER_DEBUG);
+       if (strlen($arr['url'])) {
+               fetch_url($dir . '?url=' . bin2hex($arr['url']));
+       }
+
+       return;
+}
+
+function directory_update_all() {
+       $r = q("SELECT `url` FROM `contact`
+               INNER JOIN `profile` ON `profile`.`uid` = `contact`.`uid`
+               INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
+                       WHERE `contact`.`self` AND `profile`.`net-publish` AND `profile`.`is-default` AND
+                               NOT `user`.`account_expired` AND `user`.`verified`");
+
+       if (DBM::is_result($r)) {
+               foreach ($r AS $user) {
+                       Worker::add(PRIORITY_LOW, 'directory', $user['url']);
+               }
+       }
+}
diff --git a/worker/discover_poco.php b/worker/discover_poco.php
new file mode 100644 (file)
index 0000000..bb8daad
--- /dev/null
@@ -0,0 +1,293 @@
+<?php
+use Friendica\Core\Cache;
+use Friendica\Core\Config;
+use Friendica\Core\Worker;
+use Friendica\Database\DBM;
+use Friendica\Network\Probe;
+
+require_once 'include/socgraph.php';
+require_once 'include/datetime.php';
+
+function discover_poco_run(&$argv, &$argc) {
+
+       /*
+       This function can be called in these ways:
+       - dirsearch <search pattern>: Searches for "search pattern" in the directory. "search pattern" is url encoded.
+       - checkcontact: Updates gcontact entries
+       - suggestions: Discover other servers for their contacts.
+       - server <poco url>: Searches for the poco server list. "poco url" is base64 encoded.
+       - update_server: Frequently check the first 250 servers for vitality.
+       - update_server_directory: Discover the given server id for their contacts
+       - poco_load: Load POCO data from a given POCO address
+       - check_profile: Update remote profile data
+       */
+
+       if (($argc > 2) && ($argv[1] == "dirsearch")) {
+               $search = urldecode($argv[2]);
+               $mode = 1;
+       } elseif (($argc == 2) && ($argv[1] == "checkcontact")) {
+               $mode = 2;
+       } elseif (($argc == 2) && ($argv[1] == "suggestions")) {
+               $mode = 3;
+       } elseif (($argc == 3) && ($argv[1] == "server")) {
+               $mode = 4;
+       } elseif (($argc == 2) && ($argv[1] == "update_server")) {
+               $mode = 5;
+       } elseif (($argc == 3) && ($argv[1] == "update_server_directory")) {
+               $mode = 6;
+       } elseif (($argc > 5) && ($argv[1] == "poco_load")) {
+               $mode = 7;
+       } elseif (($argc == 3) && ($argv[1] == "check_profile")) {
+               $mode = 8;
+       } elseif ($argc == 1) {
+               $search = "";
+               $mode = 0;
+       } else {
+               die("Unknown or missing parameter ".$argv[1]."\n");
+       }
+
+       logger('start '.$search);
+
+       if ($mode == 8) {
+               if ($argv[2] != "") {
+                       poco_last_updated($argv[2], true);
+               }
+       } elseif ($mode == 7) {
+               if ($argc == 6) {
+                       $url = $argv[5];
+               } else {
+                       $url = '';
+               }
+               poco_load_worker(intval($argv[2]), intval($argv[3]), intval($argv[4]), $url);
+       } elseif ($mode == 6) {
+               poco_discover_single_server(intval($argv[2]));
+       } elseif ($mode == 5) {
+               update_server();
+       } elseif ($mode == 4) {
+               $server_url = $argv[2];
+               if ($server_url == "") {
+                       return;
+               }
+               $server_url = filter_var($server_url, FILTER_SANITIZE_URL);
+               if (substr(normalise_link($server_url), 0, 7) != "http://") {
+                       return;
+               }
+               $result = "Checking server ".$server_url." - ";
+               $ret = poco_check_server($server_url);
+               if ($ret) {
+                       $result .= "success";
+               } else {
+                       $result .= "failed";
+               }
+               logger($result, LOGGER_DEBUG);
+       } elseif ($mode == 3) {
+               update_suggestions();
+       } elseif (($mode == 2) && Config::get('system','poco_completion')) {
+               discover_users();
+       } elseif (($mode == 1) && ($search != "") && Config::get('system','poco_local_search')) {
+               discover_directory($search);
+               gs_search_user($search);
+       } elseif (($mode == 0) && ($search == "") && (Config::get('system','poco_discovery') > 0)) {
+               // Query Friendica and Hubzilla servers for their users
+               poco_discover();
+
+               // Query GNU Social servers for their users ("statistics" addon has to be enabled on the GS server)
+               if (!Config::get('system','ostatus_disabled'))
+                       gs_discover();
+       }
+
+       logger('end '.$search);
+
+       return;
+}
+
+/**
+ * @brief Updates the first 250 servers
+ *
+ */
+function update_server() {
+       $r = q("SELECT `url`, `created`, `last_failure`, `last_contact` FROM `gserver` ORDER BY rand()");
+
+       if (!DBM::is_result($r)) {
+               return;
+       }
+
+       $updated = 0;
+
+       foreach ($r AS $server) {
+               if (!poco_do_update($server["created"], "", $server["last_failure"], $server["last_contact"])) {
+                       continue;
+               }
+               logger('Update server status for server '.$server["url"], LOGGER_DEBUG);
+
+               Worker::add(PRIORITY_LOW, "discover_poco", "server", $server["url"]);
+
+               if (++$updated > 250) {
+                       return;
+               }
+       }
+}
+
+function discover_users() {
+       logger("Discover users", LOGGER_DEBUG);
+
+       $starttime = time();
+
+       $users = q("SELECT `url`, `created`, `updated`, `last_failure`, `last_contact`, `server_url`, `network` FROM `gcontact`
+                       WHERE `last_contact` < UTC_TIMESTAMP - INTERVAL 1 MONTH AND
+                               `last_failure` < UTC_TIMESTAMP - INTERVAL 1 MONTH AND
+                               `network` IN ('%s', '%s', '%s', '%s', '') ORDER BY rand()",
+                       dbesc(NETWORK_DFRN), dbesc(NETWORK_DIASPORA),
+                       dbesc(NETWORK_OSTATUS), dbesc(NETWORK_FEED));
+
+       if (!$users) {
+               return;
+       }
+       $checked = 0;
+
+       foreach ($users AS $user) {
+
+               $urlparts = parse_url($user["url"]);
+               if (!isset($urlparts["scheme"])) {
+                       q("UPDATE `gcontact` SET `network` = '%s' WHERE `nurl` = '%s'",
+                               dbesc(NETWORK_PHANTOM), dbesc(normalise_link($user["url"])));
+                       continue;
+                }
+
+               if (in_array($urlparts["host"], array("www.facebook.com", "facebook.com", "twitter.com",
+                                                       "identi.ca", "alpha.app.net"))) {
+                       $networks = array("www.facebook.com" => NETWORK_FACEBOOK,
+                                       "facebook.com" => NETWORK_FACEBOOK,
+                                       "twitter.com" => NETWORK_TWITTER,
+                                       "identi.ca" => NETWORK_PUMPIO,
+                                       "alpha.app.net" => NETWORK_APPNET);
+
+                       q("UPDATE `gcontact` SET `network` = '%s' WHERE `nurl` = '%s'",
+                               dbesc($networks[$urlparts["host"]]), dbesc(normalise_link($user["url"])));
+                       continue;
+               }
+
+               $server_url = poco_detect_server($user["url"]);
+               $force_update = false;
+
+               if ($user["server_url"] != "") {
+
+                       $force_update = (normalise_link($user["server_url"]) != normalise_link($server_url));
+
+                       $server_url = $user["server_url"];
+               }
+
+               if ((($server_url == "") && ($user["network"] == NETWORK_FEED)) || $force_update || poco_check_server($server_url, $user["network"])) {
+                       logger('Check profile '.$user["url"]);
+                       Worker::add(PRIORITY_LOW, "discover_poco", "check_profile", $user["url"]);
+
+                       if (++$checked > 100) {
+                               return;
+                       }
+               } else {
+                       q("UPDATE `gcontact` SET `last_failure` = '%s' WHERE `nurl` = '%s'",
+                               dbesc(datetime_convert()), dbesc(normalise_link($user["url"])));
+               }
+
+               // Quit the loop after 3 minutes
+               if (time() > ($starttime + 180)) {
+                       return;
+               }
+       }
+}
+
+function discover_directory($search) {
+
+       $data = Cache::get("dirsearch:".$search);
+       if (!is_null($data)) {
+               // Only search for the same item every 24 hours
+               if (time() < $data + (60 * 60 * 24)) {
+                       logger("Already searched for ".$search." in the last 24 hours", LOGGER_DEBUG);
+                       return;
+               }
+       }
+
+       $x = fetch_url(get_server()."/lsearch?p=1&n=500&search=".urlencode($search));
+       $j = json_decode($x);
+
+       if (count($j->results)) {
+               foreach ($j->results as $jj) {
+                       // Check if the contact already exists
+                       $exists = q("SELECT `id`, `last_contact`, `last_failure`, `updated` FROM `gcontact` WHERE `nurl` = '%s'", normalise_link($jj->url));
+                       if (DBM::is_result($exists)) {
+                               logger("Profile ".$jj->url." already exists (".$search.")", LOGGER_DEBUG);
+
+                               if (($exists[0]["last_contact"] < $exists[0]["last_failure"]) &&
+                                       ($exists[0]["updated"] < $exists[0]["last_failure"])) {
+                                       continue;
+                               }
+                               // Update the contact
+                               poco_last_updated($jj->url);
+                               continue;
+                       }
+
+                       $server_url = poco_detect_server($jj->url);
+                       if ($server_url != '') {
+                               if (!poco_check_server($server_url)) {
+                                       logger("Friendica server ".$server_url." doesn't answer.", LOGGER_DEBUG);
+                                       continue;
+                               }
+                               logger("Friendica server ".$server_url." seems to be okay.", LOGGER_DEBUG);
+                       }
+
+                       $data = Probe::uri($jj->url);
+                       if ($data["network"] == NETWORK_DFRN) {
+                               logger("Profile ".$jj->url." is reachable (".$search.")", LOGGER_DEBUG);
+                               logger("Add profile ".$jj->url." to local directory (".$search.")", LOGGER_DEBUG);
+
+                               if ($jj->tags != "") {
+                                       $data["keywords"] = $jj->tags;
+                               }
+
+                               $data["server_url"] = $data["baseurl"];
+
+                               update_gcontact($data);
+                       } else {
+                               logger("Profile ".$jj->url." is not responding or no Friendica contact - but network ".$data["network"], LOGGER_DEBUG);
+                       }
+               }
+       }
+       Cache::set("dirsearch:".$search, time(), CACHE_DAY);
+}
+
+/**
+ * @brief Search for GNU Social user with gstools.org
+ *
+ * @param str $search User name
+ */
+function gs_search_user($search) {
+
+       // Currently disabled, since the service isn't available anymore.
+       // It is not removed since I hope that there will be a successor.
+       return false;
+
+       $a = get_app();
+
+       $url = "http://gstools.org/api/users_search/".urlencode($search);
+
+       $result = z_fetch_url($url);
+       if (!$result["success"]) {
+               return false;
+       }
+
+       $contacts = json_decode($result["body"]);
+
+       if ($contacts->status == 'ERROR') {
+               return false;
+       }
+
+       /// @TODO AS is considered as a notation for constants (as they usually being written all upper-case)
+       /// @TODO find all those and convert to all lower-case which is a keyword then
+       foreach ($contacts->data AS $user) {
+               $contact = Probe::uri($user->site_address."/".$user->name);
+               if ($contact["network"] != NETWORK_PHANTOM) {
+                       $contact["about"] = $user->description;
+                       update_gcontact($contact);
+               }
+       }
+}
diff --git a/worker/expire.php b/worker/expire.php
new file mode 100644 (file)
index 0000000..7a3549a
--- /dev/null
@@ -0,0 +1,76 @@
+<?php
+
+use Friendica\Core\Config;
+use Friendica\Core\Worker;
+use Friendica\Database\DBM;
+
+function expire_run(&$argv, &$argc){
+       global $a;
+
+       require_once('include/datetime.php');
+       require_once('include/items.php');
+       require_once('include/Contact.php');
+
+       load_hooks();
+
+       if (($argc == 2) && ($argv[1] == 'delete')) {
+               logger('Delete expired items', LOGGER_DEBUG);
+               // physically remove anything that has been deleted for more than two months
+               $r = dba::p("SELECT `id` FROM `item` WHERE `deleted` AND `changed` < UTC_TIMESTAMP() - INTERVAL 60 DAY");
+               while ($row = dba::fetch($r)) {
+                       dba::delete('item', array('id' => $row['id']));
+               }
+               dba::close($r);
+
+               logger('Delete expired items - done', LOGGER_DEBUG);
+
+               // make this optional as it could have a performance impact on large sites
+               if (intval(Config::get('system', 'optimize_items'))) {
+                       q("OPTIMIZE TABLE `item`");
+               }
+               return;
+       } elseif (($argc == 2) && (intval($argv[1]) > 0)) {
+               $user = dba::select('user', array('uid', 'username', 'expire'), array('uid' => $argv[1]), array('limit' => 1));
+               if (DBM::is_result($user)) {
+                       logger('Expire items for user '.$user['uid'].' ('.$user['username'].') - interval: '.$user['expire'], LOGGER_DEBUG);
+                       item_expire($user['uid'], $user['expire']);
+                       logger('Expire items for user '.$user['uid'].' ('.$user['username'].') - done ', LOGGER_DEBUG);
+               }
+               return;
+       } elseif (($argc == 3) && ($argv[1] == 'hook') && is_array($a->hooks) && array_key_exists("expire", $a->hooks)) {
+               foreach ($a->hooks["expire"] as $hook) {
+                       if ($hook[1] == $argv[2]) {
+                               logger("Calling expire hook '" . $hook[1] . "'", LOGGER_DEBUG);
+                               call_single_hook($a, $name, $hook, $data);
+                       }
+               }
+               return;
+       }
+
+       logger('expire: start');
+
+       Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true),
+                       'expire', 'delete');
+
+       $r = dba::p("SELECT `uid`, `username` FROM `user` WHERE `expire` != 0");
+       while ($row = dba::fetch($r)) {
+               logger('Calling expiry for user '.$row['uid'].' ('.$row['username'].')', LOGGER_DEBUG);
+               Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true),
+                               'expire', (int)$row['uid']);
+       }
+       dba::close($r);
+
+       logger('expire: calling hooks');
+
+       if (is_array($a->hooks) && array_key_exists('expire', $a->hooks)) {
+               foreach ($a->hooks['expire'] as $hook) {
+                       logger("Calling expire hook for '" . $hook[1] . "'", LOGGER_DEBUG);
+                       Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true),
+                                       'expire', 'hook', $hook[1]);
+               }
+       }
+
+       logger('expire: end');
+
+       return;
+}
diff --git a/worker/gprobe.php b/worker/gprobe.php
new file mode 100644 (file)
index 0000000..7003051
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+use Friendica\Core\Cache;
+use Friendica\Core\Config;
+use Friendica\Database\DBM;
+use Friendica\Network\Probe;
+
+require_once 'include/socgraph.php';
+require_once 'include/datetime.php';
+
+function gprobe_run(&$argv, &$argc){
+       if ($argc != 2) {
+               return;
+       }
+       $url = $argv[1];
+
+       $r = q("SELECT `id`, `url`, `network` FROM `gcontact` WHERE `nurl` = '%s' ORDER BY `id` LIMIT 1",
+               dbesc(normalise_link($url))
+       );
+
+       logger("gprobe start for ".normalise_link($url), LOGGER_DEBUG);
+
+       if (!DBM::is_result($r)) {
+
+               // Is it a DDoS attempt?
+               $urlparts = parse_url($url);
+
+               $result = Cache::get("gprobe:".$urlparts["host"]);
+               if (!is_null($result)) {
+                       if (in_array($result["network"], array(NETWORK_FEED, NETWORK_PHANTOM))) {
+                               logger("DDoS attempt detected for ".$urlparts["host"]." by ".$_SERVER["REMOTE_ADDR"].". server data: ".print_r($_SERVER, true), LOGGER_DEBUG);
+                               return;
+                       }
+               }
+
+               $arr = Probe::uri($url);
+
+               if (is_null($result)) {
+                       Cache::set("gprobe:".$urlparts["host"], $arr);
+               }
+
+               if (!in_array($arr["network"], array(NETWORK_FEED, NETWORK_PHANTOM))) {
+                       update_gcontact($arr);
+               }
+
+               $r = q("SELECT `id`, `url`, `network` FROM `gcontact` WHERE `nurl` = '%s' ORDER BY `id` LIMIT 1",
+                       dbesc(normalise_link($url))
+               );
+       }
+       if (DBM::is_result($r)) {
+               // Check for accessibility and do a poco discovery
+               if (poco_last_updated($r[0]['url'], true) && ($r[0]["network"] == NETWORK_DFRN))
+                       poco_load(0,0,$r[0]['id'], str_replace('/profile/','/poco/',$r[0]['url']));
+       }
+
+       logger("gprobe end for ".normalise_link($url), LOGGER_DEBUG);
+       return;
+}
diff --git a/worker/notifier.php b/worker/notifier.php
new file mode 100644 (file)
index 0000000..3e9ea66
--- /dev/null
@@ -0,0 +1,617 @@
+<?php
+
+use Friendica\App;
+use Friendica\Core\Config;
+use Friendica\Core\Worker;
+use Friendica\Database\DBM;
+use Friendica\Network\Probe;
+use Friendica\Protocol\Diaspora;
+
+require_once 'include/queue_fn.php';
+require_once 'include/html2plain.php';
+require_once 'include/ostatus.php';
+require_once 'include/salmon.php';
+
+/*
+ * This file was at one time responsible for doing all deliveries, but this caused
+ * big problems when the process was killed or stalled during the delivery process.
+ * It now invokes separate queues that are delivering via delivery.php and pubsubpublish.php.
+ */
+
+/*
+ * The notifier is typically called with:
+ *
+ *             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)
+ *             expire                                  (in items.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)
+ *
+ * and ITEM_ID is the id of the item in the database that needs to be sent to others.
+ */
+
+
+function notifier_run(&$argv, &$argc){
+       global $a;
+
+       require_once 'include/datetime.php';
+       require_once 'include/items.php';
+       require_once 'include/bbcode.php';
+       require_once 'include/email.php';
+
+       if ($argc < 3) {
+               return;
+       }
+
+       logger('notifier: invoked: ' . print_r($argv,true), LOGGER_DEBUG);
+
+       $cmd = $argv[1];
+
+       switch($cmd) {
+               case 'mail':
+               default:
+                       $item_id = intval($argv[2]);
+                       if (! $item_id) {
+                               return;
+                       }
+                       break;
+       }
+
+       $expire = false;
+       $mail = false;
+       $fsuggest = false;
+       $relocate = false;
+       $top_level = false;
+       $recipients = array();
+       $url_recipients = array();
+
+       $normal_mode = true;
+
+       if ($cmd === 'mail') {
+               $normal_mode = false;
+               $mail = true;
+               $message = q("SELECT * FROM `mail` WHERE `id` = %d LIMIT 1",
+                               intval($item_id)
+               );
+               if (! count($message)) {
+                       return;
+               }
+               $uid = $message[0]['uid'];
+               $recipients[] = $message[0]['contact-id'];
+               $item = $message[0];
+
+       } elseif ($cmd === 'expire') {
+               $normal_mode = false;
+               $expire = true;
+               $items = q("SELECT * FROM `item` WHERE `uid` = %d AND `wall` = 1
+                       AND `deleted` = 1 AND `changed` > UTC_TIMESTAMP() - INTERVAL 10 MINUTE",
+                       intval($item_id)
+               );
+               $uid = $item_id;
+               $item_id = 0;
+               if (! count($items)) {
+                       return;
+               }
+       } elseif ($cmd === 'suggest') {
+               $normal_mode = false;
+               $fsuggest = true;
+
+               $suggest = q("SELECT * FROM `fsuggest` WHERE `id` = %d LIMIT 1",
+                       intval($item_id)
+               );
+               if (! count($suggest)) {
+                       return;
+               }
+               $uid = $suggest[0]['uid'];
+               $recipients[] = $suggest[0]['cid'];
+               $item = $suggest[0];
+       } elseif ($cmd === 'removeme') {
+               $r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`,
+                               `user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`,
+                               `user`.`page-flags`, `user`.`prvnets`, `user`.`account-type`, `user`.`guid`
+                       FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
+                               WHERE `contact`.`uid` = %d AND `contact`.`self` LIMIT 1",
+                               intval($item_id));
+               if (!$r)
+                       return;
+
+               $user = $r[0];
+
+               $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1", intval($item_id));
+               if (!$r)
+                       return;
+
+               $self = $r[0];
+
+               $r = q("SELECT * FROM `contact` WHERE NOT `self` AND `uid` = %d", intval($item_id));
+               if (!$r) {
+                       return;
+               }
+               require_once 'include/Contact.php';
+               foreach ($r as $contact) {
+                       terminate_friendship($user, $self, $contact);
+               }
+               return;
+       } elseif ($cmd === 'relocate') {
+               $normal_mode = false;
+               $relocate = true;
+               $uid = $item_id;
+
+               $recipients_relocate = q("SELECT * FROM `contact` WHERE `uid` = %d AND NOT `self` AND `network` IN ('%s', '%s')",
+                                       intval($uid), NETWORK_DFRN, NETWORK_DIASPORA);
+       } else {
+               // find ancestors
+               $r = q("SELECT * FROM `item` WHERE `id` = %d AND visible = 1 AND moderated = 0 LIMIT 1",
+                       intval($item_id)
+               );
+
+               if ((! DBM::is_result($r)) || (! intval($r[0]['parent']))) {
+                       return;
+               }
+
+               $target_item = $r[0];
+               $parent_id = intval($r[0]['parent']);
+               $uid = $r[0]['uid'];
+               $updated = $r[0]['edited'];
+
+               $items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer`
+                       FROM `item` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` WHERE `parent` = %d AND visible = 1 AND moderated = 0 ORDER BY `id` ASC",
+                       intval($parent_id)
+               );
+
+               if (! count($items)) {
+                       return;
+               }
+
+               // avoid race condition with deleting entries
+
+               if ($items[0]['deleted']) {
+                       foreach ($items as $item) {
+                               $item['deleted'] = 1;
+                       }
+               }
+
+               if ((count($items) == 1) && ($items[0]['id'] === $target_item['id']) && ($items[0]['uri'] === $items[0]['parent-uri'])) {
+                       logger('notifier: top level post');
+                       $top_level = true;
+               }
+
+       }
+
+       $r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`,
+               `user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`,
+               `user`.`page-flags`, `user`.`prvnets`, `user`.`account-type`
+               FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`
+               WHERE `contact`.`uid` = %d AND `contact`.`self` = 1 LIMIT 1",
+               intval($uid)
+       );
+
+       if (! DBM::is_result($r)) {
+               return;
+       }
+
+       $owner = $r[0];
+
+       $walltowall = ((($top_level) && ($owner['id'] != $items[0]['contact-id'])) ? true : false);
+
+       // Should the post be transmitted to Diaspora?
+       $diaspora_delivery = true;
+
+       // If this is a public conversation, notify the feed hub
+       $public_message = true;
+
+       // Do a PuSH
+       $push_notify = false;
+
+       // Deliver directly to a forum, don't PuSH
+       $direct_forum_delivery = false;
+
+       // fill this in with a single salmon slap if applicable
+       $slap = '';
+
+       if (! ($mail || $fsuggest || $relocate)) {
+
+               $slap = ostatus::salmon($target_item,$owner);
+
+               require_once 'include/group.php';
+
+               $parent = $items[0];
+
+               $thr_parent = q("SELECT `network`, `author-link`, `owner-link` FROM `item` WHERE `uri` = '%s' AND `uid` = %d",
+                       dbesc($target_item["thr-parent"]), intval($target_item["uid"]));
+
+               logger('GUID: '.$target_item["guid"].': Parent is '.$parent['network'].'. Thread parent is '.$thr_parent[0]['network'], LOGGER_DEBUG);
+
+               // This is IMPORTANT!!!!
+
+               // We will only send a "notify owner to relay" or followup message if the referenced post
+               // originated on our system by virtue of having our hostname somewhere
+               // in the URI, AND it was a comment (not top_level) AND the parent originated elsewhere.
+
+               // if $parent['wall'] == 1 we will already have the parent message in our array
+               // and we will relay the whole lot.
+
+               // expire sends an entire group of expire messages and cannot be forwarded.
+               // However the conversation owner will be a part of the conversation and will
+               // be notified during this run.
+               // Other DFRN conversation members will be alerted during polled updates.
+
+
+
+               // Diaspora members currently are not notified of expirations, and other networks have
+               // either limited or no ability to process deletions. We should at least fix Diaspora
+               // by stringing togther an array of retractions and sending them onward.
+
+
+               $localhost = str_replace('www.','',$a->get_hostname());
+               if (strpos($localhost,':')) {
+                       $localhost = substr($localhost,0,strpos($localhost,':'));
+               }
+               /**
+                *
+                * Be VERY CAREFUL if you make any changes to the following several lines. Seemingly innocuous changes
+                * have been known to cause runaway conditions which affected several servers, along with
+                * permissions issues.
+                *
+                */
+
+               $relay_to_owner = false;
+
+               if (!$top_level && ($parent['wall'] == 0) && !$expire && (stristr($target_item['uri'],$localhost))) {
+                       $relay_to_owner = true;
+               }
+
+
+               if (($cmd === 'uplink') && (intval($parent['forum_mode']) == 1) && !$top_level) {
+                       $relay_to_owner = true;
+               }
+
+               // until the 'origin' flag has been in use for several months
+               // we will just use it as a fallback test
+               // later we will be able to use it as the primary test of whether or not to relay.
+
+               if (! $target_item['origin']) {
+                       $relay_to_owner = false;
+               }
+               if ($parent['origin']) {
+                       $relay_to_owner = false;
+               }
+
+               // Special treatment for forum posts
+               if (($target_item['author-link'] != $target_item['owner-link']) &&
+                       ($owner['id'] != $target_item['contact-id']) &&
+                       ($target_item['uri'] === $target_item['parent-uri'])) {
+
+                       $fields = array('forum', 'prv');
+                       $condition = array('id' => $target_item['contact-id']);
+                       $contact = dba::select('contact', $fields, $condition, array('limit' => 1));
+                       if (!DBM::is_result($contact)) {
+                               // Should never happen
+                               return false;
+                       }
+
+                       // Is the post from a forum?
+                       if ($contact['forum'] || $contact['prv']) {
+                               $relay_to_owner = true;
+                               $direct_forum_delivery = true;
+                       }
+               }
+               if ($relay_to_owner) {
+                       logger('notifier: followup '.$target_item["guid"], LOGGER_DEBUG);
+                       // local followup to remote post
+                       $followup = true;
+                       $public_message = false; // not public
+                       $conversant_str = dbesc($parent['contact-id']);
+                       $recipients = array($parent['contact-id']);
+                       $recipients_followup  = array($parent['contact-id']);
+
+                       //if (!$target_item['private'] && $target_item['wall'] &&
+                       if (!$target_item['private'] &&
+                               (strlen($target_item['allow_cid'].$target_item['allow_gid'].
+                                       $target_item['deny_cid'].$target_item['deny_gid']) == 0))
+                               $push_notify = true;
+
+                       if (($thr_parent && ($thr_parent[0]['network'] == NETWORK_OSTATUS)) || ($parent['network'] == NETWORK_OSTATUS)) {
+
+                               $push_notify = true;
+
+                               if ($parent["network"] == NETWORK_OSTATUS) {
+                                       // Distribute the message to the DFRN contacts as if this wasn't a followup since OStatus can't relay comments
+                                       // Currently it is work at progress
+                                       $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `network` = '%s' AND NOT `blocked` AND NOT `pending` AND NOT `archive`",
+                                               intval($uid),
+                                               dbesc(NETWORK_DFRN)
+                                       );
+                                       if (DBM::is_result($r)) {
+                                               foreach ($r as $rr) {
+                                                       $recipients_followup[] = $rr['id'];
+                                               }
+                                       }
+                               }
+                       }
+
+                       if ($direct_forum_delivery) {
+                               $push_notify = false;
+                       }
+
+                       logger("Notify ".$target_item["guid"]." via PuSH: ".($push_notify?"Yes":"No"), LOGGER_DEBUG);
+               } else {
+                       $followup = false;
+
+                       logger('Distributing directly '.$target_item["guid"], LOGGER_DEBUG);
+
+                       // don't send deletions onward for other people's stuff
+
+                       if ($target_item['deleted'] && (! intval($target_item['wall']))) {
+                               logger('notifier: ignoring delete notification for non-wall item');
+                               return;
+                       }
+
+                       if ((strlen($parent['allow_cid']))
+                               || (strlen($parent['allow_gid']))
+                               || (strlen($parent['deny_cid']))
+                               || (strlen($parent['deny_gid']))) {
+                               $public_message = false; // private recipients, not public
+                       }
+
+                       $allow_people = expand_acl($parent['allow_cid']);
+                       $allow_groups = expand_groups(expand_acl($parent['allow_gid']),true);
+                       $deny_people  = expand_acl($parent['deny_cid']);
+                       $deny_groups  = expand_groups(expand_acl($parent['deny_gid']));
+
+                       // 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', $item_id);
+                       }
+
+                       $conversants = array();
+
+                       foreach ($items as $item) {
+                               $recipients[] = $item['contact-id'];
+                               $conversants[] = $item['contact-id'];
+                               // pull out additional tagged people to notify (if public message)
+                               if ($public_message && strlen($item['inform'])) {
+                                       $people = explode(',',$item['inform']);
+                                       foreach ($people as $person) {
+                                               if (substr($person,0,4) === 'cid:') {
+                                                       $recipients[] = intval(substr($person,4));
+                                                       $conversants[] = intval(substr($person,4));
+                                               } else {
+                                                       $url_recipients[] = substr($person,4);
+                                               }
+                                       }
+                               }
+                       }
+
+                       if (count($url_recipients))
+                               logger('notifier: '.$target_item["guid"].' url_recipients ' . print_r($url_recipients,true));
+
+                       $conversants = array_unique($conversants);
+
+
+                       $recipients = array_unique(array_merge($recipients,$allow_people,$allow_groups));
+                       $deny = array_unique(array_merge($deny_people,$deny_groups));
+                       $recipients = array_diff($recipients,$deny);
+
+                       $conversant_str = dbesc(implode(', ',$conversants));
+               }
+
+               // If the thread parent is OStatus then do some magic to distribute the messages.
+               // We have not only to look at the parent, since it could be a Friendica thread.
+               if (($thr_parent && ($thr_parent[0]['network'] == NETWORK_OSTATUS)) || ($parent['network'] == NETWORK_OSTATUS)) {
+
+                       $diaspora_delivery = false;
+
+                       logger('Some parent is OStatus for '.$target_item["guid"]." - Author: ".$thr_parent[0]['author-link']." - Owner: ".$thr_parent[0]['owner-link'], LOGGER_DEBUG);
+
+                       // Send a salmon to the parent author
+                       $r = q("SELECT `url`, `notify` FROM `contact` WHERE `nurl`='%s' AND `uid` IN (0, %d) AND `notify` != ''",
+                               dbesc(normalise_link($thr_parent[0]['author-link'])),
+                               intval($uid));
+                       if (DBM::is_result($r)) {
+                               $probed_contact = $r[0];
+                       } else {
+                               $probed_contact = Probe::uri($thr_parent[0]['author-link']);
+                       }
+
+                       if ($probed_contact["notify"] != "") {
+                               logger('Notify parent author '.$probed_contact["url"].': '.$probed_contact["notify"]);
+                               $url_recipients[$probed_contact["notify"]] = $probed_contact["notify"];
+                       }
+
+                       // Send a salmon to the parent owner
+                       $r = q("SELECT `url`, `notify` FROM `contact` WHERE `nurl`='%s' AND `uid` IN (0, %d) AND `notify` != ''",
+                               dbesc(normalise_link($thr_parent[0]['owner-link'])),
+                               intval($uid));
+                       if (DBM::is_result($r)) {
+                               $probed_contact = $r[0];
+                       } else {
+                               $probed_contact = Probe::uri($thr_parent[0]['owner-link']);
+                       }
+
+                       if ($probed_contact["notify"] != "") {
+                               logger('Notify parent owner '.$probed_contact["url"].': '.$probed_contact["notify"]);
+                               $url_recipients[$probed_contact["notify"]] = $probed_contact["notify"];
+                       }
+
+                       // Send a salmon notification to every person we mentioned in the post
+                       $arr = explode(',',$target_item['tag']);
+                       foreach ($arr as $x) {
+                               //logger('Checking tag '.$x, LOGGER_DEBUG);
+                               $matches = null;
+                               if (preg_match('/@\[url=([^\]]*)\]/',$x,$matches)) {
+                                               $probed_contact = Probe::uri($matches[1]);
+                                       if ($probed_contact["notify"] != "") {
+                                               logger('Notify mentioned user '.$probed_contact["url"].': '.$probed_contact["notify"]);
+                                               $url_recipients[$probed_contact["notify"]] = $probed_contact["notify"];
+                                       }
+                               }
+                       }
+
+                       // It only makes sense to distribute answers to OStatus messages to Friendica and OStatus - but not Diaspora
+                       $sql_extra = " AND `network` IN ('".NETWORK_OSTATUS."', '".NETWORK_DFRN."')";
+               } else {
+                       $sql_extra = " AND `network` IN ('".NETWORK_OSTATUS."', '".NETWORK_DFRN."', '".NETWORK_DIASPORA."', '".NETWORK_MAIL."', '".NETWORK_MAIL2."')";
+               }
+       } else {
+               $public_message = false;
+       }
+
+       // If this is a public message and pubmail is set on the parent, include all your email contacts
+
+       $mail_disabled = ((function_exists('imap_open') && (!Config::get('system','imap_disabled'))) ? 0 : 1);
+
+       if (! $mail_disabled) {
+               if ((! strlen($target_item['allow_cid'])) && (! strlen($target_item['allow_gid']))
+                       && (! strlen($target_item['deny_cid'])) && (! strlen($target_item['deny_gid']))
+                       && (intval($target_item['pubmail']))) {
+                       $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `network` = '%s'",
+                               intval($uid),
+                               dbesc(NETWORK_MAIL)
+                       );
+                       if (DBM::is_result($r)) {
+                               foreach ($r as $rr) {
+                                       $recipients[] = $rr['id'];
+                               }
+                       }
+               }
+       }
+
+       if ($followup) {
+               $recip_str = implode(', ', $recipients_followup);
+       } else {
+               $recip_str = implode(', ', $recipients);
+       }
+       if ($relocate) {
+               $r = $recipients_relocate;
+       } else {
+               $r = q("SELECT `id`, `url`, `network`, `self` FROM `contact`
+                       WHERE `id` IN (%s) AND NOT `blocked` AND NOT `pending` AND NOT `archive`".$sql_extra,
+                       dbesc($recip_str)
+               );
+       }
+
+       // delivery loop
+
+       if (DBM::is_result($r)) {
+               foreach ($r as $contact) {
+                       if ($contact['self']) {
+                               continue;
+                       }
+                       logger("Deliver ".$target_item["guid"]." to ".$contact['url']." via network ".$contact['network'], LOGGER_DEBUG);
+
+                       Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true),
+                                       'delivery', $cmd, $item_id, (int)$contact['id']);
+               }
+       }
+
+       // send salmon slaps to mentioned remote tags (@foo@example.com) in OStatus posts
+       // They are especially used for notifications to OStatus users that don't follow us.
+
+       if ($slap && count($url_recipients) && ($public_message || $push_notify) && $normal_mode) {
+               if (!Config::get('system','dfrn_only')) {
+                       foreach ($url_recipients as $url) {
+                               if ($url) {
+                                       logger('notifier: urldelivery: ' . $url);
+                                       $deliver_status = slapper($owner,$url,$slap);
+                                       /// @TODO Redeliver/queue these items on failure, though there is no contact record
+                               }
+                       }
+               }
+       }
+
+
+       if ($public_message) {
+
+               $r0 = array();
+               $r1 = array();
+
+               if ($diaspora_delivery) {
+                       if (!$followup) {
+                               $r0 = Diaspora::relay_list();
+                       }
+
+                       $r1 = q("SELECT `batch`, ANY_VALUE(`id`) AS `id`, ANY_VALUE(`name`) AS `name`, ANY_VALUE(`network`) AS `network`
+                               FROM `contact` WHERE `network` = '%s' AND `batch` != ''
+                               AND `uid` = %d AND `rel` != %d AND NOT `blocked` AND NOT `pending` AND NOT `archive` GROUP BY `batch`",
+                               dbesc(NETWORK_DIASPORA),
+                               intval($owner['uid']),
+                               intval(CONTACT_IS_SHARING)
+                       );
+               }
+
+               $r2 = q("SELECT `id`, `name`,`network` FROM `contact`
+                       WHERE `network` in ('%s', '%s') AND `uid` = %d AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `rel` != %d",
+                       dbesc(NETWORK_DFRN),
+                       dbesc(NETWORK_MAIL2),
+                       intval($owner['uid']),
+                       intval(CONTACT_IS_SHARING)
+               );
+
+               $r = array_merge($r2,$r1,$r0);
+
+               if (DBM::is_result($r)) {
+                       logger('pubdeliver '.$target_item["guid"].': '.print_r($r,true), LOGGER_DEBUG);
+
+                       foreach ($r as $rr) {
+
+                               // except for Diaspora batch jobs
+                               // Don't deliver to folks who have already been delivered to
+
+                               if (($rr['network'] !== NETWORK_DIASPORA) && (in_array($rr['id'],$conversants))) {
+                                       logger('notifier: already delivered id=' . $rr['id']);
+                                       continue;
+                               }
+
+                               if ((! $mail) && (! $fsuggest) && (! $followup)) {
+                                       logger('notifier: delivery agent: '.$rr['name'].' '.$rr['id'].' '.$rr['network'].' '.$target_item["guid"]);
+                                       Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true),
+                                                       'delivery', $cmd, $item_id, (int)$rr['id']);
+                               }
+                       }
+               }
+
+               $push_notify = true;
+
+       }
+
+       // Notify PuSH subscribers (Used for OStatus distribution of regular posts)
+       if ($push_notify) {
+               // Set push flag for PuSH subscribers to this topic,
+               // they will be notified in queue.php
+               q("UPDATE `push_subscriber` SET `push` = 1 ".
+                 "WHERE `nickname` = '%s' AND `push` = 0", dbesc($owner['nickname']));
+
+               logger('Activating internal PuSH for item '.$item_id, LOGGER_DEBUG);
+
+               // Handling the pubsubhubbub requests
+               Worker::add(array('priority' => PRIORITY_HIGH, 'created' => $a->queue['created'], 'dont_fork' => true),
+                               'pubsubpublish');
+       }
+
+       logger('notifier: calling hooks', LOGGER_DEBUG);
+
+       if ($normal_mode) {
+               call_hooks('notifier_normal',$target_item);
+       }
+
+       call_hooks('notifier_end',$target_item);
+
+       return;
+}
diff --git a/worker/profile_update.php b/worker/profile_update.php
new file mode 100644 (file)
index 0000000..0c5de01
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+use Friendica\Protocol\Diaspora;
+
+function profile_update_run(&$argv, &$argc) {
+       if ($argc != 2) {
+               return;
+       }
+
+       $uid = intval($argv[1]);
+
+       Diaspora::send_profile($uid);
+}
diff --git a/worker/pubsubpublish.php b/worker/pubsubpublish.php
new file mode 100644 (file)
index 0000000..52a707b
--- /dev/null
@@ -0,0 +1,91 @@
+<?php
+
+use Friendica\App;
+use Friendica\Core\System;
+use Friendica\Core\Config;
+use Friendica\Core\Worker;
+use Friendica\Database\DBM;
+
+require_once('include/items.php');
+require_once('include/ostatus.php');
+
+function pubsubpublish_run(&$argv, &$argc){
+       global $a;
+
+       if ($argc > 1) {
+               $pubsubpublish_id = intval($argv[1]);
+       } else {
+               // We'll push to each subscriber that has push > 0,
+               // i.e. there has been an update (set in notifier.php).
+               $r = q("SELECT `id`, `callback_url` FROM `push_subscriber` WHERE `push` > 0 ORDER BY `last_update` DESC");
+
+               foreach ($r as $rr) {
+                       logger("Publish feed to ".$rr["callback_url"], LOGGER_DEBUG);
+                       Worker::add(array('priority' => PRIORITY_HIGH, 'created' => $a->queue['created'], 'dont_fork' => true),
+                                       'pubsubpublish', (int)$rr["id"]);
+               }
+       }
+
+       handle_pubsubhubbub($pubsubpublish_id);
+
+       return;
+}
+
+function handle_pubsubhubbub($id) {
+       global $a;
+
+       $r = q("SELECT * FROM `push_subscriber` WHERE `id` = %d", intval($id));
+       if (!DBM::is_result($r)) {
+               return;
+       }
+
+       $rr = $r[0];
+
+       /// @todo Check server status with poco_check_server()
+       // Before this can be done we need a way to safely detect the server url.
+
+       logger("Generate feed of user ".$rr['nickname']." to ".$rr['callback_url']." - last updated ".$rr['last_update'], LOGGER_DEBUG);
+
+       $last_update = $rr['last_update'];
+       $params = ostatus::feed($a, $rr['nickname'], $last_update);
+
+       if (!$params) {
+               return;
+       }
+
+       $hmac_sig = hash_hmac("sha1", $params, $rr['secret']);
+
+       $headers = array("Content-type: application/atom+xml",
+                       sprintf("Link: <%s>;rel=hub,<%s>;rel=self",
+                               System::baseUrl().'/pubsubhubbub/'.$rr['nickname'],
+                               $rr['topic']),
+                       "X-Hub-Signature: sha1=".$hmac_sig);
+
+       logger('POST '.print_r($headers, true)."\n".$params, LOGGER_DEBUG);
+
+       post_url($rr['callback_url'], $params, $headers);
+       $ret = $a->get_curl_code();
+
+       if ($ret >= 200 && $ret <= 299) {
+               logger('successfully pushed to '.$rr['callback_url']);
+
+               // set last_update to the "created" date of the last item, and reset push=0
+               q("UPDATE `push_subscriber` SET `push` = 0, last_update = '%s' WHERE id = %d",
+                       dbesc($last_update),
+                       intval($rr['id']));
+
+       } else {
+               logger('error when pushing to '.$rr['callback_url'].' HTTP: '.$ret);
+
+               // we use the push variable also as a counter, if we failed we
+               // increment this until some upper limit where we give up
+               $new_push = intval($rr['push']) + 1;
+
+               if ($new_push > 30) // OK, let's give up
+                       $new_push = 0;
+
+               q("UPDATE `push_subscriber` SET `push` = %d WHERE id = %d",
+                       $new_push,
+                       intval($rr['id']));
+       }
+}
diff --git a/worker/queue.php b/worker/queue.php
new file mode 100644 (file)
index 0000000..a56c41d
--- /dev/null
@@ -0,0 +1,191 @@
+<?php
+/**
+ * @file include/queue.php
+ */
+use Friendica\Core\Cache;
+use Friendica\Core\Config;
+use Friendica\Core\Worker;
+use Friendica\Database\DBM;
+use Friendica\Protocol\Diaspora;
+use Friendica\Protocol\DFRN;
+
+require_once 'include/queue_fn.php';
+require_once 'include/datetime.php';
+require_once 'include/items.php';
+require_once 'include/bbcode.php';
+require_once 'include/socgraph.php';
+
+function queue_run(&$argv, &$argc)
+{
+       global $a;
+
+       if ($argc > 1) {
+               $queue_id = intval($argv[1]);
+       } else {
+               $queue_id = 0;
+       }
+
+       $cachekey_deadguy = 'queue_run:deadguy:';
+       $cachekey_server = 'queue_run:server:';
+
+       if (!$queue_id) {
+               logger('queue: start');
+
+               // Handling the pubsubhubbub requests
+               Worker::add(array('priority' => PRIORITY_HIGH, 'dont_fork' => true), 'pubsubpublish');
+
+               $r = q(
+                       "SELECT `queue`.*, `contact`.`name`, `contact`.`uid` FROM `queue`
+                       INNER JOIN `contact` ON `queue`.`cid` = `contact`.`id`
+                       WHERE `queue`.`created` < UTC_TIMESTAMP() - INTERVAL 3 DAY"
+               );
+
+               if (DBM::is_result($r)) {
+                       foreach ($r as $rr) {
+                               logger('Removing expired queue item for ' . $rr['name'] . ', uid=' . $rr['uid']);
+                               logger('Expired queue data: ' . $rr['content'], LOGGER_DATA);
+                       }
+                       q("DELETE FROM `queue` WHERE `created` < UTC_TIMESTAMP() - INTERVAL 3 DAY");
+               }
+
+               /*
+                * For the first 12 hours we'll try to deliver every 15 minutes
+                * After that, we'll only attempt delivery once per hour.
+                */
+               $r = q("SELECT `id` FROM `queue` WHERE ((`created` > UTC_TIMESTAMP() - INTERVAL 12 HOUR AND `last` < UTC_TIMESTAMP() - INTERVAL 15 MINUTE) OR (`last` < UTC_TIMESTAMP() - INTERVAL 1 HOUR)) ORDER BY `cid`, `created`");
+
+               call_hooks('queue_predeliver', $a, $r);
+
+               if (DBM::is_result($r)) {
+                       foreach ($r as $q_item) {
+                               logger('Call queue for id '.$q_item['id']);
+                               Worker::add(array('priority' => PRIORITY_LOW, 'dont_fork' => true), "queue", (int)$q_item['id']);
+                       }
+               }
+               return;
+       }
+
+
+       // delivering
+
+       require_once 'include/salmon.php';
+
+       $r = q(
+               "SELECT * FROM `queue` WHERE `id` = %d LIMIT 1",
+               intval($queue_id)
+       );
+
+       if (!DBM::is_result($r)) {
+               return;
+       }
+
+       $q_item = $r[0];
+
+       $c = q(
+               "SELECT * FROM `contact` WHERE `id` = %d LIMIT 1",
+               intval($q_item['cid'])
+       );
+
+       if (!DBM::is_result($c)) {
+               remove_queue_item($q_item['id']);
+               return;
+       }
+
+       $dead = Cache::get($cachekey_deadguy.$c[0]['notify']);
+
+       if (!is_null($dead) && $dead) {
+               logger('queue: skipping known dead url: '.$c[0]['notify']);
+               update_queue_time($q_item['id']);
+               return;
+       }
+
+       $server = poco_detect_server($c[0]['url']);
+
+       if ($server != "") {
+               $vital = Cache::get($cachekey_server.$server);
+
+               if (is_null($vital)) {
+                       logger("Check server ".$server." (".$c[0]["network"].")");
+
+                       $vital = poco_check_server($server, $c[0]["network"], true);
+                       Cache::set($cachekey_server.$server, $vital, CACHE_QUARTER_HOUR);
+               }
+
+               if (!is_null($vital) && !$vital) {
+                       logger('queue: skipping dead server: '.$server);
+                       update_queue_time($q_item['id']);
+                       return;
+               }
+       }
+
+       $u = q(
+               "SELECT `user`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`
+               FROM `user` WHERE `uid` = %d LIMIT 1",
+               intval($c[0]['uid'])
+       );
+       if (!DBM::is_result($u)) {
+               remove_queue_item($q_item['id']);
+               return;
+       }
+
+       $data      = $q_item['content'];
+       $public    = $q_item['batch'];
+       $contact   = $c[0];
+       $owner     = $u[0];
+
+       $deliver_status = 0;
+
+       switch ($contact['network']) {
+               case NETWORK_DFRN:
+                       logger('queue: dfrndelivery: item '.$q_item['id'].' for '.$contact['name'].' <'.$contact['url'].'>');
+                       $deliver_status = DFRN::deliver($owner, $contact, $data);
+
+                       if ($deliver_status == (-1)) {
+                               update_queue_time($q_item['id']);
+                               Cache::set($cachekey_deadguy.$contact['notify'], true, CACHE_QUARTER_HOUR);
+                       } else {
+                               remove_queue_item($q_item['id']);
+                       }
+                       break;
+               case NETWORK_OSTATUS:
+                       if ($contact['notify']) {
+                               logger('queue: slapdelivery: item '.$q_item['id'].' for '.$contact['name'].' <'.$contact['url'].'>');
+                               $deliver_status = slapper($owner, $contact['notify'], $data);
+
+                               if ($deliver_status == (-1)) {
+                                       update_queue_time($q_item['id']);
+                                       Cache::set($cachekey_deadguy.$contact['notify'], true, CACHE_QUARTER_HOUR);
+                               } else {
+                                       remove_queue_item($q_item['id']);
+                               }
+                       }
+                       break;
+               case NETWORK_DIASPORA:
+                       if ($contact['notify']) {
+                               logger('queue: diaspora_delivery: item '.$q_item['id'].' for '.$contact['name'].' <'.$contact['url'].'>');
+                               $deliver_status = Diaspora::transmit($owner, $contact, $data, $public, true);
+
+                               if ($deliver_status == (-1)) {
+                                       update_queue_time($q_item['id']);
+                                       Cache::set($cachekey_deadguy.$contact['notify'], true, CACHE_QUARTER_HOUR);
+                               } else {
+                                       remove_queue_item($q_item['id']);
+                               }
+                       }
+                       break;
+
+               default:
+                       $params = array('owner' => $owner, 'contact' => $contact, 'queue' => $q_item, 'result' => false);
+                       call_hooks('queue_deliver', $a, $params);
+
+                       if ($params['result']) {
+                               remove_queue_item($q_item['id']);
+                       } else {
+                               update_queue_time($q_item['id']);
+                       }
+                       break;
+       }
+       logger('Deliver status '.(int)$deliver_status.' for item '.$q_item['id'].' to '.$contact['name'].' <'.$contact['url'].'>');
+
+       return;
+}
diff --git a/worker/remove_contact.php b/worker/remove_contact.php
new file mode 100644 (file)
index 0000000..9d4b1e4
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+/**
+ * @file include/remove_contact.php
+ * @brief Removes orphaned data from deleted contacts
+ */
+
+use Friendica\Core\Config;
+
+function remove_contact_run($argv, $argc) {
+       if ($argc != 2) {
+               return;
+       }
+
+       $id = intval($argv[1]);
+
+       // Only delete if the contact doesn't exist (anymore)
+       $r = dba::exists('contact', array('id' => $id));
+       if ($r) {
+               return;
+       }
+
+       // Now we delete all the depending table entries
+       dba::delete('contact', array('id' => $id));
+}
diff --git a/worker/shadowupdate.php b/worker/shadowupdate.php
new file mode 100644 (file)
index 0000000..c41b231
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+
+use Friendica\App;
+use Friendica\Core\Config;
+
+require_once("boot.php");
+require_once("include/threads.php");
+
+function shadowupdate_run(&$argv, &$argc){
+       global $a;
+
+       if (empty($a)) {
+               $a = new App(dirname(__DIR__));
+       }
+
+       @include(".htconfig.php");
+       require_once("include/dba.php");
+       dba::connect($db_host, $db_user, $db_pass, $db_data);
+       unset($db_host, $db_user, $db_pass, $db_data);
+
+       Config::load();
+
+       update_shadow_copy();
+}
+
+if (array_search(__file__,get_included_files())===0){
+       shadowupdate_run($_SERVER["argv"],$_SERVER["argc"]);
+       killme();
+}
diff --git a/worker/spool_post.php b/worker/spool_post.php
new file mode 100644 (file)
index 0000000..b7b8de3
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+/**
+ * @file include/spool_post.php
+ * @brief Posts items that wer spooled because they couldn't be posted.
+ */
+
+use Friendica\Core\Config;
+
+require_once("include/items.php");
+
+function spool_post_run($argv, $argc) {
+       global $a;
+
+       $path = get_spoolpath();
+
+       if (($path != '') && is_writable($path)){
+               if ($dh = opendir($path)) {
+                       while (($file = readdir($dh)) !== false) {
+
+                               // It is not named like a spool file, so we don't care.
+                               if (substr($file, 0, 5) != "item-") {
+                                       continue;
+                               }
+
+                               $fullfile = $path."/".$file;
+
+                               // We don't care about directories either
+                               if (filetype($fullfile) != "file") {
+                                       continue;
+                               }
+
+                               // We can't read or write the file? So we don't care about it.
+                               if (!is_writable($fullfile) || !is_readable($fullfile)) {
+                                       continue;
+                               }
+
+                               $arr = json_decode(file_get_contents($fullfile), true);
+
+                               // If it isn't an array then it is no spool file
+                               if (!is_array($arr)) {
+                                       continue;
+                               }
+
+                               // Skip if it doesn't seem to be an item array
+                               if (!isset($arr['uid']) && !isset($arr['uri']) && !isset($arr['network'])) {
+                                       continue;
+                               }
+
+                               $result = item_store($arr);
+
+                               logger("Spool file ".$file." stored: ".$result, LOGGER_DEBUG);
+                               unlink($fullfile);
+                       }
+                       closedir($dh);
+               }
+       }
+}
diff --git a/worker/tagupdate.php b/worker/tagupdate.php
new file mode 100644 (file)
index 0000000..1e97135
--- /dev/null
@@ -0,0 +1,6 @@
+<?php
+require_once("include/tags.php");
+
+function tagupdate_run(&$argv, &$argc){
+       update_items();
+}
diff --git a/worker/threadupdate.php b/worker/threadupdate.php
new file mode 100644 (file)
index 0000000..3a40286
--- /dev/null
@@ -0,0 +1,7 @@
+<?php
+require_once("include/threads.php");
+
+function threadupdate_run(&$argv, &$argc){
+       update_threads();
+       update_threads_mention();
+}
diff --git a/worker/update_gcontact.php b/worker/update_gcontact.php
new file mode 100644 (file)
index 0000000..cd7a936
--- /dev/null
@@ -0,0 +1,80 @@
+<?php
+
+use Friendica\Core\Config;
+use Friendica\Network\Probe;
+use Friendica\Database\DBM;
+
+function update_gcontact_run(&$argv, &$argc) {
+       global $a;
+
+       require_once 'include/socgraph.php';
+
+       logger('update_gcontact: start');
+
+       if (($argc > 1) && (intval($argv[1]))) {
+               $contact_id = intval($argv[1]);
+       }
+
+       if (!$contact_id) {
+               logger('update_gcontact: no contact');
+               return;
+       }
+
+       $r = q("SELECT * FROM `gcontact` WHERE `id` = %d", intval($contact_id));
+
+       if (!DBM::is_result($r)) {
+               return;
+       }
+
+       if (!in_array($r[0]["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS))) {
+               return;
+       }
+
+       $data = Probe::uri($r[0]["url"]);
+
+       if (!in_array($data["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS))) {
+               if ($r[0]["server_url"] != "")
+                       poco_check_server($r[0]["server_url"], $r[0]["network"]);
+
+               q("UPDATE `gcontact` SET `last_failure` = '%s' WHERE `id` = %d",
+                       dbesc(datetime_convert()), intval($contact_id));
+               return;
+       }
+
+       if (($data["name"] == "") && ($r[0]['name'] != ""))
+               $data["name"] = $r[0]['name'];
+
+       if (($data["nick"] == "") && ($r[0]['nick'] != ""))
+               $data["nick"] = $r[0]['nick'];
+
+       if (($data["addr"] == "") && ($r[0]['addr'] != ""))
+               $data["addr"] = $r[0]['addr'];
+
+       if (($data["photo"] == "") && ($r[0]['photo'] != ""))
+               $data["photo"] = $r[0]['photo'];
+
+
+       q("UPDATE `gcontact` SET `name` = '%s', `nick` = '%s', `addr` = '%s', `photo` = '%s'
+                               WHERE `id` = %d",
+                               dbesc($data["name"]),
+                               dbesc($data["nick"]),
+                               dbesc($data["addr"]),
+                               dbesc($data["photo"]),
+                               intval($contact_id)
+                       );
+
+       q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `addr` = '%s', `photo` = '%s'
+                               WHERE `uid` = 0 AND `addr` = '' AND `nurl` = '%s'",
+                               dbesc($data["name"]),
+                               dbesc($data["nick"]),
+                               dbesc($data["addr"]),
+                               dbesc($data["photo"]),
+                               dbesc(normalise_link($data["url"]))
+                       );
+
+       q("UPDATE `contact` SET `addr` = '%s'
+                               WHERE `uid` != 0 AND `addr` = '' AND `nurl` = '%s'",
+                               dbesc($data["addr"]),
+                               dbesc(normalise_link($data["url"]))
+                       );
+}