--- /dev/null
+<?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;
+}
--- /dev/null
+<?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);
+}
--- /dev/null
+<?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
+}
--- /dev/null
+<?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');
+ }
+}
--- /dev/null
+<?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);
+}
--- /dev/null
+<?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;
+}
--- /dev/null
+<?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']);
+ }
+ }
+}
--- /dev/null
+<?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);
+ }
+ }
+}
--- /dev/null
+<?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;
+}
--- /dev/null
+<?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;
+}
--- /dev/null
+<?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;
+}
--- /dev/null
+<?php
+use Friendica\Protocol\Diaspora;
+
+function profile_update_run(&$argv, &$argc) {
+ if ($argc != 2) {
+ return;
+ }
+
+ $uid = intval($argv[1]);
+
+ Diaspora::send_profile($uid);
+}
--- /dev/null
+<?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']));
+ }
+}
--- /dev/null
+<?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;
+}
--- /dev/null
+<?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));
+}
--- /dev/null
+<?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();
+}
--- /dev/null
+<?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);
+ }
+ }
+}
--- /dev/null
+<?php
+require_once("include/tags.php");
+
+function tagupdate_run(&$argv, &$argc){
+ update_items();
+}
--- /dev/null
+<?php
+require_once("include/threads.php");
+
+function threadupdate_run(&$argv, &$argc){
+ update_threads();
+ update_threads_mention();
+}
--- /dev/null
+<?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"]))
+ );
+}
// The script could be provided as full path or only with the function name
if ($include == basename($include)) {
- $include = "worker/".$include.".php";
+ $include = "include/".$include.".php";
}
if (!validate_include($include)) {
+++ /dev/null
-<?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;
-}
+++ /dev/null
-<?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);
-}
+++ /dev/null
-<?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
-}
+++ /dev/null
-<?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');
- }
-}
+++ /dev/null
-<?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);
-}
+++ /dev/null
-<?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;
-}
+++ /dev/null
-<?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']);
- }
- }
-}
+++ /dev/null
-<?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);
- }
- }
-}
+++ /dev/null
-<?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;
-}
+++ /dev/null
-<?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;
-}
+++ /dev/null
-<?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;
-}
+++ /dev/null
-<?php
-use Friendica\Protocol\Diaspora;
-
-function profile_update_run(&$argv, &$argc) {
- if ($argc != 2) {
- return;
- }
-
- $uid = intval($argv[1]);
-
- Diaspora::send_profile($uid);
-}
+++ /dev/null
-<?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']));
- }
-}
+++ /dev/null
-<?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;
-}
+++ /dev/null
-<?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));
-}
+++ /dev/null
-<?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();
-}
+++ /dev/null
-<?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);
- }
- }
-}
+++ /dev/null
-<?php
-require_once("include/tags.php");
-
-function tagupdate_run(&$argv, &$argc){
- update_items();
-}
+++ /dev/null
-<?php
-require_once("include/threads.php");
-
-function threadupdate_run(&$argv, &$argc){
- update_threads();
- update_threads_mention();
-}
+++ /dev/null
-<?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"]))
- );
-}