From: Michael Date: Tue, 14 Nov 2017 22:13:33 +0000 (+0000) Subject: Command back ... X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=9576f6743d79153caed60f6a81c260fc041bef06;p=friendica.git Command back ... --- diff --git a/include/checkversion.php b/include/checkversion.php new file mode 100644 index 0000000000..7d3c2de6f7 --- /dev/null +++ b/include/checkversion.php @@ -0,0 +1,46 @@ + '%s' + AND `account_expires_on` < UTC_TIMESTAMP()", dbesc(NULL_DATE)); + + // delete user records for recently removed accounts + $r = q("SELECT * FROM `user` WHERE `account_removed` AND `account_expires_on` < UTC_TIMESTAMP() - INTERVAL 3 DAY"); + if (DBM::is_result($r)) { + foreach ($r as $user) { + dba::delete('user', array('uid' => $user['uid'])); + } + } +} + +/** + * @brief Clear cache entries + * + * @param App $a + */ +function cron_clear_cache(App $a) { + + $last = Config::get('system','cache_last_cleared'); + + if ($last) { + $next = $last + (3600); // Once per hour + $clear_cache = ($next <= time()); + } else { + $clear_cache = true; + } + + if (!$clear_cache) { + return; + } + + // clear old cache + Cache::clear(); + + // clear old item cache files + clear_cache(); + + // clear cache for photos + clear_cache($a->get_basepath(), $a->get_basepath()."/photo"); + + // clear smarty cache + clear_cache($a->get_basepath()."/view/smarty3/compiled", $a->get_basepath()."/view/smarty3/compiled"); + + // clear cache for image proxy + if (!Config::get("system", "proxy_disabled")) { + clear_cache($a->get_basepath(), $a->get_basepath()."/proxy"); + + $cachetime = Config::get('system','proxy_cache_time'); + if (!$cachetime) { + $cachetime = PROXY_DEFAULT_TIME; + } + q('DELETE FROM `photo` WHERE `uid` = 0 AND `resource-id` LIKE "pic:%%" AND `created` < NOW() - INTERVAL %d SECOND', $cachetime); + } + + // Delete the cached OEmbed entries that are older than one year + q("DELETE FROM `oembed` WHERE `created` < NOW() - INTERVAL 3 MONTH"); + + // Delete the cached "parse_url" entries that are older than one year + q("DELETE FROM `parsed_url` WHERE `created` < NOW() - INTERVAL 3 MONTH"); + + // Maximum table size in megabyte + $max_tablesize = intval(Config::get('system','optimize_max_tablesize')) * 1000000; + if ($max_tablesize == 0) { + $max_tablesize = 100 * 1000000; // Default are 100 MB + } + if ($max_tablesize > 0) { + // Minimum fragmentation level in percent + $fragmentation_level = intval(Config::get('system','optimize_fragmentation')) / 100; + if ($fragmentation_level == 0) { + $fragmentation_level = 0.3; // Default value is 30% + } + + // Optimize some tables that need to be optimized + $r = q("SHOW TABLE STATUS"); + foreach ($r as $table) { + + // Don't optimize tables that are too large + if ($table["Data_length"] > $max_tablesize) { + continue; + } + + // Don't optimize empty tables + if ($table["Data_length"] == 0) { + continue; + } + + // Calculate fragmentation + $fragmentation = $table["Data_free"] / ($table["Data_length"] + $table["Index_length"]); + + logger("Table ".$table["Name"]." - Fragmentation level: ".round($fragmentation * 100, 2), LOGGER_DEBUG); + + // Don't optimize tables that needn't to be optimized + if ($fragmentation < $fragmentation_level) { + continue; + } + + // So optimize it + logger("Optimize Table ".$table["Name"], LOGGER_DEBUG); + q("OPTIMIZE TABLE `%s`", dbesc($table["Name"])); + } + } + + Config::set('system','cache_last_cleared', time()); +} + +/** + * @brief Repair missing values in Diaspora contacts + * + * @param App $a + */ +function cron_repair_diaspora(App $a) { + + $starttime = time(); + + $r = q("SELECT `id`, `url` FROM `contact` + WHERE `network` = '%s' AND (`batch` = '' OR `notify` = '' OR `poll` = '' OR pubkey = '') + ORDER BY RAND() LIMIT 50", dbesc(NETWORK_DIASPORA)); + if (!DBM::is_result($r)) { + return; + } + + foreach ($r AS $contact) { + // Quit the loop after 3 minutes + if (time() > ($starttime + 180)) { + return; + } + + if (!poco_reachable($contact["url"])) { + continue; + } + + $data = Probe::uri($contact["url"]); + if ($data["network"] != NETWORK_DIASPORA) { + continue; + } + + logger("Repair contact ".$contact["id"]." ".$contact["url"], LOGGER_DEBUG); + q("UPDATE `contact` SET `batch` = '%s', `notify` = '%s', `poll` = '%s', pubkey = '%s' WHERE `id` = %d", + dbesc($data["batch"]), dbesc($data["notify"]), dbesc($data["poll"]), dbesc($data["pubkey"]), + intval($contact["id"])); + } +} + +/** + * @brief Do some repairs in database entries + * + */ +function cron_repair_database() { + + // Sometimes there seem to be issues where the "self" contact vanishes. + // We haven't found the origin of the problem by now. + $r = q("SELECT `uid` FROM `user` WHERE NOT EXISTS (SELECT `uid` FROM `contact` WHERE `contact`.`uid` = `user`.`uid` AND `contact`.`self`)"); + if (DBM::is_result($r)) { + foreach ($r AS $user) { + logger('Create missing self contact for user '.$user['uid']); + user_create_self_contact($user['uid']); + } + } + + // Set the parent if it wasn't set. (Shouldn't happen - but does sometimes) + // This call is very "cheap" so we can do it at any time without a problem + q("UPDATE `item` INNER JOIN `item` AS `parent` ON `parent`.`uri` = `item`.`parent-uri` AND `parent`.`uid` = `item`.`uid` SET `item`.`parent` = `parent`.`id` WHERE `item`.`parent` = 0"); + + // There was an issue where the nick vanishes from the contact table + q("UPDATE `contact` INNER JOIN `user` ON `contact`.`uid` = `user`.`uid` SET `nick` = `nickname` WHERE `self` AND `nick`=''"); + + // Update the global contacts for local users + $r = q("SELECT `uid` FROM `user` WHERE `verified` AND NOT `blocked` AND NOT `account_removed` AND NOT `account_expired`"); + if (DBM::is_result($r)) { + foreach ($r AS $user) { + update_gcontact_for_user($user["uid"]); + } + } + + /// @todo + /// - remove thread entries without item + /// - remove sign entries without item + /// - remove children when parent got lost + /// - set contact-id in item when not present +} diff --git a/include/dbclean.php b/include/dbclean.php new file mode 100644 index 0000000000..1e1dd90829 --- /dev/null +++ b/include/dbclean.php @@ -0,0 +1,303 @@ + 0))) { + Worker::add(PRIORITY_LOW, 'dbclean', $i); + } + } + } else { + remove_orphans($stage); + } +} + +/** + * @brief Remove orphaned database entries + * @param integer $stage What should be deleted? + * + * Values for $stage: + * ------------------ + * 1: Old global item entries from item table without user copy. + * 2: Items without parents. + * 3: Orphaned data from thread table. + * 4: Orphaned data from notify table. + * 5: Orphaned data from notify-threads table. + * 6: Orphaned data from sign table. + * 7: Orphaned data from term table. + * 8: Expired threads. + * 9: Old global item entries from expired threads + */ +function remove_orphans($stage = 0) { + global $db; + + $count = 0; + + // We split the deletion in many small tasks + $limit = 1000; + + // Get the expire days for step 8 and 9 + $days = Config::get('system', 'dbclean-expire-days', 0); + + if ($stage == 1) { + $last_id = Config::get('system', 'dbclean-last-id-1', 0); + + logger("Deleting old global item entries from item table without user copy. Last ID: ".$last_id); + $r = dba::p("SELECT `id` FROM `item` WHERE `uid` = 0 AND + NOT EXISTS (SELECT `guid` FROM `item` AS `i` WHERE `item`.`guid` = `i`.`guid` AND `i`.`uid` != 0) AND + `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY AND `id` >= ? + ORDER BY `id` LIMIT ".intval($limit), $last_id); + $count = dba::num_rows($r); + if ($count > 0) { + logger("found global item orphans: ".$count); + while ($orphan = dba::fetch($r)) { + $last_id = $orphan["id"]; + dba::delete('item', array('id' => $orphan["id"])); + } + } else { + logger("No global item orphans found"); + } + dba::close($r); + logger("Done deleting ".$count." old global item entries from item table without user copy. Last ID: ".$last_id); + + Config::set('system', 'dbclean-last-id-1', $last_id); + } elseif ($stage == 2) { + $last_id = Config::get('system', 'dbclean-last-id-2', 0); + + logger("Deleting items without parents. Last ID: ".$last_id); + $r = dba::p("SELECT `id` FROM `item` + WHERE NOT EXISTS (SELECT `id` FROM `item` AS `i` WHERE `item`.`parent` = `i`.`id`) + AND `id` >= ? ORDER BY `id` LIMIT ".intval($limit), $last_id); + $count = dba::num_rows($r); + if ($count > 0) { + logger("found item orphans without parents: ".$count); + while ($orphan = dba::fetch($r)) { + $last_id = $orphan["id"]; + dba::delete('item', array('id' => $orphan["id"])); + } + } else { + logger("No item orphans without parents found"); + } + dba::close($r); + logger("Done deleting ".$count." items without parents. Last ID: ".$last_id); + + Config::set('system', 'dbclean-last-id-2', $last_id); + + if ($count < $limit) { + Config::set('system', 'finished-dbclean-2', true); + } + } elseif ($stage == 3) { + $last_id = Config::get('system', 'dbclean-last-id-3', 0); + + logger("Deleting orphaned data from thread table. Last ID: ".$last_id); + $r = dba::p("SELECT `iid` FROM `thread` + WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `thread`.`iid`) AND `iid` >= ? + ORDER BY `iid` LIMIT ".intval($limit), $last_id); + $count = dba::num_rows($r); + if ($count > 0) { + logger("found thread orphans: ".$count); + while ($orphan = dba::fetch($r)) { + $last_id = $orphan["iid"]; + dba::delete('thread', array('iid' => $orphan["iid"])); + } + } else { + logger("No thread orphans found"); + } + dba::close($r); + logger("Done deleting ".$count." orphaned data from thread table. Last ID: ".$last_id); + + Config::set('system', 'dbclean-last-id-3', $last_id); + + if ($count < $limit) { + Config::set('system', 'finished-dbclean-3', true); + } + } elseif ($stage == 4) { + $last_id = Config::get('system', 'dbclean-last-id-4', 0); + + logger("Deleting orphaned data from notify table. Last ID: ".$last_id); + $r = dba::p("SELECT `iid`, `id` FROM `notify` + WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `notify`.`iid`) AND `id` >= ? + ORDER BY `id` LIMIT ".intval($limit), $last_id); + $count = dba::num_rows($r); + if ($count > 0) { + logger("found notify orphans: ".$count); + while ($orphan = dba::fetch($r)) { + $last_id = $orphan["id"]; + dba::delete('notify', array('iid' => $orphan["iid"])); + } + } else { + logger("No notify orphans found"); + } + dba::close($r); + logger("Done deleting ".$count." orphaned data from notify table. Last ID: ".$last_id); + + Config::set('system', 'dbclean-last-id-4', $last_id); + + if ($count < $limit) { + Config::set('system', 'finished-dbclean-4', true); + } + } elseif ($stage == 5) { + $last_id = Config::get('system', 'dbclean-last-id-5', 0); + + logger("Deleting orphaned data from notify-threads table. Last ID: ".$last_id); + $r = dba::p("SELECT `id` FROM `notify-threads` + WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `notify-threads`.`master-parent-item`) AND `id` >= ? + ORDER BY `id` LIMIT ".intval($limit), $last_id); + $count = dba::num_rows($r); + if ($count > 0) { + logger("found notify-threads orphans: ".$count); + while ($orphan = dba::fetch($r)) { + $last_id = $orphan["id"]; + dba::delete('notify-threads', array('id' => $orphan["id"])); + } + } else { + logger("No notify-threads orphans found"); + } + dba::close($r); + logger("Done deleting ".$count." orphaned data from notify-threads table. Last ID: ".$last_id); + + Config::set('system', 'dbclean-last-id-5', $last_id); + + if ($count < $limit) { + Config::set('system', 'finished-dbclean-5', true); + } + } elseif ($stage == 6) { + $last_id = Config::get('system', 'dbclean-last-id-6', 0); + + logger("Deleting orphaned data from sign table. Last ID: ".$last_id); + $r = dba::p("SELECT `iid`, `id` FROM `sign` + WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `sign`.`iid`) AND `id` >= ? + ORDER BY `id` LIMIT ".intval($limit), $last_id); + $count = dba::num_rows($r); + if ($count > 0) { + logger("found sign orphans: ".$count); + while ($orphan = dba::fetch($r)) { + $last_id = $orphan["id"]; + dba::delete('sign', array('iid' => $orphan["iid"])); + } + } else { + logger("No sign orphans found"); + } + dba::close($r); + logger("Done deleting ".$count." orphaned data from sign table. Last ID: ".$last_id); + + Config::set('system', 'dbclean-last-id-6', $last_id); + + if ($count < $limit) { + Config::set('system', 'finished-dbclean-6', true); + } + } elseif ($stage == 7) { + $last_id = Config::get('system', 'dbclean-last-id-7', 0); + + logger("Deleting orphaned data from term table. Last ID: ".$last_id); + $r = dba::p("SELECT `oid`, `tid` FROM `term` + WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `term`.`oid`) AND `tid` >= ? + ORDER BY `tid` LIMIT ".intval($limit), $last_id); + $count = dba::num_rows($r); + if ($count > 0) { + logger("found term orphans: ".$count); + while ($orphan = dba::fetch($r)) { + $last_id = $orphan["tid"]; + dba::delete('term', array('oid' => $orphan["oid"])); + } + } else { + logger("No term orphans found"); + } + dba::close($r); + logger("Done deleting ".$count." orphaned data from term table. Last ID: ".$last_id); + + Config::set('system', 'dbclean-last-id-7', $last_id); + + if ($count < $limit) { + Config::set('system', 'finished-dbclean-7', true); + } + } elseif ($stage == 8) { + if ($days <= 0) { + return; + } + + $last_id = Config::get('system', 'dbclean-last-id-8', 0); + + logger("Deleting expired threads. Last ID: ".$last_id); + $r = dba::p("SELECT `thread`.`iid` FROM `thread` + INNER JOIN `contact` ON `thread`.`contact-id` = `contact`.`id` AND NOT `notify_new_posts` + WHERE `thread`.`received` < UTC_TIMESTAMP() - INTERVAL ? DAY + AND NOT `thread`.`mention` AND NOT `thread`.`starred` + AND NOT `thread`.`wall` AND NOT `thread`.`origin` + AND `thread`.`uid` != 0 AND `thread`.`iid` >= ? + AND NOT `thread`.`iid` IN (SELECT `parent` FROM `item` + WHERE (`item`.`starred` OR (`item`.`resource-id` != '') + OR (`item`.`file` != '') OR (`item`.`event-id` != '') + OR (`item`.`attach` != '') OR `item`.`wall` OR `item`.`origin`) + AND `item`.`parent` = `thread`.`iid`) + ORDER BY `thread`.`iid` LIMIT 1000", $days, $last_id); + $count = dba::num_rows($r); + if ($count > 0) { + logger("found expired threads: ".$count); + while ($thread = dba::fetch($r)) { + $last_id = $thread["iid"]; + dba::delete('thread', array('iid' => $thread["iid"])); + } + } else { + logger("No expired threads found"); + } + dba::close($r); + logger("Done deleting ".$count." expired threads. Last ID: ".$last_id); + + Config::set('system', 'dbclean-last-id-8', $last_id); + } elseif ($stage == 9) { + if ($days <= 0) { + return; + } + + $last_id = Config::get('system', 'dbclean-last-id-9', 0); + $till_id = Config::get('system', 'dbclean-last-id-8', 0); + + logger("Deleting old global item entries from expired threads from ID ".$last_id." to ID ".$till_id); + $r = dba::p("SELECT `id` FROM `item` WHERE `uid` = 0 AND + NOT EXISTS (SELECT `guid` FROM `item` AS `i` WHERE `item`.`guid` = `i`.`guid` AND `i`.`uid` != 0) AND + `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY AND `id` >= ? AND `id` <= ? + ORDER BY `id` LIMIT ".intval($limit), $last_id, $till_id); + $count = dba::num_rows($r); + if ($count > 0) { + logger("found global item entries from expired threads: ".$count); + while ($orphan = dba::fetch($r)) { + $last_id = $orphan["id"]; + dba::delete('item', array('id' => $orphan["id"])); + } + } else { + logger("No global item entries from expired threads"); + } + dba::close($r); + logger("Done deleting ".$count." old global item entries from expired threads. Last ID: ".$last_id); + + Config::set('system', 'dbclean-last-id-9', $last_id); + } + + // Call it again if not all entries were purged + if (($stage != 0) && ($count > 0)) { + Worker::add(PRIORITY_MEDIUM, 'dbclean'); + } +} diff --git a/include/dbupdate.php b/include/dbupdate.php new file mode 100644 index 0000000000..799ca262c8 --- /dev/null +++ b/include/dbupdate.php @@ -0,0 +1,13 @@ + UTC_TIMESTAMP() - INTERVAL 30 MINUTE", + intval($item_id) + ); + $uid = $item_id; + $item_id = 0; + if (!count($items)) { + continue; + } + } elseif ($cmd === 'suggest') { + $normal_mode = false; + $fsuggest = true; + + $suggest = q("SELECT * FROM `fsuggest` WHERE `id` = %d LIMIT 1", + intval($item_id) + ); + if (!count($suggest)) { + return; + } + $uid = $suggest[0]['uid']; + $recipients[] = $suggest[0]['cid']; + $item = $suggest[0]; + } elseif ($cmd === 'relocate') { + $normal_mode = false; + $relocate = true; + $uid = $item_id; + } else { + // find ancestors + $r = q("SELECT * FROM `item` WHERE `id` = %d AND visible = 1 AND moderated = 0 LIMIT 1", + intval($item_id) + ); + + if ((!DBM::is_result($r)) || (!intval($r[0]['parent']))) { + continue; + } + + $target_item = $r[0]; + $parent_id = intval($r[0]['parent']); + $uid = $r[0]['uid']; + $updated = $r[0]['edited']; + + $items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer` + FROM `item` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` WHERE `parent` = %d AND visible = 1 AND moderated = 0 ORDER BY `id` ASC", + intval($parent_id) + ); + + if (!count($items)) { + continue; + } + + $icontacts = null; + $contacts_arr = array(); + foreach ($items as $item) { + if (!in_array($item['contact-id'],$contacts_arr)) { + $contacts_arr[] = intval($item['contact-id']); + } + } + if (count($contacts_arr)) { + $str_contacts = implode(',',$contacts_arr); + $icontacts = q("SELECT * FROM `contact` + WHERE `id` IN ( $str_contacts ) " + ); + } + if ( !($icontacts && count($icontacts))) { + continue; + } + + // avoid race condition with deleting entries + + if ($items[0]['deleted']) { + foreach ($items as $item) { + $item['deleted'] = 1; + } + } + + // When commenting too fast after delivery, a post wasn't recognized as top level post. + // The count then showed more than one entry. The additional check should help. + // The check for the "count" should be superfluous, but I'm not totally sure by now, so we keep it. + if ((($items[0]['id'] == $item_id) || (count($items) == 1)) && ($items[0]['uri'] === $items[0]['parent-uri'])) { + logger('delivery: top level post'); + $top_level = true; + } + } + + $r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`, + `user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`, + `user`.`page-flags`, `user`.`account-type`, `user`.`prvnets` + FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid` + WHERE `contact`.`uid` = %d AND `contact`.`self` = 1 LIMIT 1", + intval($uid) + ); + + if (!DBM::is_result($r)) { + continue; + } + + $owner = $r[0]; + + $walltowall = ((($top_level) && ($owner['id'] != $items[0]['contact-id'])) ? true : false); + + $public_message = true; + + if (!($mail || $fsuggest || $relocate)) { + require_once 'include/group.php'; + + $parent = $items[0]; + + // This is IMPORTANT!!!! + + // We will only send a "notify owner to relay" or followup message if the referenced post + // originated on our system by virtue of having our hostname somewhere + // in the URI, AND it was a comment (not top_level) AND the parent originated elsewhere. + // if $parent['wall'] == 1 we will already have the parent message in our array + // and we will relay the whole lot. + + // expire sends an entire group of expire messages and cannot be forwarded. + // However the conversation owner will be a part of the conversation and will + // be notified during this run. + // Other DFRN conversation members will be alerted during polled updates. + + // Diaspora members currently are not notified of expirations, and other networks have + // either limited or no ability to process deletions. We should at least fix Diaspora + // by stringing togther an array of retractions and sending them onward. + + + $localhost = $a->get_hostname(); + if (strpos($localhost,':')) { + $localhost = substr($localhost,0,strpos($localhost,':')); + } + /** + * + * Be VERY CAREFUL if you make any changes to the following line. Seemingly innocuous changes + * have been known to cause runaway conditions which affected several servers, along with + * permissions issues. + * + */ + + $relay_to_owner = false; + + if (!$top_level && ($parent['wall'] == 0) && !$expire && stristr($target_item['uri'],$localhost)) { + $relay_to_owner = true; + } + + if ($relay_to_owner) { + logger('followup '.$target_item["guid"], LOGGER_DEBUG); + // local followup to remote post + $followup = true; + } + + if ((strlen($parent['allow_cid'])) + || (strlen($parent['allow_gid'])) + || (strlen($parent['deny_cid'])) + || (strlen($parent['deny_gid'])) + || $parent["private"]) { + $public_message = false; // private recipients, not public + } + + } + + $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `blocked` = 0 AND `pending` = 0", + intval($contact_id) + ); + + if (DBM::is_result($r)) { + $contact = $r[0]; + } + if ($contact['self']) { + continue; + } + $deliver_status = 0; + + logger("main delivery by delivery: followup=$followup mail=$mail fsuggest=$fsuggest relocate=$relocate - network ".$contact['network']); + + switch($contact['network']) { + + case NETWORK_DFRN: + logger('notifier: '.$target_item["guid"].' dfrndelivery: '.$contact['name']); + + if ($mail) { + $item['body'] = fix_private_photos($item['body'],$owner['uid'],null,$message[0]['contact-id']); + $atom = DFRN::mail($item, $owner); + } elseif ($fsuggest) { + $atom = DFRN::fsuggest($item, $owner); + q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item['id'])); + } elseif ($relocate) { + $atom = DFRN::relocate($owner, $uid); + } elseif ($followup) { + $msgitems = array(); + foreach ($items as $item) { // there is only one item + if (!$item['parent']) { + continue; + } + if ($item['id'] == $item_id) { + logger('followup: item: '. print_r($item,true), LOGGER_DATA); + $msgitems[] = $item; + } + } + $atom = DFRN::entries($msgitems,$owner); + } else { + $msgitems = array(); + foreach ($items as $item) { + if (!$item['parent']) { + continue; + } + + // private emails may be in included in public conversations. Filter them. + if ($public_message && $item['private']) { + continue; + } + + $item_contact = get_item_contact($item,$icontacts); + if (!$item_contact) { + continue; + } + + if ($normal_mode) { + if ($item_id == $item['id'] || $item['id'] == $item['parent']) { + $item["entry:comment-allow"] = true; + $item["entry:cid"] = (($top_level) ? $contact['id'] : 0); + $msgitems[] = $item; + } + } else { + $item["entry:comment-allow"] = true; + $msgitems[] = $item; + } + } + $atom = DFRN::entries($msgitems,$owner); + } + + logger('notifier entry: '.$contact["url"].' '.$target_item["guid"].' entry: '.$atom, LOGGER_DEBUG); + + logger('notifier: '.$atom, LOGGER_DATA); + $basepath = implode('/', array_slice(explode('/',$contact['url']),0,3)); + + // perform local delivery if we are on the same site + + if (link_compare($basepath,System::baseUrl())) { + + $nickname = basename($contact['url']); + if ($contact['issued-id']) { + $sql_extra = sprintf(" AND `dfrn-id` = '%s' ", dbesc($contact['issued-id'])); + } else { + $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($contact['dfrn-id'])); + } + + $x = q("SELECT `contact`.*, `contact`.`uid` AS `importer_uid`, + `contact`.`pubkey` AS `cpubkey`, + `contact`.`prvkey` AS `cprvkey`, + `contact`.`thumb` AS `thumb`, + `contact`.`url` as `url`, + `contact`.`name` as `senderName`, + `user`.* + FROM `contact` + INNER JOIN `user` ON `contact`.`uid` = `user`.`uid` + WHERE `contact`.`blocked` = 0 AND `contact`.`pending` = 0 + AND `contact`.`network` = '%s' AND `user`.`nickname` = '%s' + $sql_extra + AND `user`.`account_expired` = 0 AND `user`.`account_removed` = 0 LIMIT 1", + dbesc(NETWORK_DFRN), + dbesc($nickname) + ); + + if ($x && count($x)) { + $write_flag = ((($x[0]['rel']) && ($x[0]['rel'] != CONTACT_IS_SHARING)) ? true : false); + if ((($owner['page-flags'] == PAGE_COMMUNITY) || $write_flag) && !$x[0]['writable']) { + q("UPDATE `contact` SET `writable` = 1 WHERE `id` = %d", + intval($x[0]['id']) + ); + $x[0]['writable'] = 1; + } + + $ssl_policy = Config::get('system','ssl_policy'); + fix_contact_ssl_policy($x[0],$ssl_policy); + + // If we are setup as a soapbox we aren't accepting top level posts from this person + + if (($x[0]['page-flags'] == PAGE_SOAPBOX) && $top_level) { + break; + } + logger('mod-delivery: local delivery'); + DFRN::import($atom, $x[0]); + break; + } + } + + if (!was_recently_delayed($contact['id'])) { + $deliver_status = DFRN::deliver($owner,$contact,$atom); + } else { + $deliver_status = (-1); + } + + logger('notifier: dfrn_delivery to '.$contact["url"].' with guid '.$target_item["guid"].' returns '.$deliver_status); + + if ($deliver_status < 0) { + logger('notifier: delivery failed: queuing message'); + add_to_queue($contact['id'],NETWORK_DFRN,$atom); + + // The message could not be delivered. We mark the contact as "dead" + mark_for_death($contact); + } else { + // We successfully delivered a message, the contact is alive + unmark_for_death($contact); + } + + break; + + case NETWORK_OSTATUS: + // Do not send to otatus if we are not configured to send to public networks + if ($owner['prvnets']) { + break; + } + if (Config::get('system','ostatus_disabled') || Config::get('system','dfrn_only')) { + break; + } + + // There is currently no code here to distribute anything to OStatus. + // This is done in "notifier.php" (See "url_recipients" and "push_notify") + break; + + case NETWORK_MAIL: + case NETWORK_MAIL2: + + if (Config::get('system','dfrn_only')) { + break; + } + // WARNING: does not currently convert to RFC2047 header encodings, etc. + + $addr = $contact['addr']; + if (!strlen($addr)) { + break; + } + + if ($cmd === 'wall-new' || $cmd === 'comment-new') { + + $it = null; + if ($cmd === 'wall-new') { + $it = $items[0]; + } else { + $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval($argv[2]), + intval($uid) + ); + if (DBM::is_result($r)) + $it = $r[0]; + } + if (!$it) + break; + + + $local_user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", + intval($uid) + ); + if (!count($local_user)) + break; + + $reply_to = ''; + $r1 = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1", + intval($uid) + ); + if ($r1 && $r1[0]['reply_to']) + $reply_to = $r1[0]['reply_to']; + + $subject = (($it['title']) ? email_header_encode($it['title'],'UTF-8') : t("\x28no subject\x29")) ; + + // only expose our real email address to true friends + + if (($contact['rel'] == CONTACT_IS_FRIEND) && !$contact['blocked']) { + if ($reply_to) { + $headers = 'From: '.email_header_encode($local_user[0]['username'],'UTF-8').' <'.$reply_to.'>'."\n"; + $headers .= 'Sender: '.$local_user[0]['email']."\n"; + } else { + $headers = 'From: '.email_header_encode($local_user[0]['username'],'UTF-8').' <'.$local_user[0]['email'].'>'."\n"; + } + } else { + $headers = 'From: '. email_header_encode($local_user[0]['username'],'UTF-8') .' <'. t('noreply') .'@'.$a->get_hostname() .'>'. "\n"; + } + + //if ($reply_to) + // $headers .= 'Reply-to: '.$reply_to . "\n"; + + $headers .= 'Message-Id: <'. iri2msgid($it['uri']).'>'. "\n"; + + //logger("Mail: uri: ".$it['uri']." parent-uri ".$it['parent-uri'], LOGGER_DEBUG); + //logger("Mail: Data: ".print_r($it, true), LOGGER_DEBUG); + //logger("Mail: Data: ".print_r($it, true), LOGGER_DATA); + + if ($it['uri'] !== $it['parent-uri']) { + $headers .= "References: <".iri2msgid($it["parent-uri"]).">"; + + // If Threading is enabled, write down the correct parent + if (($it["thr-parent"] != "") && ($it["thr-parent"] != $it["parent-uri"])) + $headers .= " <".iri2msgid($it["thr-parent"]).">"; + $headers .= "\n"; + + if (!$it['title']) { + $r = q("SELECT `title` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", + dbesc($it['parent-uri']), + intval($uid)); + + if (DBM::is_result($r) && ($r[0]['title'] != '')) { + $subject = $r[0]['title']; + } else { + $r = q("SELECT `title` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d LIMIT 1", + dbesc($it['parent-uri']), + intval($uid)); + + if (DBM::is_result($r) && ($r[0]['title'] != '')) + $subject = $r[0]['title']; + } + } + if (strncasecmp($subject,'RE:',3)) + $subject = 'Re: '.$subject; + } + email_send($addr, $subject, $headers, $it); + } + break; + + case NETWORK_DIASPORA: + if ($public_message) + $loc = 'public batch '.$contact['batch']; + else + $loc = $contact['name']; + + logger('delivery: diaspora batch deliver: '.$loc); + + if (Config::get('system','dfrn_only') || (!Config::get('system','diaspora_enabled'))) + break; + + if ($mail) { + Diaspora::send_mail($item,$owner,$contact); + break; + } + + if (!$normal_mode) + break; + + if (!$contact['pubkey'] && !$public_message) + break; + + if (($target_item['deleted']) && (($target_item['uri'] === $target_item['parent-uri']) || $followup)) { + // top-level retraction + logger('diaspora retract: '.$loc); + Diaspora::send_retraction($target_item,$owner,$contact,$public_message); + break; + } elseif ($relocate) { + Diaspora::sendAccountMigration($owner, $contact, $uid); + break; + } elseif ($followup) { + // send comments and likes to owner to relay + logger('diaspora followup: '.$loc); + Diaspora::send_followup($target_item,$owner,$contact,$public_message); + break; + } elseif ($target_item['uri'] !== $target_item['parent-uri']) { + // we are the relay - send comments, likes and relayable_retractions to our conversants + logger('diaspora relay: '.$loc); + Diaspora::send_relay($target_item,$owner,$contact,$public_message); + break; + } elseif ($top_level && !$walltowall) { + // currently no workable solution for sending walltowall + logger('diaspora status: '.$loc); + Diaspora::send_status($target_item,$owner,$contact,$public_message); + break; + } + + logger('delivery: diaspora unknown mode: '.$contact['name']); + + break; + + default: + break; + } + } + + return; +} diff --git a/include/directory.php b/include/directory.php new file mode 100644 index 0000000000..f56e8dbaa4 --- /dev/null +++ b/include/directory.php @@ -0,0 +1,45 @@ + $argv[1]); + + call_hooks('globaldir_update', $arr); + + logger('Updating directory: ' . $arr['url'], LOGGER_DEBUG); + if (strlen($arr['url'])) { + fetch_url($dir . '?url=' . bin2hex($arr['url'])); + } + + return; +} + +function directory_update_all() { + $r = q("SELECT `url` FROM `contact` + INNER JOIN `profile` ON `profile`.`uid` = `contact`.`uid` + INNER JOIN `user` ON `user`.`uid` = `contact`.`uid` + WHERE `contact`.`self` AND `profile`.`net-publish` AND `profile`.`is-default` AND + NOT `user`.`account_expired` AND `user`.`verified`"); + + if (DBM::is_result($r)) { + foreach ($r AS $user) { + Worker::add(PRIORITY_LOW, 'directory', $user['url']); + } + } +} diff --git a/include/discover_poco.php b/include/discover_poco.php new file mode 100644 index 0000000000..bb8daad6f3 --- /dev/null +++ b/include/discover_poco.php @@ -0,0 +1,293 @@ +: Searches for "search pattern" in the directory. "search pattern" is url encoded. + - checkcontact: Updates gcontact entries + - suggestions: Discover other servers for their contacts. + - server : Searches for the poco server list. "poco url" is base64 encoded. + - update_server: Frequently check the first 250 servers for vitality. + - update_server_directory: Discover the given server id for their contacts + - poco_load: Load POCO data from a given POCO address + - check_profile: Update remote profile data + */ + + if (($argc > 2) && ($argv[1] == "dirsearch")) { + $search = urldecode($argv[2]); + $mode = 1; + } elseif (($argc == 2) && ($argv[1] == "checkcontact")) { + $mode = 2; + } elseif (($argc == 2) && ($argv[1] == "suggestions")) { + $mode = 3; + } elseif (($argc == 3) && ($argv[1] == "server")) { + $mode = 4; + } elseif (($argc == 2) && ($argv[1] == "update_server")) { + $mode = 5; + } elseif (($argc == 3) && ($argv[1] == "update_server_directory")) { + $mode = 6; + } elseif (($argc > 5) && ($argv[1] == "poco_load")) { + $mode = 7; + } elseif (($argc == 3) && ($argv[1] == "check_profile")) { + $mode = 8; + } elseif ($argc == 1) { + $search = ""; + $mode = 0; + } else { + die("Unknown or missing parameter ".$argv[1]."\n"); + } + + logger('start '.$search); + + if ($mode == 8) { + if ($argv[2] != "") { + poco_last_updated($argv[2], true); + } + } elseif ($mode == 7) { + if ($argc == 6) { + $url = $argv[5]; + } else { + $url = ''; + } + poco_load_worker(intval($argv[2]), intval($argv[3]), intval($argv[4]), $url); + } elseif ($mode == 6) { + poco_discover_single_server(intval($argv[2])); + } elseif ($mode == 5) { + update_server(); + } elseif ($mode == 4) { + $server_url = $argv[2]; + if ($server_url == "") { + return; + } + $server_url = filter_var($server_url, FILTER_SANITIZE_URL); + if (substr(normalise_link($server_url), 0, 7) != "http://") { + return; + } + $result = "Checking server ".$server_url." - "; + $ret = poco_check_server($server_url); + if ($ret) { + $result .= "success"; + } else { + $result .= "failed"; + } + logger($result, LOGGER_DEBUG); + } elseif ($mode == 3) { + update_suggestions(); + } elseif (($mode == 2) && Config::get('system','poco_completion')) { + discover_users(); + } elseif (($mode == 1) && ($search != "") && Config::get('system','poco_local_search')) { + discover_directory($search); + gs_search_user($search); + } elseif (($mode == 0) && ($search == "") && (Config::get('system','poco_discovery') > 0)) { + // Query Friendica and Hubzilla servers for their users + poco_discover(); + + // Query GNU Social servers for their users ("statistics" addon has to be enabled on the GS server) + if (!Config::get('system','ostatus_disabled')) + gs_discover(); + } + + logger('end '.$search); + + return; +} + +/** + * @brief Updates the first 250 servers + * + */ +function update_server() { + $r = q("SELECT `url`, `created`, `last_failure`, `last_contact` FROM `gserver` ORDER BY rand()"); + + if (!DBM::is_result($r)) { + return; + } + + $updated = 0; + + foreach ($r AS $server) { + if (!poco_do_update($server["created"], "", $server["last_failure"], $server["last_contact"])) { + continue; + } + logger('Update server status for server '.$server["url"], LOGGER_DEBUG); + + Worker::add(PRIORITY_LOW, "discover_poco", "server", $server["url"]); + + if (++$updated > 250) { + return; + } + } +} + +function discover_users() { + logger("Discover users", LOGGER_DEBUG); + + $starttime = time(); + + $users = q("SELECT `url`, `created`, `updated`, `last_failure`, `last_contact`, `server_url`, `network` FROM `gcontact` + WHERE `last_contact` < UTC_TIMESTAMP - INTERVAL 1 MONTH AND + `last_failure` < UTC_TIMESTAMP - INTERVAL 1 MONTH AND + `network` IN ('%s', '%s', '%s', '%s', '') ORDER BY rand()", + dbesc(NETWORK_DFRN), dbesc(NETWORK_DIASPORA), + dbesc(NETWORK_OSTATUS), dbesc(NETWORK_FEED)); + + if (!$users) { + return; + } + $checked = 0; + + foreach ($users AS $user) { + + $urlparts = parse_url($user["url"]); + if (!isset($urlparts["scheme"])) { + q("UPDATE `gcontact` SET `network` = '%s' WHERE `nurl` = '%s'", + dbesc(NETWORK_PHANTOM), dbesc(normalise_link($user["url"]))); + continue; + } + + if (in_array($urlparts["host"], array("www.facebook.com", "facebook.com", "twitter.com", + "identi.ca", "alpha.app.net"))) { + $networks = array("www.facebook.com" => NETWORK_FACEBOOK, + "facebook.com" => NETWORK_FACEBOOK, + "twitter.com" => NETWORK_TWITTER, + "identi.ca" => NETWORK_PUMPIO, + "alpha.app.net" => NETWORK_APPNET); + + q("UPDATE `gcontact` SET `network` = '%s' WHERE `nurl` = '%s'", + dbesc($networks[$urlparts["host"]]), dbesc(normalise_link($user["url"]))); + continue; + } + + $server_url = poco_detect_server($user["url"]); + $force_update = false; + + if ($user["server_url"] != "") { + + $force_update = (normalise_link($user["server_url"]) != normalise_link($server_url)); + + $server_url = $user["server_url"]; + } + + if ((($server_url == "") && ($user["network"] == NETWORK_FEED)) || $force_update || poco_check_server($server_url, $user["network"])) { + logger('Check profile '.$user["url"]); + Worker::add(PRIORITY_LOW, "discover_poco", "check_profile", $user["url"]); + + if (++$checked > 100) { + return; + } + } else { + q("UPDATE `gcontact` SET `last_failure` = '%s' WHERE `nurl` = '%s'", + dbesc(datetime_convert()), dbesc(normalise_link($user["url"]))); + } + + // Quit the loop after 3 minutes + if (time() > ($starttime + 180)) { + return; + } + } +} + +function discover_directory($search) { + + $data = Cache::get("dirsearch:".$search); + if (!is_null($data)) { + // Only search for the same item every 24 hours + if (time() < $data + (60 * 60 * 24)) { + logger("Already searched for ".$search." in the last 24 hours", LOGGER_DEBUG); + return; + } + } + + $x = fetch_url(get_server()."/lsearch?p=1&n=500&search=".urlencode($search)); + $j = json_decode($x); + + if (count($j->results)) { + foreach ($j->results as $jj) { + // Check if the contact already exists + $exists = q("SELECT `id`, `last_contact`, `last_failure`, `updated` FROM `gcontact` WHERE `nurl` = '%s'", normalise_link($jj->url)); + if (DBM::is_result($exists)) { + logger("Profile ".$jj->url." already exists (".$search.")", LOGGER_DEBUG); + + if (($exists[0]["last_contact"] < $exists[0]["last_failure"]) && + ($exists[0]["updated"] < $exists[0]["last_failure"])) { + continue; + } + // Update the contact + poco_last_updated($jj->url); + continue; + } + + $server_url = poco_detect_server($jj->url); + if ($server_url != '') { + if (!poco_check_server($server_url)) { + logger("Friendica server ".$server_url." doesn't answer.", LOGGER_DEBUG); + continue; + } + logger("Friendica server ".$server_url." seems to be okay.", LOGGER_DEBUG); + } + + $data = Probe::uri($jj->url); + if ($data["network"] == NETWORK_DFRN) { + logger("Profile ".$jj->url." is reachable (".$search.")", LOGGER_DEBUG); + logger("Add profile ".$jj->url." to local directory (".$search.")", LOGGER_DEBUG); + + if ($jj->tags != "") { + $data["keywords"] = $jj->tags; + } + + $data["server_url"] = $data["baseurl"]; + + update_gcontact($data); + } else { + logger("Profile ".$jj->url." is not responding or no Friendica contact - but network ".$data["network"], LOGGER_DEBUG); + } + } + } + Cache::set("dirsearch:".$search, time(), CACHE_DAY); +} + +/** + * @brief Search for GNU Social user with gstools.org + * + * @param str $search User name + */ +function gs_search_user($search) { + + // Currently disabled, since the service isn't available anymore. + // It is not removed since I hope that there will be a successor. + return false; + + $a = get_app(); + + $url = "http://gstools.org/api/users_search/".urlencode($search); + + $result = z_fetch_url($url); + if (!$result["success"]) { + return false; + } + + $contacts = json_decode($result["body"]); + + if ($contacts->status == 'ERROR') { + return false; + } + + /// @TODO AS is considered as a notation for constants (as they usually being written all upper-case) + /// @TODO find all those and convert to all lower-case which is a keyword then + foreach ($contacts->data AS $user) { + $contact = Probe::uri($user->site_address."/".$user->name); + if ($contact["network"] != NETWORK_PHANTOM) { + $contact["about"] = $user->description; + update_gcontact($contact); + } + } +} diff --git a/include/expire.php b/include/expire.php new file mode 100644 index 0000000000..7a3549ada6 --- /dev/null +++ b/include/expire.php @@ -0,0 +1,76 @@ + $row['id'])); + } + dba::close($r); + + logger('Delete expired items - done', LOGGER_DEBUG); + + // make this optional as it could have a performance impact on large sites + if (intval(Config::get('system', 'optimize_items'))) { + q("OPTIMIZE TABLE `item`"); + } + return; + } elseif (($argc == 2) && (intval($argv[1]) > 0)) { + $user = dba::select('user', array('uid', 'username', 'expire'), array('uid' => $argv[1]), array('limit' => 1)); + if (DBM::is_result($user)) { + logger('Expire items for user '.$user['uid'].' ('.$user['username'].') - interval: '.$user['expire'], LOGGER_DEBUG); + item_expire($user['uid'], $user['expire']); + logger('Expire items for user '.$user['uid'].' ('.$user['username'].') - done ', LOGGER_DEBUG); + } + return; + } elseif (($argc == 3) && ($argv[1] == 'hook') && is_array($a->hooks) && array_key_exists("expire", $a->hooks)) { + foreach ($a->hooks["expire"] as $hook) { + if ($hook[1] == $argv[2]) { + logger("Calling expire hook '" . $hook[1] . "'", LOGGER_DEBUG); + call_single_hook($a, $name, $hook, $data); + } + } + return; + } + + logger('expire: start'); + + Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true), + 'expire', 'delete'); + + $r = dba::p("SELECT `uid`, `username` FROM `user` WHERE `expire` != 0"); + while ($row = dba::fetch($r)) { + logger('Calling expiry for user '.$row['uid'].' ('.$row['username'].')', LOGGER_DEBUG); + Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true), + 'expire', (int)$row['uid']); + } + dba::close($r); + + logger('expire: calling hooks'); + + if (is_array($a->hooks) && array_key_exists('expire', $a->hooks)) { + foreach ($a->hooks['expire'] as $hook) { + logger("Calling expire hook for '" . $hook[1] . "'", LOGGER_DEBUG); + Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true), + 'expire', 'hook', $hook[1]); + } + } + + logger('expire: end'); + + return; +} diff --git a/include/gprobe.php b/include/gprobe.php new file mode 100644 index 0000000000..7003051851 --- /dev/null +++ b/include/gprobe.php @@ -0,0 +1,57 @@ + UTC_TIMESTAMP() - INTERVAL 10 MINUTE", + intval($item_id) + ); + $uid = $item_id; + $item_id = 0; + if (! count($items)) { + return; + } + } elseif ($cmd === 'suggest') { + $normal_mode = false; + $fsuggest = true; + + $suggest = q("SELECT * FROM `fsuggest` WHERE `id` = %d LIMIT 1", + intval($item_id) + ); + if (! count($suggest)) { + return; + } + $uid = $suggest[0]['uid']; + $recipients[] = $suggest[0]['cid']; + $item = $suggest[0]; + } elseif ($cmd === 'removeme') { + $r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`, + `user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`, + `user`.`page-flags`, `user`.`prvnets`, `user`.`account-type`, `user`.`guid` + FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid` + WHERE `contact`.`uid` = %d AND `contact`.`self` LIMIT 1", + intval($item_id)); + if (!$r) + return; + + $user = $r[0]; + + $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1", intval($item_id)); + if (!$r) + return; + + $self = $r[0]; + + $r = q("SELECT * FROM `contact` WHERE NOT `self` AND `uid` = %d", intval($item_id)); + if (!$r) { + return; + } + require_once 'include/Contact.php'; + foreach ($r as $contact) { + terminate_friendship($user, $self, $contact); + } + return; + } elseif ($cmd === 'relocate') { + $normal_mode = false; + $relocate = true; + $uid = $item_id; + + $recipients_relocate = q("SELECT * FROM `contact` WHERE `uid` = %d AND NOT `self` AND `network` IN ('%s', '%s')", + intval($uid), NETWORK_DFRN, NETWORK_DIASPORA); + } else { + // find ancestors + $r = q("SELECT * FROM `item` WHERE `id` = %d AND visible = 1 AND moderated = 0 LIMIT 1", + intval($item_id) + ); + + if ((! DBM::is_result($r)) || (! intval($r[0]['parent']))) { + return; + } + + $target_item = $r[0]; + $parent_id = intval($r[0]['parent']); + $uid = $r[0]['uid']; + $updated = $r[0]['edited']; + + $items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer` + FROM `item` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` WHERE `parent` = %d AND visible = 1 AND moderated = 0 ORDER BY `id` ASC", + intval($parent_id) + ); + + if (! count($items)) { + return; + } + + // avoid race condition with deleting entries + + if ($items[0]['deleted']) { + foreach ($items as $item) { + $item['deleted'] = 1; + } + } + + if ((count($items) == 1) && ($items[0]['id'] === $target_item['id']) && ($items[0]['uri'] === $items[0]['parent-uri'])) { + logger('notifier: top level post'); + $top_level = true; + } + + } + + $r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`, + `user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`, + `user`.`page-flags`, `user`.`prvnets`, `user`.`account-type` + FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid` + WHERE `contact`.`uid` = %d AND `contact`.`self` = 1 LIMIT 1", + intval($uid) + ); + + if (! DBM::is_result($r)) { + return; + } + + $owner = $r[0]; + + $walltowall = ((($top_level) && ($owner['id'] != $items[0]['contact-id'])) ? true : false); + + // Should the post be transmitted to Diaspora? + $diaspora_delivery = true; + + // If this is a public conversation, notify the feed hub + $public_message = true; + + // Do a PuSH + $push_notify = false; + + // Deliver directly to a forum, don't PuSH + $direct_forum_delivery = false; + + // fill this in with a single salmon slap if applicable + $slap = ''; + + if (! ($mail || $fsuggest || $relocate)) { + + $slap = ostatus::salmon($target_item,$owner); + + require_once 'include/group.php'; + + $parent = $items[0]; + + $thr_parent = q("SELECT `network`, `author-link`, `owner-link` FROM `item` WHERE `uri` = '%s' AND `uid` = %d", + dbesc($target_item["thr-parent"]), intval($target_item["uid"])); + + logger('GUID: '.$target_item["guid"].': Parent is '.$parent['network'].'. Thread parent is '.$thr_parent[0]['network'], LOGGER_DEBUG); + + // This is IMPORTANT!!!! + + // We will only send a "notify owner to relay" or followup message if the referenced post + // originated on our system by virtue of having our hostname somewhere + // in the URI, AND it was a comment (not top_level) AND the parent originated elsewhere. + + // if $parent['wall'] == 1 we will already have the parent message in our array + // and we will relay the whole lot. + + // expire sends an entire group of expire messages and cannot be forwarded. + // However the conversation owner will be a part of the conversation and will + // be notified during this run. + // Other DFRN conversation members will be alerted during polled updates. + + + + // Diaspora members currently are not notified of expirations, and other networks have + // either limited or no ability to process deletions. We should at least fix Diaspora + // by stringing togther an array of retractions and sending them onward. + + + $localhost = str_replace('www.','',$a->get_hostname()); + if (strpos($localhost,':')) { + $localhost = substr($localhost,0,strpos($localhost,':')); + } + /** + * + * Be VERY CAREFUL if you make any changes to the following several lines. Seemingly innocuous changes + * have been known to cause runaway conditions which affected several servers, along with + * permissions issues. + * + */ + + $relay_to_owner = false; + + if (!$top_level && ($parent['wall'] == 0) && !$expire && (stristr($target_item['uri'],$localhost))) { + $relay_to_owner = true; + } + + + if (($cmd === 'uplink') && (intval($parent['forum_mode']) == 1) && !$top_level) { + $relay_to_owner = true; + } + + // until the 'origin' flag has been in use for several months + // we will just use it as a fallback test + // later we will be able to use it as the primary test of whether or not to relay. + + if (! $target_item['origin']) { + $relay_to_owner = false; + } + if ($parent['origin']) { + $relay_to_owner = false; + } + + // Special treatment for forum posts + if (($target_item['author-link'] != $target_item['owner-link']) && + ($owner['id'] != $target_item['contact-id']) && + ($target_item['uri'] === $target_item['parent-uri'])) { + + $fields = array('forum', 'prv'); + $condition = array('id' => $target_item['contact-id']); + $contact = dba::select('contact', $fields, $condition, array('limit' => 1)); + if (!DBM::is_result($contact)) { + // Should never happen + return false; + } + + // Is the post from a forum? + if ($contact['forum'] || $contact['prv']) { + $relay_to_owner = true; + $direct_forum_delivery = true; + } + } + if ($relay_to_owner) { + logger('notifier: followup '.$target_item["guid"], LOGGER_DEBUG); + // local followup to remote post + $followup = true; + $public_message = false; // not public + $conversant_str = dbesc($parent['contact-id']); + $recipients = array($parent['contact-id']); + $recipients_followup = array($parent['contact-id']); + + //if (!$target_item['private'] && $target_item['wall'] && + if (!$target_item['private'] && + (strlen($target_item['allow_cid'].$target_item['allow_gid']. + $target_item['deny_cid'].$target_item['deny_gid']) == 0)) + $push_notify = true; + + if (($thr_parent && ($thr_parent[0]['network'] == NETWORK_OSTATUS)) || ($parent['network'] == NETWORK_OSTATUS)) { + + $push_notify = true; + + if ($parent["network"] == NETWORK_OSTATUS) { + // Distribute the message to the DFRN contacts as if this wasn't a followup since OStatus can't relay comments + // Currently it is work at progress + $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `network` = '%s' AND NOT `blocked` AND NOT `pending` AND NOT `archive`", + intval($uid), + dbesc(NETWORK_DFRN) + ); + if (DBM::is_result($r)) { + foreach ($r as $rr) { + $recipients_followup[] = $rr['id']; + } + } + } + } + + if ($direct_forum_delivery) { + $push_notify = false; + } + + logger("Notify ".$target_item["guid"]." via PuSH: ".($push_notify?"Yes":"No"), LOGGER_DEBUG); + } else { + $followup = false; + + logger('Distributing directly '.$target_item["guid"], LOGGER_DEBUG); + + // don't send deletions onward for other people's stuff + + if ($target_item['deleted'] && (! intval($target_item['wall']))) { + logger('notifier: ignoring delete notification for non-wall item'); + return; + } + + if ((strlen($parent['allow_cid'])) + || (strlen($parent['allow_gid'])) + || (strlen($parent['deny_cid'])) + || (strlen($parent['deny_gid']))) { + $public_message = false; // private recipients, not public + } + + $allow_people = expand_acl($parent['allow_cid']); + $allow_groups = expand_groups(expand_acl($parent['allow_gid']),true); + $deny_people = expand_acl($parent['deny_cid']); + $deny_groups = expand_groups(expand_acl($parent['deny_gid'])); + + // if our parent is a public forum (forum_mode == 1), uplink to the origional author causing + // a delivery fork. private groups (forum_mode == 2) do not uplink + + if ((intval($parent['forum_mode']) == 1) && (! $top_level) && ($cmd !== 'uplink')) { + Worker::add($a->queue['priority'], 'notifier', 'uplink', $item_id); + } + + $conversants = array(); + + foreach ($items as $item) { + $recipients[] = $item['contact-id']; + $conversants[] = $item['contact-id']; + // pull out additional tagged people to notify (if public message) + if ($public_message && strlen($item['inform'])) { + $people = explode(',',$item['inform']); + foreach ($people as $person) { + if (substr($person,0,4) === 'cid:') { + $recipients[] = intval(substr($person,4)); + $conversants[] = intval(substr($person,4)); + } else { + $url_recipients[] = substr($person,4); + } + } + } + } + + if (count($url_recipients)) + logger('notifier: '.$target_item["guid"].' url_recipients ' . print_r($url_recipients,true)); + + $conversants = array_unique($conversants); + + + $recipients = array_unique(array_merge($recipients,$allow_people,$allow_groups)); + $deny = array_unique(array_merge($deny_people,$deny_groups)); + $recipients = array_diff($recipients,$deny); + + $conversant_str = dbesc(implode(', ',$conversants)); + } + + // If the thread parent is OStatus then do some magic to distribute the messages. + // We have not only to look at the parent, since it could be a Friendica thread. + if (($thr_parent && ($thr_parent[0]['network'] == NETWORK_OSTATUS)) || ($parent['network'] == NETWORK_OSTATUS)) { + + $diaspora_delivery = false; + + logger('Some parent is OStatus for '.$target_item["guid"]." - Author: ".$thr_parent[0]['author-link']." - Owner: ".$thr_parent[0]['owner-link'], LOGGER_DEBUG); + + // Send a salmon to the parent author + $r = q("SELECT `url`, `notify` FROM `contact` WHERE `nurl`='%s' AND `uid` IN (0, %d) AND `notify` != ''", + dbesc(normalise_link($thr_parent[0]['author-link'])), + intval($uid)); + if (DBM::is_result($r)) { + $probed_contact = $r[0]; + } else { + $probed_contact = Probe::uri($thr_parent[0]['author-link']); + } + + if ($probed_contact["notify"] != "") { + logger('Notify parent author '.$probed_contact["url"].': '.$probed_contact["notify"]); + $url_recipients[$probed_contact["notify"]] = $probed_contact["notify"]; + } + + // Send a salmon to the parent owner + $r = q("SELECT `url`, `notify` FROM `contact` WHERE `nurl`='%s' AND `uid` IN (0, %d) AND `notify` != ''", + dbesc(normalise_link($thr_parent[0]['owner-link'])), + intval($uid)); + if (DBM::is_result($r)) { + $probed_contact = $r[0]; + } else { + $probed_contact = Probe::uri($thr_parent[0]['owner-link']); + } + + if ($probed_contact["notify"] != "") { + logger('Notify parent owner '.$probed_contact["url"].': '.$probed_contact["notify"]); + $url_recipients[$probed_contact["notify"]] = $probed_contact["notify"]; + } + + // Send a salmon notification to every person we mentioned in the post + $arr = explode(',',$target_item['tag']); + foreach ($arr as $x) { + //logger('Checking tag '.$x, LOGGER_DEBUG); + $matches = null; + if (preg_match('/@\[url=([^\]]*)\]/',$x,$matches)) { + $probed_contact = Probe::uri($matches[1]); + if ($probed_contact["notify"] != "") { + logger('Notify mentioned user '.$probed_contact["url"].': '.$probed_contact["notify"]); + $url_recipients[$probed_contact["notify"]] = $probed_contact["notify"]; + } + } + } + + // It only makes sense to distribute answers to OStatus messages to Friendica and OStatus - but not Diaspora + $sql_extra = " AND `network` IN ('".NETWORK_OSTATUS."', '".NETWORK_DFRN."')"; + } else { + $sql_extra = " AND `network` IN ('".NETWORK_OSTATUS."', '".NETWORK_DFRN."', '".NETWORK_DIASPORA."', '".NETWORK_MAIL."', '".NETWORK_MAIL2."')"; + } + } else { + $public_message = false; + } + + // If this is a public message and pubmail is set on the parent, include all your email contacts + + $mail_disabled = ((function_exists('imap_open') && (!Config::get('system','imap_disabled'))) ? 0 : 1); + + if (! $mail_disabled) { + if ((! strlen($target_item['allow_cid'])) && (! strlen($target_item['allow_gid'])) + && (! strlen($target_item['deny_cid'])) && (! strlen($target_item['deny_gid'])) + && (intval($target_item['pubmail']))) { + $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `network` = '%s'", + intval($uid), + dbesc(NETWORK_MAIL) + ); + if (DBM::is_result($r)) { + foreach ($r as $rr) { + $recipients[] = $rr['id']; + } + } + } + } + + if ($followup) { + $recip_str = implode(', ', $recipients_followup); + } else { + $recip_str = implode(', ', $recipients); + } + if ($relocate) { + $r = $recipients_relocate; + } else { + $r = q("SELECT `id`, `url`, `network`, `self` FROM `contact` + WHERE `id` IN (%s) AND NOT `blocked` AND NOT `pending` AND NOT `archive`".$sql_extra, + dbesc($recip_str) + ); + } + + // delivery loop + + if (DBM::is_result($r)) { + foreach ($r as $contact) { + if ($contact['self']) { + continue; + } + logger("Deliver ".$target_item["guid"]." to ".$contact['url']." via network ".$contact['network'], LOGGER_DEBUG); + + Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true), + 'delivery', $cmd, $item_id, (int)$contact['id']); + } + } + + // send salmon slaps to mentioned remote tags (@foo@example.com) in OStatus posts + // They are especially used for notifications to OStatus users that don't follow us. + + if ($slap && count($url_recipients) && ($public_message || $push_notify) && $normal_mode) { + if (!Config::get('system','dfrn_only')) { + foreach ($url_recipients as $url) { + if ($url) { + logger('notifier: urldelivery: ' . $url); + $deliver_status = slapper($owner,$url,$slap); + /// @TODO Redeliver/queue these items on failure, though there is no contact record + } + } + } + } + + + if ($public_message) { + + $r0 = array(); + $r1 = array(); + + if ($diaspora_delivery) { + if (!$followup) { + $r0 = Diaspora::relay_list(); + } + + $r1 = q("SELECT `batch`, ANY_VALUE(`id`) AS `id`, ANY_VALUE(`name`) AS `name`, ANY_VALUE(`network`) AS `network` + FROM `contact` WHERE `network` = '%s' AND `batch` != '' + AND `uid` = %d AND `rel` != %d AND NOT `blocked` AND NOT `pending` AND NOT `archive` GROUP BY `batch`", + dbesc(NETWORK_DIASPORA), + intval($owner['uid']), + intval(CONTACT_IS_SHARING) + ); + } + + $r2 = q("SELECT `id`, `name`,`network` FROM `contact` + WHERE `network` in ('%s', '%s') AND `uid` = %d AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `rel` != %d", + dbesc(NETWORK_DFRN), + dbesc(NETWORK_MAIL2), + intval($owner['uid']), + intval(CONTACT_IS_SHARING) + ); + + $r = array_merge($r2,$r1,$r0); + + if (DBM::is_result($r)) { + logger('pubdeliver '.$target_item["guid"].': '.print_r($r,true), LOGGER_DEBUG); + + foreach ($r as $rr) { + + // except for Diaspora batch jobs + // Don't deliver to folks who have already been delivered to + + if (($rr['network'] !== NETWORK_DIASPORA) && (in_array($rr['id'],$conversants))) { + logger('notifier: already delivered id=' . $rr['id']); + continue; + } + + if ((! $mail) && (! $fsuggest) && (! $followup)) { + logger('notifier: delivery agent: '.$rr['name'].' '.$rr['id'].' '.$rr['network'].' '.$target_item["guid"]); + Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true), + 'delivery', $cmd, $item_id, (int)$rr['id']); + } + } + } + + $push_notify = true; + + } + + // Notify PuSH subscribers (Used for OStatus distribution of regular posts) + if ($push_notify) { + // Set push flag for PuSH subscribers to this topic, + // they will be notified in queue.php + q("UPDATE `push_subscriber` SET `push` = 1 ". + "WHERE `nickname` = '%s' AND `push` = 0", dbesc($owner['nickname'])); + + logger('Activating internal PuSH for item '.$item_id, LOGGER_DEBUG); + + // Handling the pubsubhubbub requests + Worker::add(array('priority' => PRIORITY_HIGH, 'created' => $a->queue['created'], 'dont_fork' => true), + 'pubsubpublish'); + } + + logger('notifier: calling hooks', LOGGER_DEBUG); + + if ($normal_mode) { + call_hooks('notifier_normal',$target_item); + } + + call_hooks('notifier_end',$target_item); + + return; +} diff --git a/include/profile_update.php b/include/profile_update.php new file mode 100644 index 0000000000..0c5de0156d --- /dev/null +++ b/include/profile_update.php @@ -0,0 +1,12 @@ + 1) { + $pubsubpublish_id = intval($argv[1]); + } else { + // We'll push to each subscriber that has push > 0, + // i.e. there has been an update (set in notifier.php). + $r = q("SELECT `id`, `callback_url` FROM `push_subscriber` WHERE `push` > 0 ORDER BY `last_update` DESC"); + + foreach ($r as $rr) { + logger("Publish feed to ".$rr["callback_url"], LOGGER_DEBUG); + Worker::add(array('priority' => PRIORITY_HIGH, 'created' => $a->queue['created'], 'dont_fork' => true), + 'pubsubpublish', (int)$rr["id"]); + } + } + + handle_pubsubhubbub($pubsubpublish_id); + + return; +} + +function handle_pubsubhubbub($id) { + global $a; + + $r = q("SELECT * FROM `push_subscriber` WHERE `id` = %d", intval($id)); + if (!DBM::is_result($r)) { + return; + } + + $rr = $r[0]; + + /// @todo Check server status with poco_check_server() + // Before this can be done we need a way to safely detect the server url. + + logger("Generate feed of user ".$rr['nickname']." to ".$rr['callback_url']." - last updated ".$rr['last_update'], LOGGER_DEBUG); + + $last_update = $rr['last_update']; + $params = ostatus::feed($a, $rr['nickname'], $last_update); + + if (!$params) { + return; + } + + $hmac_sig = hash_hmac("sha1", $params, $rr['secret']); + + $headers = array("Content-type: application/atom+xml", + sprintf("Link: <%s>;rel=hub,<%s>;rel=self", + System::baseUrl().'/pubsubhubbub/'.$rr['nickname'], + $rr['topic']), + "X-Hub-Signature: sha1=".$hmac_sig); + + logger('POST '.print_r($headers, true)."\n".$params, LOGGER_DEBUG); + + post_url($rr['callback_url'], $params, $headers); + $ret = $a->get_curl_code(); + + if ($ret >= 200 && $ret <= 299) { + logger('successfully pushed to '.$rr['callback_url']); + + // set last_update to the "created" date of the last item, and reset push=0 + q("UPDATE `push_subscriber` SET `push` = 0, last_update = '%s' WHERE id = %d", + dbesc($last_update), + intval($rr['id'])); + + } else { + logger('error when pushing to '.$rr['callback_url'].' HTTP: '.$ret); + + // we use the push variable also as a counter, if we failed we + // increment this until some upper limit where we give up + $new_push = intval($rr['push']) + 1; + + if ($new_push > 30) // OK, let's give up + $new_push = 0; + + q("UPDATE `push_subscriber` SET `push` = %d WHERE id = %d", + $new_push, + intval($rr['id'])); + } +} diff --git a/include/queue.php b/include/queue.php new file mode 100644 index 0000000000..a56c41d97a --- /dev/null +++ b/include/queue.php @@ -0,0 +1,191 @@ + 1) { + $queue_id = intval($argv[1]); + } else { + $queue_id = 0; + } + + $cachekey_deadguy = 'queue_run:deadguy:'; + $cachekey_server = 'queue_run:server:'; + + if (!$queue_id) { + logger('queue: start'); + + // Handling the pubsubhubbub requests + Worker::add(array('priority' => PRIORITY_HIGH, 'dont_fork' => true), 'pubsubpublish'); + + $r = q( + "SELECT `queue`.*, `contact`.`name`, `contact`.`uid` FROM `queue` + INNER JOIN `contact` ON `queue`.`cid` = `contact`.`id` + WHERE `queue`.`created` < UTC_TIMESTAMP() - INTERVAL 3 DAY" + ); + + if (DBM::is_result($r)) { + foreach ($r as $rr) { + logger('Removing expired queue item for ' . $rr['name'] . ', uid=' . $rr['uid']); + logger('Expired queue data: ' . $rr['content'], LOGGER_DATA); + } + q("DELETE FROM `queue` WHERE `created` < UTC_TIMESTAMP() - INTERVAL 3 DAY"); + } + + /* + * For the first 12 hours we'll try to deliver every 15 minutes + * After that, we'll only attempt delivery once per hour. + */ + $r = q("SELECT `id` FROM `queue` WHERE ((`created` > UTC_TIMESTAMP() - INTERVAL 12 HOUR AND `last` < UTC_TIMESTAMP() - INTERVAL 15 MINUTE) OR (`last` < UTC_TIMESTAMP() - INTERVAL 1 HOUR)) ORDER BY `cid`, `created`"); + + call_hooks('queue_predeliver', $a, $r); + + if (DBM::is_result($r)) { + foreach ($r as $q_item) { + logger('Call queue for id '.$q_item['id']); + Worker::add(array('priority' => PRIORITY_LOW, 'dont_fork' => true), "queue", (int)$q_item['id']); + } + } + return; + } + + + // delivering + + require_once 'include/salmon.php'; + + $r = q( + "SELECT * FROM `queue` WHERE `id` = %d LIMIT 1", + intval($queue_id) + ); + + if (!DBM::is_result($r)) { + return; + } + + $q_item = $r[0]; + + $c = q( + "SELECT * FROM `contact` WHERE `id` = %d LIMIT 1", + intval($q_item['cid']) + ); + + if (!DBM::is_result($c)) { + remove_queue_item($q_item['id']); + return; + } + + $dead = Cache::get($cachekey_deadguy.$c[0]['notify']); + + if (!is_null($dead) && $dead) { + logger('queue: skipping known dead url: '.$c[0]['notify']); + update_queue_time($q_item['id']); + return; + } + + $server = poco_detect_server($c[0]['url']); + + if ($server != "") { + $vital = Cache::get($cachekey_server.$server); + + if (is_null($vital)) { + logger("Check server ".$server." (".$c[0]["network"].")"); + + $vital = poco_check_server($server, $c[0]["network"], true); + Cache::set($cachekey_server.$server, $vital, CACHE_QUARTER_HOUR); + } + + if (!is_null($vital) && !$vital) { + logger('queue: skipping dead server: '.$server); + update_queue_time($q_item['id']); + return; + } + } + + $u = q( + "SELECT `user`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey` + FROM `user` WHERE `uid` = %d LIMIT 1", + intval($c[0]['uid']) + ); + if (!DBM::is_result($u)) { + remove_queue_item($q_item['id']); + return; + } + + $data = $q_item['content']; + $public = $q_item['batch']; + $contact = $c[0]; + $owner = $u[0]; + + $deliver_status = 0; + + switch ($contact['network']) { + case NETWORK_DFRN: + logger('queue: dfrndelivery: item '.$q_item['id'].' for '.$contact['name'].' <'.$contact['url'].'>'); + $deliver_status = DFRN::deliver($owner, $contact, $data); + + if ($deliver_status == (-1)) { + update_queue_time($q_item['id']); + Cache::set($cachekey_deadguy.$contact['notify'], true, CACHE_QUARTER_HOUR); + } else { + remove_queue_item($q_item['id']); + } + break; + case NETWORK_OSTATUS: + if ($contact['notify']) { + logger('queue: slapdelivery: item '.$q_item['id'].' for '.$contact['name'].' <'.$contact['url'].'>'); + $deliver_status = slapper($owner, $contact['notify'], $data); + + if ($deliver_status == (-1)) { + update_queue_time($q_item['id']); + Cache::set($cachekey_deadguy.$contact['notify'], true, CACHE_QUARTER_HOUR); + } else { + remove_queue_item($q_item['id']); + } + } + break; + case NETWORK_DIASPORA: + if ($contact['notify']) { + logger('queue: diaspora_delivery: item '.$q_item['id'].' for '.$contact['name'].' <'.$contact['url'].'>'); + $deliver_status = Diaspora::transmit($owner, $contact, $data, $public, true); + + if ($deliver_status == (-1)) { + update_queue_time($q_item['id']); + Cache::set($cachekey_deadguy.$contact['notify'], true, CACHE_QUARTER_HOUR); + } else { + remove_queue_item($q_item['id']); + } + } + break; + + default: + $params = array('owner' => $owner, 'contact' => $contact, 'queue' => $q_item, 'result' => false); + call_hooks('queue_deliver', $a, $params); + + if ($params['result']) { + remove_queue_item($q_item['id']); + } else { + update_queue_time($q_item['id']); + } + break; + } + logger('Deliver status '.(int)$deliver_status.' for item '.$q_item['id'].' to '.$contact['name'].' <'.$contact['url'].'>'); + + return; +} diff --git a/include/remove_contact.php b/include/remove_contact.php new file mode 100644 index 0000000000..9d4b1e4c37 --- /dev/null +++ b/include/remove_contact.php @@ -0,0 +1,24 @@ + $id)); + if ($r) { + return; + } + + // Now we delete all the depending table entries + dba::delete('contact', array('id' => $id)); +} diff --git a/include/shadowupdate.php b/include/shadowupdate.php new file mode 100644 index 0000000000..c41b231221 --- /dev/null +++ b/include/shadowupdate.php @@ -0,0 +1,29 @@ + 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"])) + ); +} diff --git a/src/Core/Worker.php b/src/Core/Worker.php index db93adddaa..b06c4920ee 100644 --- a/src/Core/Worker.php +++ b/src/Core/Worker.php @@ -241,7 +241,7 @@ class Worker { // The script could be provided as full path or only with the function name if ($include == basename($include)) { - $include = "worker/".$include.".php"; + $include = "include/".$include.".php"; } if (!validate_include($include)) { diff --git a/worker/checkversion.php b/worker/checkversion.php deleted file mode 100644 index 7d3c2de6f7..0000000000 --- a/worker/checkversion.php +++ /dev/null @@ -1,46 +0,0 @@ - '%s' - AND `account_expires_on` < UTC_TIMESTAMP()", dbesc(NULL_DATE)); - - // delete user records for recently removed accounts - $r = q("SELECT * FROM `user` WHERE `account_removed` AND `account_expires_on` < UTC_TIMESTAMP() - INTERVAL 3 DAY"); - if (DBM::is_result($r)) { - foreach ($r as $user) { - dba::delete('user', array('uid' => $user['uid'])); - } - } -} - -/** - * @brief Clear cache entries - * - * @param App $a - */ -function cron_clear_cache(App $a) { - - $last = Config::get('system','cache_last_cleared'); - - if ($last) { - $next = $last + (3600); // Once per hour - $clear_cache = ($next <= time()); - } else { - $clear_cache = true; - } - - if (!$clear_cache) { - return; - } - - // clear old cache - Cache::clear(); - - // clear old item cache files - clear_cache(); - - // clear cache for photos - clear_cache($a->get_basepath(), $a->get_basepath()."/photo"); - - // clear smarty cache - clear_cache($a->get_basepath()."/view/smarty3/compiled", $a->get_basepath()."/view/smarty3/compiled"); - - // clear cache for image proxy - if (!Config::get("system", "proxy_disabled")) { - clear_cache($a->get_basepath(), $a->get_basepath()."/proxy"); - - $cachetime = Config::get('system','proxy_cache_time'); - if (!$cachetime) { - $cachetime = PROXY_DEFAULT_TIME; - } - q('DELETE FROM `photo` WHERE `uid` = 0 AND `resource-id` LIKE "pic:%%" AND `created` < NOW() - INTERVAL %d SECOND', $cachetime); - } - - // Delete the cached OEmbed entries that are older than one year - q("DELETE FROM `oembed` WHERE `created` < NOW() - INTERVAL 3 MONTH"); - - // Delete the cached "parse_url" entries that are older than one year - q("DELETE FROM `parsed_url` WHERE `created` < NOW() - INTERVAL 3 MONTH"); - - // Maximum table size in megabyte - $max_tablesize = intval(Config::get('system','optimize_max_tablesize')) * 1000000; - if ($max_tablesize == 0) { - $max_tablesize = 100 * 1000000; // Default are 100 MB - } - if ($max_tablesize > 0) { - // Minimum fragmentation level in percent - $fragmentation_level = intval(Config::get('system','optimize_fragmentation')) / 100; - if ($fragmentation_level == 0) { - $fragmentation_level = 0.3; // Default value is 30% - } - - // Optimize some tables that need to be optimized - $r = q("SHOW TABLE STATUS"); - foreach ($r as $table) { - - // Don't optimize tables that are too large - if ($table["Data_length"] > $max_tablesize) { - continue; - } - - // Don't optimize empty tables - if ($table["Data_length"] == 0) { - continue; - } - - // Calculate fragmentation - $fragmentation = $table["Data_free"] / ($table["Data_length"] + $table["Index_length"]); - - logger("Table ".$table["Name"]." - Fragmentation level: ".round($fragmentation * 100, 2), LOGGER_DEBUG); - - // Don't optimize tables that needn't to be optimized - if ($fragmentation < $fragmentation_level) { - continue; - } - - // So optimize it - logger("Optimize Table ".$table["Name"], LOGGER_DEBUG); - q("OPTIMIZE TABLE `%s`", dbesc($table["Name"])); - } - } - - Config::set('system','cache_last_cleared', time()); -} - -/** - * @brief Repair missing values in Diaspora contacts - * - * @param App $a - */ -function cron_repair_diaspora(App $a) { - - $starttime = time(); - - $r = q("SELECT `id`, `url` FROM `contact` - WHERE `network` = '%s' AND (`batch` = '' OR `notify` = '' OR `poll` = '' OR pubkey = '') - ORDER BY RAND() LIMIT 50", dbesc(NETWORK_DIASPORA)); - if (!DBM::is_result($r)) { - return; - } - - foreach ($r AS $contact) { - // Quit the loop after 3 minutes - if (time() > ($starttime + 180)) { - return; - } - - if (!poco_reachable($contact["url"])) { - continue; - } - - $data = Probe::uri($contact["url"]); - if ($data["network"] != NETWORK_DIASPORA) { - continue; - } - - logger("Repair contact ".$contact["id"]." ".$contact["url"], LOGGER_DEBUG); - q("UPDATE `contact` SET `batch` = '%s', `notify` = '%s', `poll` = '%s', pubkey = '%s' WHERE `id` = %d", - dbesc($data["batch"]), dbesc($data["notify"]), dbesc($data["poll"]), dbesc($data["pubkey"]), - intval($contact["id"])); - } -} - -/** - * @brief Do some repairs in database entries - * - */ -function cron_repair_database() { - - // Sometimes there seem to be issues where the "self" contact vanishes. - // We haven't found the origin of the problem by now. - $r = q("SELECT `uid` FROM `user` WHERE NOT EXISTS (SELECT `uid` FROM `contact` WHERE `contact`.`uid` = `user`.`uid` AND `contact`.`self`)"); - if (DBM::is_result($r)) { - foreach ($r AS $user) { - logger('Create missing self contact for user '.$user['uid']); - user_create_self_contact($user['uid']); - } - } - - // Set the parent if it wasn't set. (Shouldn't happen - but does sometimes) - // This call is very "cheap" so we can do it at any time without a problem - q("UPDATE `item` INNER JOIN `item` AS `parent` ON `parent`.`uri` = `item`.`parent-uri` AND `parent`.`uid` = `item`.`uid` SET `item`.`parent` = `parent`.`id` WHERE `item`.`parent` = 0"); - - // There was an issue where the nick vanishes from the contact table - q("UPDATE `contact` INNER JOIN `user` ON `contact`.`uid` = `user`.`uid` SET `nick` = `nickname` WHERE `self` AND `nick`=''"); - - // Update the global contacts for local users - $r = q("SELECT `uid` FROM `user` WHERE `verified` AND NOT `blocked` AND NOT `account_removed` AND NOT `account_expired`"); - if (DBM::is_result($r)) { - foreach ($r AS $user) { - update_gcontact_for_user($user["uid"]); - } - } - - /// @todo - /// - remove thread entries without item - /// - remove sign entries without item - /// - remove children when parent got lost - /// - set contact-id in item when not present -} diff --git a/worker/dbclean.php b/worker/dbclean.php deleted file mode 100644 index 1e1dd90829..0000000000 --- a/worker/dbclean.php +++ /dev/null @@ -1,303 +0,0 @@ - 0))) { - Worker::add(PRIORITY_LOW, 'dbclean', $i); - } - } - } else { - remove_orphans($stage); - } -} - -/** - * @brief Remove orphaned database entries - * @param integer $stage What should be deleted? - * - * Values for $stage: - * ------------------ - * 1: Old global item entries from item table without user copy. - * 2: Items without parents. - * 3: Orphaned data from thread table. - * 4: Orphaned data from notify table. - * 5: Orphaned data from notify-threads table. - * 6: Orphaned data from sign table. - * 7: Orphaned data from term table. - * 8: Expired threads. - * 9: Old global item entries from expired threads - */ -function remove_orphans($stage = 0) { - global $db; - - $count = 0; - - // We split the deletion in many small tasks - $limit = 1000; - - // Get the expire days for step 8 and 9 - $days = Config::get('system', 'dbclean-expire-days', 0); - - if ($stage == 1) { - $last_id = Config::get('system', 'dbclean-last-id-1', 0); - - logger("Deleting old global item entries from item table without user copy. Last ID: ".$last_id); - $r = dba::p("SELECT `id` FROM `item` WHERE `uid` = 0 AND - NOT EXISTS (SELECT `guid` FROM `item` AS `i` WHERE `item`.`guid` = `i`.`guid` AND `i`.`uid` != 0) AND - `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY AND `id` >= ? - ORDER BY `id` LIMIT ".intval($limit), $last_id); - $count = dba::num_rows($r); - if ($count > 0) { - logger("found global item orphans: ".$count); - while ($orphan = dba::fetch($r)) { - $last_id = $orphan["id"]; - dba::delete('item', array('id' => $orphan["id"])); - } - } else { - logger("No global item orphans found"); - } - dba::close($r); - logger("Done deleting ".$count." old global item entries from item table without user copy. Last ID: ".$last_id); - - Config::set('system', 'dbclean-last-id-1', $last_id); - } elseif ($stage == 2) { - $last_id = Config::get('system', 'dbclean-last-id-2', 0); - - logger("Deleting items without parents. Last ID: ".$last_id); - $r = dba::p("SELECT `id` FROM `item` - WHERE NOT EXISTS (SELECT `id` FROM `item` AS `i` WHERE `item`.`parent` = `i`.`id`) - AND `id` >= ? ORDER BY `id` LIMIT ".intval($limit), $last_id); - $count = dba::num_rows($r); - if ($count > 0) { - logger("found item orphans without parents: ".$count); - while ($orphan = dba::fetch($r)) { - $last_id = $orphan["id"]; - dba::delete('item', array('id' => $orphan["id"])); - } - } else { - logger("No item orphans without parents found"); - } - dba::close($r); - logger("Done deleting ".$count." items without parents. Last ID: ".$last_id); - - Config::set('system', 'dbclean-last-id-2', $last_id); - - if ($count < $limit) { - Config::set('system', 'finished-dbclean-2', true); - } - } elseif ($stage == 3) { - $last_id = Config::get('system', 'dbclean-last-id-3', 0); - - logger("Deleting orphaned data from thread table. Last ID: ".$last_id); - $r = dba::p("SELECT `iid` FROM `thread` - WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `thread`.`iid`) AND `iid` >= ? - ORDER BY `iid` LIMIT ".intval($limit), $last_id); - $count = dba::num_rows($r); - if ($count > 0) { - logger("found thread orphans: ".$count); - while ($orphan = dba::fetch($r)) { - $last_id = $orphan["iid"]; - dba::delete('thread', array('iid' => $orphan["iid"])); - } - } else { - logger("No thread orphans found"); - } - dba::close($r); - logger("Done deleting ".$count." orphaned data from thread table. Last ID: ".$last_id); - - Config::set('system', 'dbclean-last-id-3', $last_id); - - if ($count < $limit) { - Config::set('system', 'finished-dbclean-3', true); - } - } elseif ($stage == 4) { - $last_id = Config::get('system', 'dbclean-last-id-4', 0); - - logger("Deleting orphaned data from notify table. Last ID: ".$last_id); - $r = dba::p("SELECT `iid`, `id` FROM `notify` - WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `notify`.`iid`) AND `id` >= ? - ORDER BY `id` LIMIT ".intval($limit), $last_id); - $count = dba::num_rows($r); - if ($count > 0) { - logger("found notify orphans: ".$count); - while ($orphan = dba::fetch($r)) { - $last_id = $orphan["id"]; - dba::delete('notify', array('iid' => $orphan["iid"])); - } - } else { - logger("No notify orphans found"); - } - dba::close($r); - logger("Done deleting ".$count." orphaned data from notify table. Last ID: ".$last_id); - - Config::set('system', 'dbclean-last-id-4', $last_id); - - if ($count < $limit) { - Config::set('system', 'finished-dbclean-4', true); - } - } elseif ($stage == 5) { - $last_id = Config::get('system', 'dbclean-last-id-5', 0); - - logger("Deleting orphaned data from notify-threads table. Last ID: ".$last_id); - $r = dba::p("SELECT `id` FROM `notify-threads` - WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `notify-threads`.`master-parent-item`) AND `id` >= ? - ORDER BY `id` LIMIT ".intval($limit), $last_id); - $count = dba::num_rows($r); - if ($count > 0) { - logger("found notify-threads orphans: ".$count); - while ($orphan = dba::fetch($r)) { - $last_id = $orphan["id"]; - dba::delete('notify-threads', array('id' => $orphan["id"])); - } - } else { - logger("No notify-threads orphans found"); - } - dba::close($r); - logger("Done deleting ".$count." orphaned data from notify-threads table. Last ID: ".$last_id); - - Config::set('system', 'dbclean-last-id-5', $last_id); - - if ($count < $limit) { - Config::set('system', 'finished-dbclean-5', true); - } - } elseif ($stage == 6) { - $last_id = Config::get('system', 'dbclean-last-id-6', 0); - - logger("Deleting orphaned data from sign table. Last ID: ".$last_id); - $r = dba::p("SELECT `iid`, `id` FROM `sign` - WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `sign`.`iid`) AND `id` >= ? - ORDER BY `id` LIMIT ".intval($limit), $last_id); - $count = dba::num_rows($r); - if ($count > 0) { - logger("found sign orphans: ".$count); - while ($orphan = dba::fetch($r)) { - $last_id = $orphan["id"]; - dba::delete('sign', array('iid' => $orphan["iid"])); - } - } else { - logger("No sign orphans found"); - } - dba::close($r); - logger("Done deleting ".$count." orphaned data from sign table. Last ID: ".$last_id); - - Config::set('system', 'dbclean-last-id-6', $last_id); - - if ($count < $limit) { - Config::set('system', 'finished-dbclean-6', true); - } - } elseif ($stage == 7) { - $last_id = Config::get('system', 'dbclean-last-id-7', 0); - - logger("Deleting orphaned data from term table. Last ID: ".$last_id); - $r = dba::p("SELECT `oid`, `tid` FROM `term` - WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `term`.`oid`) AND `tid` >= ? - ORDER BY `tid` LIMIT ".intval($limit), $last_id); - $count = dba::num_rows($r); - if ($count > 0) { - logger("found term orphans: ".$count); - while ($orphan = dba::fetch($r)) { - $last_id = $orphan["tid"]; - dba::delete('term', array('oid' => $orphan["oid"])); - } - } else { - logger("No term orphans found"); - } - dba::close($r); - logger("Done deleting ".$count." orphaned data from term table. Last ID: ".$last_id); - - Config::set('system', 'dbclean-last-id-7', $last_id); - - if ($count < $limit) { - Config::set('system', 'finished-dbclean-7', true); - } - } elseif ($stage == 8) { - if ($days <= 0) { - return; - } - - $last_id = Config::get('system', 'dbclean-last-id-8', 0); - - logger("Deleting expired threads. Last ID: ".$last_id); - $r = dba::p("SELECT `thread`.`iid` FROM `thread` - INNER JOIN `contact` ON `thread`.`contact-id` = `contact`.`id` AND NOT `notify_new_posts` - WHERE `thread`.`received` < UTC_TIMESTAMP() - INTERVAL ? DAY - AND NOT `thread`.`mention` AND NOT `thread`.`starred` - AND NOT `thread`.`wall` AND NOT `thread`.`origin` - AND `thread`.`uid` != 0 AND `thread`.`iid` >= ? - AND NOT `thread`.`iid` IN (SELECT `parent` FROM `item` - WHERE (`item`.`starred` OR (`item`.`resource-id` != '') - OR (`item`.`file` != '') OR (`item`.`event-id` != '') - OR (`item`.`attach` != '') OR `item`.`wall` OR `item`.`origin`) - AND `item`.`parent` = `thread`.`iid`) - ORDER BY `thread`.`iid` LIMIT 1000", $days, $last_id); - $count = dba::num_rows($r); - if ($count > 0) { - logger("found expired threads: ".$count); - while ($thread = dba::fetch($r)) { - $last_id = $thread["iid"]; - dba::delete('thread', array('iid' => $thread["iid"])); - } - } else { - logger("No expired threads found"); - } - dba::close($r); - logger("Done deleting ".$count." expired threads. Last ID: ".$last_id); - - Config::set('system', 'dbclean-last-id-8', $last_id); - } elseif ($stage == 9) { - if ($days <= 0) { - return; - } - - $last_id = Config::get('system', 'dbclean-last-id-9', 0); - $till_id = Config::get('system', 'dbclean-last-id-8', 0); - - logger("Deleting old global item entries from expired threads from ID ".$last_id." to ID ".$till_id); - $r = dba::p("SELECT `id` FROM `item` WHERE `uid` = 0 AND - NOT EXISTS (SELECT `guid` FROM `item` AS `i` WHERE `item`.`guid` = `i`.`guid` AND `i`.`uid` != 0) AND - `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY AND `id` >= ? AND `id` <= ? - ORDER BY `id` LIMIT ".intval($limit), $last_id, $till_id); - $count = dba::num_rows($r); - if ($count > 0) { - logger("found global item entries from expired threads: ".$count); - while ($orphan = dba::fetch($r)) { - $last_id = $orphan["id"]; - dba::delete('item', array('id' => $orphan["id"])); - } - } else { - logger("No global item entries from expired threads"); - } - dba::close($r); - logger("Done deleting ".$count." old global item entries from expired threads. Last ID: ".$last_id); - - Config::set('system', 'dbclean-last-id-9', $last_id); - } - - // Call it again if not all entries were purged - if (($stage != 0) && ($count > 0)) { - Worker::add(PRIORITY_MEDIUM, 'dbclean'); - } -} diff --git a/worker/dbupdate.php b/worker/dbupdate.php deleted file mode 100644 index 799ca262c8..0000000000 --- a/worker/dbupdate.php +++ /dev/null @@ -1,13 +0,0 @@ - UTC_TIMESTAMP() - INTERVAL 30 MINUTE", - intval($item_id) - ); - $uid = $item_id; - $item_id = 0; - if (!count($items)) { - continue; - } - } elseif ($cmd === 'suggest') { - $normal_mode = false; - $fsuggest = true; - - $suggest = q("SELECT * FROM `fsuggest` WHERE `id` = %d LIMIT 1", - intval($item_id) - ); - if (!count($suggest)) { - return; - } - $uid = $suggest[0]['uid']; - $recipients[] = $suggest[0]['cid']; - $item = $suggest[0]; - } elseif ($cmd === 'relocate') { - $normal_mode = false; - $relocate = true; - $uid = $item_id; - } else { - // find ancestors - $r = q("SELECT * FROM `item` WHERE `id` = %d AND visible = 1 AND moderated = 0 LIMIT 1", - intval($item_id) - ); - - if ((!DBM::is_result($r)) || (!intval($r[0]['parent']))) { - continue; - } - - $target_item = $r[0]; - $parent_id = intval($r[0]['parent']); - $uid = $r[0]['uid']; - $updated = $r[0]['edited']; - - $items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer` - FROM `item` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` WHERE `parent` = %d AND visible = 1 AND moderated = 0 ORDER BY `id` ASC", - intval($parent_id) - ); - - if (!count($items)) { - continue; - } - - $icontacts = null; - $contacts_arr = array(); - foreach ($items as $item) { - if (!in_array($item['contact-id'],$contacts_arr)) { - $contacts_arr[] = intval($item['contact-id']); - } - } - if (count($contacts_arr)) { - $str_contacts = implode(',',$contacts_arr); - $icontacts = q("SELECT * FROM `contact` - WHERE `id` IN ( $str_contacts ) " - ); - } - if ( !($icontacts && count($icontacts))) { - continue; - } - - // avoid race condition with deleting entries - - if ($items[0]['deleted']) { - foreach ($items as $item) { - $item['deleted'] = 1; - } - } - - // When commenting too fast after delivery, a post wasn't recognized as top level post. - // The count then showed more than one entry. The additional check should help. - // The check for the "count" should be superfluous, but I'm not totally sure by now, so we keep it. - if ((($items[0]['id'] == $item_id) || (count($items) == 1)) && ($items[0]['uri'] === $items[0]['parent-uri'])) { - logger('delivery: top level post'); - $top_level = true; - } - } - - $r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`, - `user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`, - `user`.`page-flags`, `user`.`account-type`, `user`.`prvnets` - FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid` - WHERE `contact`.`uid` = %d AND `contact`.`self` = 1 LIMIT 1", - intval($uid) - ); - - if (!DBM::is_result($r)) { - continue; - } - - $owner = $r[0]; - - $walltowall = ((($top_level) && ($owner['id'] != $items[0]['contact-id'])) ? true : false); - - $public_message = true; - - if (!($mail || $fsuggest || $relocate)) { - require_once 'include/group.php'; - - $parent = $items[0]; - - // This is IMPORTANT!!!! - - // We will only send a "notify owner to relay" or followup message if the referenced post - // originated on our system by virtue of having our hostname somewhere - // in the URI, AND it was a comment (not top_level) AND the parent originated elsewhere. - // if $parent['wall'] == 1 we will already have the parent message in our array - // and we will relay the whole lot. - - // expire sends an entire group of expire messages and cannot be forwarded. - // However the conversation owner will be a part of the conversation and will - // be notified during this run. - // Other DFRN conversation members will be alerted during polled updates. - - // Diaspora members currently are not notified of expirations, and other networks have - // either limited or no ability to process deletions. We should at least fix Diaspora - // by stringing togther an array of retractions and sending them onward. - - - $localhost = $a->get_hostname(); - if (strpos($localhost,':')) { - $localhost = substr($localhost,0,strpos($localhost,':')); - } - /** - * - * Be VERY CAREFUL if you make any changes to the following line. Seemingly innocuous changes - * have been known to cause runaway conditions which affected several servers, along with - * permissions issues. - * - */ - - $relay_to_owner = false; - - if (!$top_level && ($parent['wall'] == 0) && !$expire && stristr($target_item['uri'],$localhost)) { - $relay_to_owner = true; - } - - if ($relay_to_owner) { - logger('followup '.$target_item["guid"], LOGGER_DEBUG); - // local followup to remote post - $followup = true; - } - - if ((strlen($parent['allow_cid'])) - || (strlen($parent['allow_gid'])) - || (strlen($parent['deny_cid'])) - || (strlen($parent['deny_gid'])) - || $parent["private"]) { - $public_message = false; // private recipients, not public - } - - } - - $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `blocked` = 0 AND `pending` = 0", - intval($contact_id) - ); - - if (DBM::is_result($r)) { - $contact = $r[0]; - } - if ($contact['self']) { - continue; - } - $deliver_status = 0; - - logger("main delivery by delivery: followup=$followup mail=$mail fsuggest=$fsuggest relocate=$relocate - network ".$contact['network']); - - switch($contact['network']) { - - case NETWORK_DFRN: - logger('notifier: '.$target_item["guid"].' dfrndelivery: '.$contact['name']); - - if ($mail) { - $item['body'] = fix_private_photos($item['body'],$owner['uid'],null,$message[0]['contact-id']); - $atom = DFRN::mail($item, $owner); - } elseif ($fsuggest) { - $atom = DFRN::fsuggest($item, $owner); - q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item['id'])); - } elseif ($relocate) { - $atom = DFRN::relocate($owner, $uid); - } elseif ($followup) { - $msgitems = array(); - foreach ($items as $item) { // there is only one item - if (!$item['parent']) { - continue; - } - if ($item['id'] == $item_id) { - logger('followup: item: '. print_r($item,true), LOGGER_DATA); - $msgitems[] = $item; - } - } - $atom = DFRN::entries($msgitems,$owner); - } else { - $msgitems = array(); - foreach ($items as $item) { - if (!$item['parent']) { - continue; - } - - // private emails may be in included in public conversations. Filter them. - if ($public_message && $item['private']) { - continue; - } - - $item_contact = get_item_contact($item,$icontacts); - if (!$item_contact) { - continue; - } - - if ($normal_mode) { - if ($item_id == $item['id'] || $item['id'] == $item['parent']) { - $item["entry:comment-allow"] = true; - $item["entry:cid"] = (($top_level) ? $contact['id'] : 0); - $msgitems[] = $item; - } - } else { - $item["entry:comment-allow"] = true; - $msgitems[] = $item; - } - } - $atom = DFRN::entries($msgitems,$owner); - } - - logger('notifier entry: '.$contact["url"].' '.$target_item["guid"].' entry: '.$atom, LOGGER_DEBUG); - - logger('notifier: '.$atom, LOGGER_DATA); - $basepath = implode('/', array_slice(explode('/',$contact['url']),0,3)); - - // perform local delivery if we are on the same site - - if (link_compare($basepath,System::baseUrl())) { - - $nickname = basename($contact['url']); - if ($contact['issued-id']) { - $sql_extra = sprintf(" AND `dfrn-id` = '%s' ", dbesc($contact['issued-id'])); - } else { - $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($contact['dfrn-id'])); - } - - $x = q("SELECT `contact`.*, `contact`.`uid` AS `importer_uid`, - `contact`.`pubkey` AS `cpubkey`, - `contact`.`prvkey` AS `cprvkey`, - `contact`.`thumb` AS `thumb`, - `contact`.`url` as `url`, - `contact`.`name` as `senderName`, - `user`.* - FROM `contact` - INNER JOIN `user` ON `contact`.`uid` = `user`.`uid` - WHERE `contact`.`blocked` = 0 AND `contact`.`pending` = 0 - AND `contact`.`network` = '%s' AND `user`.`nickname` = '%s' - $sql_extra - AND `user`.`account_expired` = 0 AND `user`.`account_removed` = 0 LIMIT 1", - dbesc(NETWORK_DFRN), - dbesc($nickname) - ); - - if ($x && count($x)) { - $write_flag = ((($x[0]['rel']) && ($x[0]['rel'] != CONTACT_IS_SHARING)) ? true : false); - if ((($owner['page-flags'] == PAGE_COMMUNITY) || $write_flag) && !$x[0]['writable']) { - q("UPDATE `contact` SET `writable` = 1 WHERE `id` = %d", - intval($x[0]['id']) - ); - $x[0]['writable'] = 1; - } - - $ssl_policy = Config::get('system','ssl_policy'); - fix_contact_ssl_policy($x[0],$ssl_policy); - - // If we are setup as a soapbox we aren't accepting top level posts from this person - - if (($x[0]['page-flags'] == PAGE_SOAPBOX) && $top_level) { - break; - } - logger('mod-delivery: local delivery'); - DFRN::import($atom, $x[0]); - break; - } - } - - if (!was_recently_delayed($contact['id'])) { - $deliver_status = DFRN::deliver($owner,$contact,$atom); - } else { - $deliver_status = (-1); - } - - logger('notifier: dfrn_delivery to '.$contact["url"].' with guid '.$target_item["guid"].' returns '.$deliver_status); - - if ($deliver_status < 0) { - logger('notifier: delivery failed: queuing message'); - add_to_queue($contact['id'],NETWORK_DFRN,$atom); - - // The message could not be delivered. We mark the contact as "dead" - mark_for_death($contact); - } else { - // We successfully delivered a message, the contact is alive - unmark_for_death($contact); - } - - break; - - case NETWORK_OSTATUS: - // Do not send to otatus if we are not configured to send to public networks - if ($owner['prvnets']) { - break; - } - if (Config::get('system','ostatus_disabled') || Config::get('system','dfrn_only')) { - break; - } - - // There is currently no code here to distribute anything to OStatus. - // This is done in "notifier.php" (See "url_recipients" and "push_notify") - break; - - case NETWORK_MAIL: - case NETWORK_MAIL2: - - if (Config::get('system','dfrn_only')) { - break; - } - // WARNING: does not currently convert to RFC2047 header encodings, etc. - - $addr = $contact['addr']; - if (!strlen($addr)) { - break; - } - - if ($cmd === 'wall-new' || $cmd === 'comment-new') { - - $it = null; - if ($cmd === 'wall-new') { - $it = $items[0]; - } else { - $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($argv[2]), - intval($uid) - ); - if (DBM::is_result($r)) - $it = $r[0]; - } - if (!$it) - break; - - - $local_user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", - intval($uid) - ); - if (!count($local_user)) - break; - - $reply_to = ''; - $r1 = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1", - intval($uid) - ); - if ($r1 && $r1[0]['reply_to']) - $reply_to = $r1[0]['reply_to']; - - $subject = (($it['title']) ? email_header_encode($it['title'],'UTF-8') : t("\x28no subject\x29")) ; - - // only expose our real email address to true friends - - if (($contact['rel'] == CONTACT_IS_FRIEND) && !$contact['blocked']) { - if ($reply_to) { - $headers = 'From: '.email_header_encode($local_user[0]['username'],'UTF-8').' <'.$reply_to.'>'."\n"; - $headers .= 'Sender: '.$local_user[0]['email']."\n"; - } else { - $headers = 'From: '.email_header_encode($local_user[0]['username'],'UTF-8').' <'.$local_user[0]['email'].'>'."\n"; - } - } else { - $headers = 'From: '. email_header_encode($local_user[0]['username'],'UTF-8') .' <'. t('noreply') .'@'.$a->get_hostname() .'>'. "\n"; - } - - //if ($reply_to) - // $headers .= 'Reply-to: '.$reply_to . "\n"; - - $headers .= 'Message-Id: <'. iri2msgid($it['uri']).'>'. "\n"; - - //logger("Mail: uri: ".$it['uri']." parent-uri ".$it['parent-uri'], LOGGER_DEBUG); - //logger("Mail: Data: ".print_r($it, true), LOGGER_DEBUG); - //logger("Mail: Data: ".print_r($it, true), LOGGER_DATA); - - if ($it['uri'] !== $it['parent-uri']) { - $headers .= "References: <".iri2msgid($it["parent-uri"]).">"; - - // If Threading is enabled, write down the correct parent - if (($it["thr-parent"] != "") && ($it["thr-parent"] != $it["parent-uri"])) - $headers .= " <".iri2msgid($it["thr-parent"]).">"; - $headers .= "\n"; - - if (!$it['title']) { - $r = q("SELECT `title` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($it['parent-uri']), - intval($uid)); - - if (DBM::is_result($r) && ($r[0]['title'] != '')) { - $subject = $r[0]['title']; - } else { - $r = q("SELECT `title` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d LIMIT 1", - dbesc($it['parent-uri']), - intval($uid)); - - if (DBM::is_result($r) && ($r[0]['title'] != '')) - $subject = $r[0]['title']; - } - } - if (strncasecmp($subject,'RE:',3)) - $subject = 'Re: '.$subject; - } - email_send($addr, $subject, $headers, $it); - } - break; - - case NETWORK_DIASPORA: - if ($public_message) - $loc = 'public batch '.$contact['batch']; - else - $loc = $contact['name']; - - logger('delivery: diaspora batch deliver: '.$loc); - - if (Config::get('system','dfrn_only') || (!Config::get('system','diaspora_enabled'))) - break; - - if ($mail) { - Diaspora::send_mail($item,$owner,$contact); - break; - } - - if (!$normal_mode) - break; - - if (!$contact['pubkey'] && !$public_message) - break; - - if (($target_item['deleted']) && (($target_item['uri'] === $target_item['parent-uri']) || $followup)) { - // top-level retraction - logger('diaspora retract: '.$loc); - Diaspora::send_retraction($target_item,$owner,$contact,$public_message); - break; - } elseif ($relocate) { - Diaspora::sendAccountMigration($owner, $contact, $uid); - break; - } elseif ($followup) { - // send comments and likes to owner to relay - logger('diaspora followup: '.$loc); - Diaspora::send_followup($target_item,$owner,$contact,$public_message); - break; - } elseif ($target_item['uri'] !== $target_item['parent-uri']) { - // we are the relay - send comments, likes and relayable_retractions to our conversants - logger('diaspora relay: '.$loc); - Diaspora::send_relay($target_item,$owner,$contact,$public_message); - break; - } elseif ($top_level && !$walltowall) { - // currently no workable solution for sending walltowall - logger('diaspora status: '.$loc); - Diaspora::send_status($target_item,$owner,$contact,$public_message); - break; - } - - logger('delivery: diaspora unknown mode: '.$contact['name']); - - break; - - default: - break; - } - } - - return; -} diff --git a/worker/directory.php b/worker/directory.php deleted file mode 100644 index f56e8dbaa4..0000000000 --- a/worker/directory.php +++ /dev/null @@ -1,45 +0,0 @@ - $argv[1]); - - call_hooks('globaldir_update', $arr); - - logger('Updating directory: ' . $arr['url'], LOGGER_DEBUG); - if (strlen($arr['url'])) { - fetch_url($dir . '?url=' . bin2hex($arr['url'])); - } - - return; -} - -function directory_update_all() { - $r = q("SELECT `url` FROM `contact` - INNER JOIN `profile` ON `profile`.`uid` = `contact`.`uid` - INNER JOIN `user` ON `user`.`uid` = `contact`.`uid` - WHERE `contact`.`self` AND `profile`.`net-publish` AND `profile`.`is-default` AND - NOT `user`.`account_expired` AND `user`.`verified`"); - - if (DBM::is_result($r)) { - foreach ($r AS $user) { - Worker::add(PRIORITY_LOW, 'directory', $user['url']); - } - } -} diff --git a/worker/discover_poco.php b/worker/discover_poco.php deleted file mode 100644 index bb8daad6f3..0000000000 --- a/worker/discover_poco.php +++ /dev/null @@ -1,293 +0,0 @@ -: Searches for "search pattern" in the directory. "search pattern" is url encoded. - - checkcontact: Updates gcontact entries - - suggestions: Discover other servers for their contacts. - - server : Searches for the poco server list. "poco url" is base64 encoded. - - update_server: Frequently check the first 250 servers for vitality. - - update_server_directory: Discover the given server id for their contacts - - poco_load: Load POCO data from a given POCO address - - check_profile: Update remote profile data - */ - - if (($argc > 2) && ($argv[1] == "dirsearch")) { - $search = urldecode($argv[2]); - $mode = 1; - } elseif (($argc == 2) && ($argv[1] == "checkcontact")) { - $mode = 2; - } elseif (($argc == 2) && ($argv[1] == "suggestions")) { - $mode = 3; - } elseif (($argc == 3) && ($argv[1] == "server")) { - $mode = 4; - } elseif (($argc == 2) && ($argv[1] == "update_server")) { - $mode = 5; - } elseif (($argc == 3) && ($argv[1] == "update_server_directory")) { - $mode = 6; - } elseif (($argc > 5) && ($argv[1] == "poco_load")) { - $mode = 7; - } elseif (($argc == 3) && ($argv[1] == "check_profile")) { - $mode = 8; - } elseif ($argc == 1) { - $search = ""; - $mode = 0; - } else { - die("Unknown or missing parameter ".$argv[1]."\n"); - } - - logger('start '.$search); - - if ($mode == 8) { - if ($argv[2] != "") { - poco_last_updated($argv[2], true); - } - } elseif ($mode == 7) { - if ($argc == 6) { - $url = $argv[5]; - } else { - $url = ''; - } - poco_load_worker(intval($argv[2]), intval($argv[3]), intval($argv[4]), $url); - } elseif ($mode == 6) { - poco_discover_single_server(intval($argv[2])); - } elseif ($mode == 5) { - update_server(); - } elseif ($mode == 4) { - $server_url = $argv[2]; - if ($server_url == "") { - return; - } - $server_url = filter_var($server_url, FILTER_SANITIZE_URL); - if (substr(normalise_link($server_url), 0, 7) != "http://") { - return; - } - $result = "Checking server ".$server_url." - "; - $ret = poco_check_server($server_url); - if ($ret) { - $result .= "success"; - } else { - $result .= "failed"; - } - logger($result, LOGGER_DEBUG); - } elseif ($mode == 3) { - update_suggestions(); - } elseif (($mode == 2) && Config::get('system','poco_completion')) { - discover_users(); - } elseif (($mode == 1) && ($search != "") && Config::get('system','poco_local_search')) { - discover_directory($search); - gs_search_user($search); - } elseif (($mode == 0) && ($search == "") && (Config::get('system','poco_discovery') > 0)) { - // Query Friendica and Hubzilla servers for their users - poco_discover(); - - // Query GNU Social servers for their users ("statistics" addon has to be enabled on the GS server) - if (!Config::get('system','ostatus_disabled')) - gs_discover(); - } - - logger('end '.$search); - - return; -} - -/** - * @brief Updates the first 250 servers - * - */ -function update_server() { - $r = q("SELECT `url`, `created`, `last_failure`, `last_contact` FROM `gserver` ORDER BY rand()"); - - if (!DBM::is_result($r)) { - return; - } - - $updated = 0; - - foreach ($r AS $server) { - if (!poco_do_update($server["created"], "", $server["last_failure"], $server["last_contact"])) { - continue; - } - logger('Update server status for server '.$server["url"], LOGGER_DEBUG); - - Worker::add(PRIORITY_LOW, "discover_poco", "server", $server["url"]); - - if (++$updated > 250) { - return; - } - } -} - -function discover_users() { - logger("Discover users", LOGGER_DEBUG); - - $starttime = time(); - - $users = q("SELECT `url`, `created`, `updated`, `last_failure`, `last_contact`, `server_url`, `network` FROM `gcontact` - WHERE `last_contact` < UTC_TIMESTAMP - INTERVAL 1 MONTH AND - `last_failure` < UTC_TIMESTAMP - INTERVAL 1 MONTH AND - `network` IN ('%s', '%s', '%s', '%s', '') ORDER BY rand()", - dbesc(NETWORK_DFRN), dbesc(NETWORK_DIASPORA), - dbesc(NETWORK_OSTATUS), dbesc(NETWORK_FEED)); - - if (!$users) { - return; - } - $checked = 0; - - foreach ($users AS $user) { - - $urlparts = parse_url($user["url"]); - if (!isset($urlparts["scheme"])) { - q("UPDATE `gcontact` SET `network` = '%s' WHERE `nurl` = '%s'", - dbesc(NETWORK_PHANTOM), dbesc(normalise_link($user["url"]))); - continue; - } - - if (in_array($urlparts["host"], array("www.facebook.com", "facebook.com", "twitter.com", - "identi.ca", "alpha.app.net"))) { - $networks = array("www.facebook.com" => NETWORK_FACEBOOK, - "facebook.com" => NETWORK_FACEBOOK, - "twitter.com" => NETWORK_TWITTER, - "identi.ca" => NETWORK_PUMPIO, - "alpha.app.net" => NETWORK_APPNET); - - q("UPDATE `gcontact` SET `network` = '%s' WHERE `nurl` = '%s'", - dbesc($networks[$urlparts["host"]]), dbesc(normalise_link($user["url"]))); - continue; - } - - $server_url = poco_detect_server($user["url"]); - $force_update = false; - - if ($user["server_url"] != "") { - - $force_update = (normalise_link($user["server_url"]) != normalise_link($server_url)); - - $server_url = $user["server_url"]; - } - - if ((($server_url == "") && ($user["network"] == NETWORK_FEED)) || $force_update || poco_check_server($server_url, $user["network"])) { - logger('Check profile '.$user["url"]); - Worker::add(PRIORITY_LOW, "discover_poco", "check_profile", $user["url"]); - - if (++$checked > 100) { - return; - } - } else { - q("UPDATE `gcontact` SET `last_failure` = '%s' WHERE `nurl` = '%s'", - dbesc(datetime_convert()), dbesc(normalise_link($user["url"]))); - } - - // Quit the loop after 3 minutes - if (time() > ($starttime + 180)) { - return; - } - } -} - -function discover_directory($search) { - - $data = Cache::get("dirsearch:".$search); - if (!is_null($data)) { - // Only search for the same item every 24 hours - if (time() < $data + (60 * 60 * 24)) { - logger("Already searched for ".$search." in the last 24 hours", LOGGER_DEBUG); - return; - } - } - - $x = fetch_url(get_server()."/lsearch?p=1&n=500&search=".urlencode($search)); - $j = json_decode($x); - - if (count($j->results)) { - foreach ($j->results as $jj) { - // Check if the contact already exists - $exists = q("SELECT `id`, `last_contact`, `last_failure`, `updated` FROM `gcontact` WHERE `nurl` = '%s'", normalise_link($jj->url)); - if (DBM::is_result($exists)) { - logger("Profile ".$jj->url." already exists (".$search.")", LOGGER_DEBUG); - - if (($exists[0]["last_contact"] < $exists[0]["last_failure"]) && - ($exists[0]["updated"] < $exists[0]["last_failure"])) { - continue; - } - // Update the contact - poco_last_updated($jj->url); - continue; - } - - $server_url = poco_detect_server($jj->url); - if ($server_url != '') { - if (!poco_check_server($server_url)) { - logger("Friendica server ".$server_url." doesn't answer.", LOGGER_DEBUG); - continue; - } - logger("Friendica server ".$server_url." seems to be okay.", LOGGER_DEBUG); - } - - $data = Probe::uri($jj->url); - if ($data["network"] == NETWORK_DFRN) { - logger("Profile ".$jj->url." is reachable (".$search.")", LOGGER_DEBUG); - logger("Add profile ".$jj->url." to local directory (".$search.")", LOGGER_DEBUG); - - if ($jj->tags != "") { - $data["keywords"] = $jj->tags; - } - - $data["server_url"] = $data["baseurl"]; - - update_gcontact($data); - } else { - logger("Profile ".$jj->url." is not responding or no Friendica contact - but network ".$data["network"], LOGGER_DEBUG); - } - } - } - Cache::set("dirsearch:".$search, time(), CACHE_DAY); -} - -/** - * @brief Search for GNU Social user with gstools.org - * - * @param str $search User name - */ -function gs_search_user($search) { - - // Currently disabled, since the service isn't available anymore. - // It is not removed since I hope that there will be a successor. - return false; - - $a = get_app(); - - $url = "http://gstools.org/api/users_search/".urlencode($search); - - $result = z_fetch_url($url); - if (!$result["success"]) { - return false; - } - - $contacts = json_decode($result["body"]); - - if ($contacts->status == 'ERROR') { - return false; - } - - /// @TODO AS is considered as a notation for constants (as they usually being written all upper-case) - /// @TODO find all those and convert to all lower-case which is a keyword then - foreach ($contacts->data AS $user) { - $contact = Probe::uri($user->site_address."/".$user->name); - if ($contact["network"] != NETWORK_PHANTOM) { - $contact["about"] = $user->description; - update_gcontact($contact); - } - } -} diff --git a/worker/expire.php b/worker/expire.php deleted file mode 100644 index 7a3549ada6..0000000000 --- a/worker/expire.php +++ /dev/null @@ -1,76 +0,0 @@ - $row['id'])); - } - dba::close($r); - - logger('Delete expired items - done', LOGGER_DEBUG); - - // make this optional as it could have a performance impact on large sites - if (intval(Config::get('system', 'optimize_items'))) { - q("OPTIMIZE TABLE `item`"); - } - return; - } elseif (($argc == 2) && (intval($argv[1]) > 0)) { - $user = dba::select('user', array('uid', 'username', 'expire'), array('uid' => $argv[1]), array('limit' => 1)); - if (DBM::is_result($user)) { - logger('Expire items for user '.$user['uid'].' ('.$user['username'].') - interval: '.$user['expire'], LOGGER_DEBUG); - item_expire($user['uid'], $user['expire']); - logger('Expire items for user '.$user['uid'].' ('.$user['username'].') - done ', LOGGER_DEBUG); - } - return; - } elseif (($argc == 3) && ($argv[1] == 'hook') && is_array($a->hooks) && array_key_exists("expire", $a->hooks)) { - foreach ($a->hooks["expire"] as $hook) { - if ($hook[1] == $argv[2]) { - logger("Calling expire hook '" . $hook[1] . "'", LOGGER_DEBUG); - call_single_hook($a, $name, $hook, $data); - } - } - return; - } - - logger('expire: start'); - - Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true), - 'expire', 'delete'); - - $r = dba::p("SELECT `uid`, `username` FROM `user` WHERE `expire` != 0"); - while ($row = dba::fetch($r)) { - logger('Calling expiry for user '.$row['uid'].' ('.$row['username'].')', LOGGER_DEBUG); - Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true), - 'expire', (int)$row['uid']); - } - dba::close($r); - - logger('expire: calling hooks'); - - if (is_array($a->hooks) && array_key_exists('expire', $a->hooks)) { - foreach ($a->hooks['expire'] as $hook) { - logger("Calling expire hook for '" . $hook[1] . "'", LOGGER_DEBUG); - Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true), - 'expire', 'hook', $hook[1]); - } - } - - logger('expire: end'); - - return; -} diff --git a/worker/gprobe.php b/worker/gprobe.php deleted file mode 100644 index 7003051851..0000000000 --- a/worker/gprobe.php +++ /dev/null @@ -1,57 +0,0 @@ - UTC_TIMESTAMP() - INTERVAL 10 MINUTE", - intval($item_id) - ); - $uid = $item_id; - $item_id = 0; - if (! count($items)) { - return; - } - } elseif ($cmd === 'suggest') { - $normal_mode = false; - $fsuggest = true; - - $suggest = q("SELECT * FROM `fsuggest` WHERE `id` = %d LIMIT 1", - intval($item_id) - ); - if (! count($suggest)) { - return; - } - $uid = $suggest[0]['uid']; - $recipients[] = $suggest[0]['cid']; - $item = $suggest[0]; - } elseif ($cmd === 'removeme') { - $r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`, - `user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`, - `user`.`page-flags`, `user`.`prvnets`, `user`.`account-type`, `user`.`guid` - FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid` - WHERE `contact`.`uid` = %d AND `contact`.`self` LIMIT 1", - intval($item_id)); - if (!$r) - return; - - $user = $r[0]; - - $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1", intval($item_id)); - if (!$r) - return; - - $self = $r[0]; - - $r = q("SELECT * FROM `contact` WHERE NOT `self` AND `uid` = %d", intval($item_id)); - if (!$r) { - return; - } - require_once 'include/Contact.php'; - foreach ($r as $contact) { - terminate_friendship($user, $self, $contact); - } - return; - } elseif ($cmd === 'relocate') { - $normal_mode = false; - $relocate = true; - $uid = $item_id; - - $recipients_relocate = q("SELECT * FROM `contact` WHERE `uid` = %d AND NOT `self` AND `network` IN ('%s', '%s')", - intval($uid), NETWORK_DFRN, NETWORK_DIASPORA); - } else { - // find ancestors - $r = q("SELECT * FROM `item` WHERE `id` = %d AND visible = 1 AND moderated = 0 LIMIT 1", - intval($item_id) - ); - - if ((! DBM::is_result($r)) || (! intval($r[0]['parent']))) { - return; - } - - $target_item = $r[0]; - $parent_id = intval($r[0]['parent']); - $uid = $r[0]['uid']; - $updated = $r[0]['edited']; - - $items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer` - FROM `item` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` WHERE `parent` = %d AND visible = 1 AND moderated = 0 ORDER BY `id` ASC", - intval($parent_id) - ); - - if (! count($items)) { - return; - } - - // avoid race condition with deleting entries - - if ($items[0]['deleted']) { - foreach ($items as $item) { - $item['deleted'] = 1; - } - } - - if ((count($items) == 1) && ($items[0]['id'] === $target_item['id']) && ($items[0]['uri'] === $items[0]['parent-uri'])) { - logger('notifier: top level post'); - $top_level = true; - } - - } - - $r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`, - `user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`, - `user`.`page-flags`, `user`.`prvnets`, `user`.`account-type` - FROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid` - WHERE `contact`.`uid` = %d AND `contact`.`self` = 1 LIMIT 1", - intval($uid) - ); - - if (! DBM::is_result($r)) { - return; - } - - $owner = $r[0]; - - $walltowall = ((($top_level) && ($owner['id'] != $items[0]['contact-id'])) ? true : false); - - // Should the post be transmitted to Diaspora? - $diaspora_delivery = true; - - // If this is a public conversation, notify the feed hub - $public_message = true; - - // Do a PuSH - $push_notify = false; - - // Deliver directly to a forum, don't PuSH - $direct_forum_delivery = false; - - // fill this in with a single salmon slap if applicable - $slap = ''; - - if (! ($mail || $fsuggest || $relocate)) { - - $slap = ostatus::salmon($target_item,$owner); - - require_once 'include/group.php'; - - $parent = $items[0]; - - $thr_parent = q("SELECT `network`, `author-link`, `owner-link` FROM `item` WHERE `uri` = '%s' AND `uid` = %d", - dbesc($target_item["thr-parent"]), intval($target_item["uid"])); - - logger('GUID: '.$target_item["guid"].': Parent is '.$parent['network'].'. Thread parent is '.$thr_parent[0]['network'], LOGGER_DEBUG); - - // This is IMPORTANT!!!! - - // We will only send a "notify owner to relay" or followup message if the referenced post - // originated on our system by virtue of having our hostname somewhere - // in the URI, AND it was a comment (not top_level) AND the parent originated elsewhere. - - // if $parent['wall'] == 1 we will already have the parent message in our array - // and we will relay the whole lot. - - // expire sends an entire group of expire messages and cannot be forwarded. - // However the conversation owner will be a part of the conversation and will - // be notified during this run. - // Other DFRN conversation members will be alerted during polled updates. - - - - // Diaspora members currently are not notified of expirations, and other networks have - // either limited or no ability to process deletions. We should at least fix Diaspora - // by stringing togther an array of retractions and sending them onward. - - - $localhost = str_replace('www.','',$a->get_hostname()); - if (strpos($localhost,':')) { - $localhost = substr($localhost,0,strpos($localhost,':')); - } - /** - * - * Be VERY CAREFUL if you make any changes to the following several lines. Seemingly innocuous changes - * have been known to cause runaway conditions which affected several servers, along with - * permissions issues. - * - */ - - $relay_to_owner = false; - - if (!$top_level && ($parent['wall'] == 0) && !$expire && (stristr($target_item['uri'],$localhost))) { - $relay_to_owner = true; - } - - - if (($cmd === 'uplink') && (intval($parent['forum_mode']) == 1) && !$top_level) { - $relay_to_owner = true; - } - - // until the 'origin' flag has been in use for several months - // we will just use it as a fallback test - // later we will be able to use it as the primary test of whether or not to relay. - - if (! $target_item['origin']) { - $relay_to_owner = false; - } - if ($parent['origin']) { - $relay_to_owner = false; - } - - // Special treatment for forum posts - if (($target_item['author-link'] != $target_item['owner-link']) && - ($owner['id'] != $target_item['contact-id']) && - ($target_item['uri'] === $target_item['parent-uri'])) { - - $fields = array('forum', 'prv'); - $condition = array('id' => $target_item['contact-id']); - $contact = dba::select('contact', $fields, $condition, array('limit' => 1)); - if (!DBM::is_result($contact)) { - // Should never happen - return false; - } - - // Is the post from a forum? - if ($contact['forum'] || $contact['prv']) { - $relay_to_owner = true; - $direct_forum_delivery = true; - } - } - if ($relay_to_owner) { - logger('notifier: followup '.$target_item["guid"], LOGGER_DEBUG); - // local followup to remote post - $followup = true; - $public_message = false; // not public - $conversant_str = dbesc($parent['contact-id']); - $recipients = array($parent['contact-id']); - $recipients_followup = array($parent['contact-id']); - - //if (!$target_item['private'] && $target_item['wall'] && - if (!$target_item['private'] && - (strlen($target_item['allow_cid'].$target_item['allow_gid']. - $target_item['deny_cid'].$target_item['deny_gid']) == 0)) - $push_notify = true; - - if (($thr_parent && ($thr_parent[0]['network'] == NETWORK_OSTATUS)) || ($parent['network'] == NETWORK_OSTATUS)) { - - $push_notify = true; - - if ($parent["network"] == NETWORK_OSTATUS) { - // Distribute the message to the DFRN contacts as if this wasn't a followup since OStatus can't relay comments - // Currently it is work at progress - $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `network` = '%s' AND NOT `blocked` AND NOT `pending` AND NOT `archive`", - intval($uid), - dbesc(NETWORK_DFRN) - ); - if (DBM::is_result($r)) { - foreach ($r as $rr) { - $recipients_followup[] = $rr['id']; - } - } - } - } - - if ($direct_forum_delivery) { - $push_notify = false; - } - - logger("Notify ".$target_item["guid"]." via PuSH: ".($push_notify?"Yes":"No"), LOGGER_DEBUG); - } else { - $followup = false; - - logger('Distributing directly '.$target_item["guid"], LOGGER_DEBUG); - - // don't send deletions onward for other people's stuff - - if ($target_item['deleted'] && (! intval($target_item['wall']))) { - logger('notifier: ignoring delete notification for non-wall item'); - return; - } - - if ((strlen($parent['allow_cid'])) - || (strlen($parent['allow_gid'])) - || (strlen($parent['deny_cid'])) - || (strlen($parent['deny_gid']))) { - $public_message = false; // private recipients, not public - } - - $allow_people = expand_acl($parent['allow_cid']); - $allow_groups = expand_groups(expand_acl($parent['allow_gid']),true); - $deny_people = expand_acl($parent['deny_cid']); - $deny_groups = expand_groups(expand_acl($parent['deny_gid'])); - - // if our parent is a public forum (forum_mode == 1), uplink to the origional author causing - // a delivery fork. private groups (forum_mode == 2) do not uplink - - if ((intval($parent['forum_mode']) == 1) && (! $top_level) && ($cmd !== 'uplink')) { - Worker::add($a->queue['priority'], 'notifier', 'uplink', $item_id); - } - - $conversants = array(); - - foreach ($items as $item) { - $recipients[] = $item['contact-id']; - $conversants[] = $item['contact-id']; - // pull out additional tagged people to notify (if public message) - if ($public_message && strlen($item['inform'])) { - $people = explode(',',$item['inform']); - foreach ($people as $person) { - if (substr($person,0,4) === 'cid:') { - $recipients[] = intval(substr($person,4)); - $conversants[] = intval(substr($person,4)); - } else { - $url_recipients[] = substr($person,4); - } - } - } - } - - if (count($url_recipients)) - logger('notifier: '.$target_item["guid"].' url_recipients ' . print_r($url_recipients,true)); - - $conversants = array_unique($conversants); - - - $recipients = array_unique(array_merge($recipients,$allow_people,$allow_groups)); - $deny = array_unique(array_merge($deny_people,$deny_groups)); - $recipients = array_diff($recipients,$deny); - - $conversant_str = dbesc(implode(', ',$conversants)); - } - - // If the thread parent is OStatus then do some magic to distribute the messages. - // We have not only to look at the parent, since it could be a Friendica thread. - if (($thr_parent && ($thr_parent[0]['network'] == NETWORK_OSTATUS)) || ($parent['network'] == NETWORK_OSTATUS)) { - - $diaspora_delivery = false; - - logger('Some parent is OStatus for '.$target_item["guid"]." - Author: ".$thr_parent[0]['author-link']." - Owner: ".$thr_parent[0]['owner-link'], LOGGER_DEBUG); - - // Send a salmon to the parent author - $r = q("SELECT `url`, `notify` FROM `contact` WHERE `nurl`='%s' AND `uid` IN (0, %d) AND `notify` != ''", - dbesc(normalise_link($thr_parent[0]['author-link'])), - intval($uid)); - if (DBM::is_result($r)) { - $probed_contact = $r[0]; - } else { - $probed_contact = Probe::uri($thr_parent[0]['author-link']); - } - - if ($probed_contact["notify"] != "") { - logger('Notify parent author '.$probed_contact["url"].': '.$probed_contact["notify"]); - $url_recipients[$probed_contact["notify"]] = $probed_contact["notify"]; - } - - // Send a salmon to the parent owner - $r = q("SELECT `url`, `notify` FROM `contact` WHERE `nurl`='%s' AND `uid` IN (0, %d) AND `notify` != ''", - dbesc(normalise_link($thr_parent[0]['owner-link'])), - intval($uid)); - if (DBM::is_result($r)) { - $probed_contact = $r[0]; - } else { - $probed_contact = Probe::uri($thr_parent[0]['owner-link']); - } - - if ($probed_contact["notify"] != "") { - logger('Notify parent owner '.$probed_contact["url"].': '.$probed_contact["notify"]); - $url_recipients[$probed_contact["notify"]] = $probed_contact["notify"]; - } - - // Send a salmon notification to every person we mentioned in the post - $arr = explode(',',$target_item['tag']); - foreach ($arr as $x) { - //logger('Checking tag '.$x, LOGGER_DEBUG); - $matches = null; - if (preg_match('/@\[url=([^\]]*)\]/',$x,$matches)) { - $probed_contact = Probe::uri($matches[1]); - if ($probed_contact["notify"] != "") { - logger('Notify mentioned user '.$probed_contact["url"].': '.$probed_contact["notify"]); - $url_recipients[$probed_contact["notify"]] = $probed_contact["notify"]; - } - } - } - - // It only makes sense to distribute answers to OStatus messages to Friendica and OStatus - but not Diaspora - $sql_extra = " AND `network` IN ('".NETWORK_OSTATUS."', '".NETWORK_DFRN."')"; - } else { - $sql_extra = " AND `network` IN ('".NETWORK_OSTATUS."', '".NETWORK_DFRN."', '".NETWORK_DIASPORA."', '".NETWORK_MAIL."', '".NETWORK_MAIL2."')"; - } - } else { - $public_message = false; - } - - // If this is a public message and pubmail is set on the parent, include all your email contacts - - $mail_disabled = ((function_exists('imap_open') && (!Config::get('system','imap_disabled'))) ? 0 : 1); - - if (! $mail_disabled) { - if ((! strlen($target_item['allow_cid'])) && (! strlen($target_item['allow_gid'])) - && (! strlen($target_item['deny_cid'])) && (! strlen($target_item['deny_gid'])) - && (intval($target_item['pubmail']))) { - $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `network` = '%s'", - intval($uid), - dbesc(NETWORK_MAIL) - ); - if (DBM::is_result($r)) { - foreach ($r as $rr) { - $recipients[] = $rr['id']; - } - } - } - } - - if ($followup) { - $recip_str = implode(', ', $recipients_followup); - } else { - $recip_str = implode(', ', $recipients); - } - if ($relocate) { - $r = $recipients_relocate; - } else { - $r = q("SELECT `id`, `url`, `network`, `self` FROM `contact` - WHERE `id` IN (%s) AND NOT `blocked` AND NOT `pending` AND NOT `archive`".$sql_extra, - dbesc($recip_str) - ); - } - - // delivery loop - - if (DBM::is_result($r)) { - foreach ($r as $contact) { - if ($contact['self']) { - continue; - } - logger("Deliver ".$target_item["guid"]." to ".$contact['url']." via network ".$contact['network'], LOGGER_DEBUG); - - Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true), - 'delivery', $cmd, $item_id, (int)$contact['id']); - } - } - - // send salmon slaps to mentioned remote tags (@foo@example.com) in OStatus posts - // They are especially used for notifications to OStatus users that don't follow us. - - if ($slap && count($url_recipients) && ($public_message || $push_notify) && $normal_mode) { - if (!Config::get('system','dfrn_only')) { - foreach ($url_recipients as $url) { - if ($url) { - logger('notifier: urldelivery: ' . $url); - $deliver_status = slapper($owner,$url,$slap); - /// @TODO Redeliver/queue these items on failure, though there is no contact record - } - } - } - } - - - if ($public_message) { - - $r0 = array(); - $r1 = array(); - - if ($diaspora_delivery) { - if (!$followup) { - $r0 = Diaspora::relay_list(); - } - - $r1 = q("SELECT `batch`, ANY_VALUE(`id`) AS `id`, ANY_VALUE(`name`) AS `name`, ANY_VALUE(`network`) AS `network` - FROM `contact` WHERE `network` = '%s' AND `batch` != '' - AND `uid` = %d AND `rel` != %d AND NOT `blocked` AND NOT `pending` AND NOT `archive` GROUP BY `batch`", - dbesc(NETWORK_DIASPORA), - intval($owner['uid']), - intval(CONTACT_IS_SHARING) - ); - } - - $r2 = q("SELECT `id`, `name`,`network` FROM `contact` - WHERE `network` in ('%s', '%s') AND `uid` = %d AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `rel` != %d", - dbesc(NETWORK_DFRN), - dbesc(NETWORK_MAIL2), - intval($owner['uid']), - intval(CONTACT_IS_SHARING) - ); - - $r = array_merge($r2,$r1,$r0); - - if (DBM::is_result($r)) { - logger('pubdeliver '.$target_item["guid"].': '.print_r($r,true), LOGGER_DEBUG); - - foreach ($r as $rr) { - - // except for Diaspora batch jobs - // Don't deliver to folks who have already been delivered to - - if (($rr['network'] !== NETWORK_DIASPORA) && (in_array($rr['id'],$conversants))) { - logger('notifier: already delivered id=' . $rr['id']); - continue; - } - - if ((! $mail) && (! $fsuggest) && (! $followup)) { - logger('notifier: delivery agent: '.$rr['name'].' '.$rr['id'].' '.$rr['network'].' '.$target_item["guid"]); - Worker::add(array('priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true), - 'delivery', $cmd, $item_id, (int)$rr['id']); - } - } - } - - $push_notify = true; - - } - - // Notify PuSH subscribers (Used for OStatus distribution of regular posts) - if ($push_notify) { - // Set push flag for PuSH subscribers to this topic, - // they will be notified in queue.php - q("UPDATE `push_subscriber` SET `push` = 1 ". - "WHERE `nickname` = '%s' AND `push` = 0", dbesc($owner['nickname'])); - - logger('Activating internal PuSH for item '.$item_id, LOGGER_DEBUG); - - // Handling the pubsubhubbub requests - Worker::add(array('priority' => PRIORITY_HIGH, 'created' => $a->queue['created'], 'dont_fork' => true), - 'pubsubpublish'); - } - - logger('notifier: calling hooks', LOGGER_DEBUG); - - if ($normal_mode) { - call_hooks('notifier_normal',$target_item); - } - - call_hooks('notifier_end',$target_item); - - return; -} diff --git a/worker/profile_update.php b/worker/profile_update.php deleted file mode 100644 index 0c5de0156d..0000000000 --- a/worker/profile_update.php +++ /dev/null @@ -1,12 +0,0 @@ - 1) { - $pubsubpublish_id = intval($argv[1]); - } else { - // We'll push to each subscriber that has push > 0, - // i.e. there has been an update (set in notifier.php). - $r = q("SELECT `id`, `callback_url` FROM `push_subscriber` WHERE `push` > 0 ORDER BY `last_update` DESC"); - - foreach ($r as $rr) { - logger("Publish feed to ".$rr["callback_url"], LOGGER_DEBUG); - Worker::add(array('priority' => PRIORITY_HIGH, 'created' => $a->queue['created'], 'dont_fork' => true), - 'pubsubpublish', (int)$rr["id"]); - } - } - - handle_pubsubhubbub($pubsubpublish_id); - - return; -} - -function handle_pubsubhubbub($id) { - global $a; - - $r = q("SELECT * FROM `push_subscriber` WHERE `id` = %d", intval($id)); - if (!DBM::is_result($r)) { - return; - } - - $rr = $r[0]; - - /// @todo Check server status with poco_check_server() - // Before this can be done we need a way to safely detect the server url. - - logger("Generate feed of user ".$rr['nickname']." to ".$rr['callback_url']." - last updated ".$rr['last_update'], LOGGER_DEBUG); - - $last_update = $rr['last_update']; - $params = ostatus::feed($a, $rr['nickname'], $last_update); - - if (!$params) { - return; - } - - $hmac_sig = hash_hmac("sha1", $params, $rr['secret']); - - $headers = array("Content-type: application/atom+xml", - sprintf("Link: <%s>;rel=hub,<%s>;rel=self", - System::baseUrl().'/pubsubhubbub/'.$rr['nickname'], - $rr['topic']), - "X-Hub-Signature: sha1=".$hmac_sig); - - logger('POST '.print_r($headers, true)."\n".$params, LOGGER_DEBUG); - - post_url($rr['callback_url'], $params, $headers); - $ret = $a->get_curl_code(); - - if ($ret >= 200 && $ret <= 299) { - logger('successfully pushed to '.$rr['callback_url']); - - // set last_update to the "created" date of the last item, and reset push=0 - q("UPDATE `push_subscriber` SET `push` = 0, last_update = '%s' WHERE id = %d", - dbesc($last_update), - intval($rr['id'])); - - } else { - logger('error when pushing to '.$rr['callback_url'].' HTTP: '.$ret); - - // we use the push variable also as a counter, if we failed we - // increment this until some upper limit where we give up - $new_push = intval($rr['push']) + 1; - - if ($new_push > 30) // OK, let's give up - $new_push = 0; - - q("UPDATE `push_subscriber` SET `push` = %d WHERE id = %d", - $new_push, - intval($rr['id'])); - } -} diff --git a/worker/queue.php b/worker/queue.php deleted file mode 100644 index a56c41d97a..0000000000 --- a/worker/queue.php +++ /dev/null @@ -1,191 +0,0 @@ - 1) { - $queue_id = intval($argv[1]); - } else { - $queue_id = 0; - } - - $cachekey_deadguy = 'queue_run:deadguy:'; - $cachekey_server = 'queue_run:server:'; - - if (!$queue_id) { - logger('queue: start'); - - // Handling the pubsubhubbub requests - Worker::add(array('priority' => PRIORITY_HIGH, 'dont_fork' => true), 'pubsubpublish'); - - $r = q( - "SELECT `queue`.*, `contact`.`name`, `contact`.`uid` FROM `queue` - INNER JOIN `contact` ON `queue`.`cid` = `contact`.`id` - WHERE `queue`.`created` < UTC_TIMESTAMP() - INTERVAL 3 DAY" - ); - - if (DBM::is_result($r)) { - foreach ($r as $rr) { - logger('Removing expired queue item for ' . $rr['name'] . ', uid=' . $rr['uid']); - logger('Expired queue data: ' . $rr['content'], LOGGER_DATA); - } - q("DELETE FROM `queue` WHERE `created` < UTC_TIMESTAMP() - INTERVAL 3 DAY"); - } - - /* - * For the first 12 hours we'll try to deliver every 15 minutes - * After that, we'll only attempt delivery once per hour. - */ - $r = q("SELECT `id` FROM `queue` WHERE ((`created` > UTC_TIMESTAMP() - INTERVAL 12 HOUR AND `last` < UTC_TIMESTAMP() - INTERVAL 15 MINUTE) OR (`last` < UTC_TIMESTAMP() - INTERVAL 1 HOUR)) ORDER BY `cid`, `created`"); - - call_hooks('queue_predeliver', $a, $r); - - if (DBM::is_result($r)) { - foreach ($r as $q_item) { - logger('Call queue for id '.$q_item['id']); - Worker::add(array('priority' => PRIORITY_LOW, 'dont_fork' => true), "queue", (int)$q_item['id']); - } - } - return; - } - - - // delivering - - require_once 'include/salmon.php'; - - $r = q( - "SELECT * FROM `queue` WHERE `id` = %d LIMIT 1", - intval($queue_id) - ); - - if (!DBM::is_result($r)) { - return; - } - - $q_item = $r[0]; - - $c = q( - "SELECT * FROM `contact` WHERE `id` = %d LIMIT 1", - intval($q_item['cid']) - ); - - if (!DBM::is_result($c)) { - remove_queue_item($q_item['id']); - return; - } - - $dead = Cache::get($cachekey_deadguy.$c[0]['notify']); - - if (!is_null($dead) && $dead) { - logger('queue: skipping known dead url: '.$c[0]['notify']); - update_queue_time($q_item['id']); - return; - } - - $server = poco_detect_server($c[0]['url']); - - if ($server != "") { - $vital = Cache::get($cachekey_server.$server); - - if (is_null($vital)) { - logger("Check server ".$server." (".$c[0]["network"].")"); - - $vital = poco_check_server($server, $c[0]["network"], true); - Cache::set($cachekey_server.$server, $vital, CACHE_QUARTER_HOUR); - } - - if (!is_null($vital) && !$vital) { - logger('queue: skipping dead server: '.$server); - update_queue_time($q_item['id']); - return; - } - } - - $u = q( - "SELECT `user`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey` - FROM `user` WHERE `uid` = %d LIMIT 1", - intval($c[0]['uid']) - ); - if (!DBM::is_result($u)) { - remove_queue_item($q_item['id']); - return; - } - - $data = $q_item['content']; - $public = $q_item['batch']; - $contact = $c[0]; - $owner = $u[0]; - - $deliver_status = 0; - - switch ($contact['network']) { - case NETWORK_DFRN: - logger('queue: dfrndelivery: item '.$q_item['id'].' for '.$contact['name'].' <'.$contact['url'].'>'); - $deliver_status = DFRN::deliver($owner, $contact, $data); - - if ($deliver_status == (-1)) { - update_queue_time($q_item['id']); - Cache::set($cachekey_deadguy.$contact['notify'], true, CACHE_QUARTER_HOUR); - } else { - remove_queue_item($q_item['id']); - } - break; - case NETWORK_OSTATUS: - if ($contact['notify']) { - logger('queue: slapdelivery: item '.$q_item['id'].' for '.$contact['name'].' <'.$contact['url'].'>'); - $deliver_status = slapper($owner, $contact['notify'], $data); - - if ($deliver_status == (-1)) { - update_queue_time($q_item['id']); - Cache::set($cachekey_deadguy.$contact['notify'], true, CACHE_QUARTER_HOUR); - } else { - remove_queue_item($q_item['id']); - } - } - break; - case NETWORK_DIASPORA: - if ($contact['notify']) { - logger('queue: diaspora_delivery: item '.$q_item['id'].' for '.$contact['name'].' <'.$contact['url'].'>'); - $deliver_status = Diaspora::transmit($owner, $contact, $data, $public, true); - - if ($deliver_status == (-1)) { - update_queue_time($q_item['id']); - Cache::set($cachekey_deadguy.$contact['notify'], true, CACHE_QUARTER_HOUR); - } else { - remove_queue_item($q_item['id']); - } - } - break; - - default: - $params = array('owner' => $owner, 'contact' => $contact, 'queue' => $q_item, 'result' => false); - call_hooks('queue_deliver', $a, $params); - - if ($params['result']) { - remove_queue_item($q_item['id']); - } else { - update_queue_time($q_item['id']); - } - break; - } - logger('Deliver status '.(int)$deliver_status.' for item '.$q_item['id'].' to '.$contact['name'].' <'.$contact['url'].'>'); - - return; -} diff --git a/worker/remove_contact.php b/worker/remove_contact.php deleted file mode 100644 index 9d4b1e4c37..0000000000 --- a/worker/remove_contact.php +++ /dev/null @@ -1,24 +0,0 @@ - $id)); - if ($r) { - return; - } - - // Now we delete all the depending table entries - dba::delete('contact', array('id' => $id)); -} diff --git a/worker/shadowupdate.php b/worker/shadowupdate.php deleted file mode 100644 index c41b231221..0000000000 --- a/worker/shadowupdate.php +++ /dev/null @@ -1,29 +0,0 @@ - 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"])) - ); -}