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