diff --git a/include/cron.php b/include/cron.php index 0ae336e33..059c19992 100644 --- a/include/cron.php +++ b/include/cron.php @@ -68,6 +68,8 @@ function cron_run(&$argv, &$argc){ update_contact_birthdays(); + proc_run(PRIORITY_LOW, "include/discover_poco.php", "update_server"); + proc_run(PRIORITY_LOW, "include/discover_poco.php", "suggestions"); set_config('system','last_expire_day',$d2); diff --git a/include/discover_poco.php b/include/discover_poco.php index 0384483a4..f0bfb646b 100644 --- a/include/discover_poco.php +++ b/include/discover_poco.php @@ -5,28 +5,61 @@ use \Friendica\Core\Config; require_once('include/socgraph.php'); require_once('include/datetime.php'); -function discover_poco_run(&$argv, &$argc){ +function discover_poco_run(&$argv, &$argc) { + + /* + This function can be called in these ways: + - dirsearch : Searches for "search pattern" in the directory. "search pattern" is url encoded. + - checkcontact: Updates gcontact entries + - suggestions: Discover other servers for their contacts. + - server : Searches for the poco server list. "poco url" is base64 encoded. + - update_server: Frequently check the first 250 servers for vitality. + */ if (($argc > 2) && ($argv[1] == "dirsearch")) { $search = urldecode($argv[2]); $mode = 1; - } elseif(($argc == 2) && ($argv[1] == "checkcontact")) { + } elseif (($argc == 2) && ($argv[1] == "checkcontact")) { $mode = 2; - } elseif(($argc == 2) && ($argv[1] == "suggestions")) { + } 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 == 1) { $search = ""; $mode = 0; - } else + } else { die("Unknown or missing parameter ".$argv[1]."\n"); + } logger('start '.$search); - if ($mode==3) + if ($mode == 5) { + update_server(); + } elseif ($mode == 4) { + $server_url = base64_decode($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) AND get_config('system','poco_completion')) + } elseif (($mode == 2) AND get_config('system','poco_completion')) { discover_users(); - elseif (($mode == 1) AND ($search != "") and get_config('system','poco_local_search')) { + } elseif (($mode == 1) AND ($search != "") and get_config('system','poco_local_search')) { discover_directory($search); gs_search_user($search); } elseif (($mode == 0) AND ($search == "") and (get_config('system','poco_discovery') > 0)) { @@ -43,6 +76,33 @@ function discover_poco_run(&$argv, &$argc){ 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); + + proc_run(PRIORITY_LOW, "include/discover_poco.php", "server", base64_encode($server["url"])); + + if (++$updated > 250) { + return; + } + } +} + function discover_users() { logger("Discover users", LOGGER_DEBUG); @@ -53,9 +113,9 @@ function discover_users() { dbesc(NETWORK_DFRN), dbesc(NETWORK_DIASPORA), dbesc(NETWORK_OSTATUS), dbesc(NETWORK_FEED)); - if (!$users) + if (!$users) { return; - + } $checked = 0; foreach ($users AS $user) { @@ -80,27 +140,29 @@ function discover_users() { continue; } - if ($user["server_url"] != "") + if ($user["server_url"] != "") { $server_url = $user["server_url"]; - else + } else { $server_url = poco_detect_server($user["url"]); - + } if (($server_url == "") OR poco_check_server($server_url, $gcontacts[0]["network"])) { logger('Check user '.$user["url"]); poco_last_updated($user["url"], true); - if (++$checked > 100) + if (++$checked > 100) { return; - } else + } + } else { q("UPDATE `gcontact` SET `last_failure` = '%s' WHERE `nurl` = '%s'", dbesc(datetime_convert()), dbesc(normalise_link($user["url"]))); + } } } function discover_directory($search) { $data = Cache::get("dirsearch:".$search); - if (!is_null($data)){ + 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); @@ -111,7 +173,7 @@ function discover_directory($search) { $x = fetch_url(get_server()."/lsearch?p=1&n=500&search=".urlencode($search)); $j = json_decode($x); - if(count($j->results)) + 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)); @@ -119,32 +181,33 @@ function discover_directory($search) { logger("Profile ".$jj->url." already exists (".$search.")", LOGGER_DEBUG); if (($exists[0]["last_contact"] < $exists[0]["last_failure"]) AND - ($exists[0]["updated"] < $exists[0]["last_failure"])) + ($exists[0]["updated"] < $exists[0]["last_failure"])) { continue; - + } // Update the contact poco_last_updated($jj->url); continue; } - // Harcoded paths aren't so good. But in this case it is okay. - // First: We only will get Friendica contacts (which always are using this url schema) - // Second: There will be no further problems if we are doing a mistake - $server_url = preg_replace("=(https?://)(.*)/profile/(.*)=ism", "$1$2", $jj->url); - if ($server_url != $jj->url) + $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); + logger("Friendica server ".$server_url." seems to be okay.", LOGGER_DEBUG); + } - logger("Check if profile ".$jj->url." is reachable (".$search.")", LOGGER_DEBUG); $data = probe_url($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); poco_check($data["url"], $data["name"], $data["network"], $data["photo"], "", "", "", $jj->tags, $data["addr"], "", 0); + } 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); } @@ -164,14 +227,14 @@ function gs_search_user($search) { $url = "http://gstools.org/api/users_search/".urlencode($search); $result = z_fetch_url($url); - if (!$result["success"]) + if (!$result["success"]) { return false; - + } $contacts = json_decode($result["body"]); - if ($contacts->status == 'ERROR') + if ($contacts->status == 'ERROR') { return false; - + } foreach($contacts->data AS $user) { $contact = probe_url($user->site_address."/".$user->name); if ($contact["network"] != NETWORK_PHANTOM) { diff --git a/include/network.php b/include/network.php index b0e71fab7..f9d35c52c 100644 --- a/include/network.php +++ b/include/network.php @@ -72,8 +72,9 @@ function z_fetch_url($url,$binary = false, &$redirects = 0, $opts=array()) { $a = get_app(); $ch = @curl_init($url); - if(($redirects > 8) || (! $ch)) - return false; + if(($redirects > 8) || (! $ch)) { + return $ret; + } @curl_setopt($ch, CURLOPT_HEADER, true); diff --git a/include/socgraph.php b/include/socgraph.php index 01d2cff01..05f47e659 100644 --- a/include/socgraph.php +++ b/include/socgraph.php @@ -309,7 +309,18 @@ function poco_check($profile_url, $name, $network, $profile_photo, $about, $loca logger("profile-check generation: ".$generation." Network: ".$network." URL: ".$profile_url." name: ".$name." avatar: ".$profile_photo, LOGGER_DEBUG); - poco_check_server($server_url, $network); + // We check the server url to be sure that it is a real one + $server_url2 = poco_detect_server($profile_url); + + // We are no sure that it is a correct URL. So we use it in the future + if ($server_url2 != "") { + $server_url = $server_url2; + } + + // The server URL doesn't seem to be valid, so we don't store it. + if (!poco_check_server($server_url, $network)) { + $server_url = ""; + } $gcontact = array("url" => $profile_url, "addr" => $addr, @@ -401,13 +412,47 @@ function poco_detect_server($profile) { // Mastodon if ($server_url == "") { - $red = preg_replace("=(https?://)(.*)/users/(.*)=ism", "$1$2", $profile); - if ($red != $profile) { - $server_url = $red; + $mastodon = preg_replace("=(https?://)(.*)/users/(.*)=ism", "$1$2", $profile); + if ($mastodon != $profile) { + $server_url = $mastodon; $network = NETWORK_OSTATUS; } } + // Numeric OStatus variant + if ($server_url == "") { + $ostatus = preg_replace("=(https?://)(.*)/user/(.*)=ism", "$1$2", $profile); + if ($ostatus != $profile) { + $server_url = $ostatus; + $network = NETWORK_OSTATUS; + } + } + + // Wild guess + if ($server_url == "") { + $base = preg_replace("=(https?://)(.*?)/(.*)=ism", "$1$2", $profile); + if ($base != $profile) { + $server_url = $base; + $network = NETWORK_PHANTOM; + } + } + + if ($server_url == "") { + return ""; + } + + $r = q("SELECT `id` FROM `gserver` WHERE `nurl` = '%s' AND `last_contact` > `last_failure`", + dbesc(normalise_link($server_url))); + if (dbm::is_result($r)) { + return $server_url; + } + + // Fetch the host-meta to check if this really is a server + $serverret = z_fetch_url($server_url."/.well-known/host-meta"); + if (!$serverret["success"]) { + return ""; + } + return $server_url; } @@ -424,10 +469,12 @@ function poco_last_updated($profile, $force = false) { q("UPDATE `gcontact` SET `created` = '%s' WHERE `nurl` = '%s'", dbesc(datetime_convert()), dbesc(normalise_link($profile))); - if ($gcontacts[0]["server_url"] != "") + if ($gcontacts[0]["server_url"] != "") { $server_url = $gcontacts[0]["server_url"]; - else + } + if (($server_url == '') OR ($gcontacts[0]["server_url"] == $gcontacts[0]["nurl"])) { $server_url = poco_detect_server($profile); + } if (!in_array($gcontacts[0]["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_FEED, NETWORK_OSTATUS, ""))) { logger("Profile ".$profile.": Network type ".$gcontacts[0]["network"]." can't be checked", LOGGER_DEBUG); @@ -680,6 +727,213 @@ function poco_to_boolean($val) { return ($val); } +/** + * @brief Detect server type (Hubzilla or Friendica) via the poco data + * + * @param object $data POCO data + * @return array Server data + */ +function poco_detect_poco_data($data) { + $server = false; + + if (!isset($data->entry)) { + return false; + } + + if (count($data->entry) == 0) { + return false; + } + + if (!isset($data->entry[0]->urls)) { + return false; + } + + if (count($data->entry[0]->urls) == 0) { + return false; + } + + foreach ($data->entry[0]->urls AS $url) { + if ($url->type == 'zot') { + $server = array(); + $server["platform"] = 'Hubzilla'; + $server["network"] = NETWORK_DIASPORA; + return $server; + } + } + return false; +} + +/** + * @brief Detect server type by using the nodeinfo data + * + * @param string $server_url address of the server + * @return array Server data + */ +function poco_fetch_nodeinfo($server_url) { + $serverret = z_fetch_url($server_url."/.well-known/nodeinfo"); + if (!$serverret["success"]) { + return false; + } + + $nodeinfo = json_decode($serverret['body']); + + if (!is_object($nodeinfo)) { + return false; + } + + if (!is_array($nodeinfo->links)) { + return false; + } + + $nodeinfo_url = ''; + + foreach ($nodeinfo->links AS $link) { + if ($link->rel == 'http://nodeinfo.diaspora.software/ns/schema/1.0') { + $nodeinfo_url = $link->href; + } + } + + if ($nodeinfo_url == '') { + return false; + } + + $serverret = z_fetch_url($nodeinfo_url); + if (!$serverret["success"]) { + return false; + } + + $nodeinfo = json_decode($serverret['body']); + + if (!is_object($nodeinfo)) { + return false; + } + + $server = array(); + + $server['register_policy'] = REGISTER_CLOSED; + + if (is_bool($nodeinfo->openRegistrations) AND $nodeinfo->openRegistrations) { + $server['register_policy'] = REGISTER_OPEN; + } + + if (is_object($nodeinfo->software)) { + if (isset($nodeinfo->software->name)) { + $server['platform'] = $nodeinfo->software->name; + } + + if (isset($nodeinfo->software->version)) { + $server['version'] = $nodeinfo->software->version; + // Version numbers on Nodeinfo are presented with additional info, e.g.: + // 0.6.3.0-p1702cc1c, 0.6.99.0-p1b9ab160 or 3.4.3-2-1191. + $server['version'] = preg_replace("=(.+)-(.{4,})=ism", "$1", $server['version']); + } + } + + if (is_object($nodeinfo->metadata)) { + if (isset($nodeinfo->metadata->nodeName)) { + $server['site_name'] = $nodeinfo->metadata->nodeName; + } + } + + $diaspora = false; + $friendica = false; + $gnusocial = false; + + if (is_array($nodeinfo->protocols->inbound)) { + foreach ($nodeinfo->protocols->inbound AS $inbound) { + if ($inbound == 'diaspora') { + $diaspora = true; + } + if ($inbound == 'friendica') { + $friendica = true; + } + if ($inbound == 'gnusocial') { + $gnusocial = true; + } + } + } + + if ($gnusocial) { + $server['network'] = NETWORK_OSTATUS; + } + if ($diaspora) { + $server['network'] = NETWORK_DIASPORA; + } + if ($friendica) { + $server['network'] = NETWORK_DFRN; + } + + if (!$server) { + return false; + } + + return $server; +} + +/** + * @brief Detect server type (Hubzilla or Friendica) via the front page body + * + * @param string $body Front page of the server + * @return array Server data + */ +function poco_detect_server_type($body) { + $server = false; + + $doc = new \DOMDocument(); + @$doc->loadHTML($body); + $xpath = new \DomXPath($doc); + + $list = $xpath->query("//meta[@name]"); + + foreach ($list as $node) { + $attr = array(); + if ($node->attributes->length) { + foreach ($node->attributes as $attribute) { + $attr[$attribute->name] = $attribute->value; + } + } + if ($attr['name'] == 'generator') { + $version_part = explode(" ", $attr['content']); + if (count($version_part) == 2) { + if (in_array($version_part[0], array("Friendika", "Friendica"))) { + $server = array(); + $server["platform"] = $version_part[0]; + $server["version"] = $version_part[1]; + $server["network"] = NETWORK_DFRN; + } + } + } + } + + if (!$server) { + $list = $xpath->query("//meta[@property]"); + + foreach ($list as $node) { + $attr = array(); + if ($node->attributes->length) { + foreach ($node->attributes as $attribute) { + $attr[$attribute->name] = $attribute->value; + } + } + if ($attr['property'] == 'generator') { + if (in_array($attr['content'], array("hubzilla", "BlaBlaNet"))) { + $server = array(); + $server["platform"] = $attr['content']; + $server["version"] = ""; + $server["network"] = NETWORK_DIASPORA; + } + } + } + } + + if (!$server) { + return false; + } + + $server["site_name"] = $xpath->evaluate($element."//head/title/text()", $context)->item(0)->nodeValue; + return $server; +} + function poco_check_server($server_url, $network = "", $force = false) { // Unify the server address @@ -729,7 +983,9 @@ function poco_check_server($server_url, $network = "", $force = false) { logger("Server ".$server_url." is outdated or unknown. Start discovery. Force: ".$force." Created: ".$servers[0]["created"]." Failure: ".$last_failure." Contact: ".$last_contact, LOGGER_DEBUG); $failure = false; + $possible_failure = false; $orig_last_failure = $last_failure; + $orig_last_contact = $last_contact; // Check if the page is accessible via SSL. $orig_server_url = $server_url; @@ -769,18 +1025,58 @@ function poco_check_server($server_url, $network = "", $force = false) { $last_failure = datetime_convert(); $failure = true; } + $possible_failure = true; } elseif ($network == NETWORK_DIASPORA) $last_contact = datetime_convert(); + // If the server has no possible failure we reset the cached data + if (!$possible_failure) { + $version = ""; + $platform = ""; + $site_name = ""; + $info = ""; + $register_policy = -1; + } + + // Look for poco if (!$failure) { - // Test for Diaspora + $serverret = z_fetch_url($server_url."/poco"); + if ($serverret["success"]) { + $data = json_decode($serverret["body"]); + if (isset($data->totalResults)) { + $poco = $server_url."/poco"; + $last_contact = datetime_convert(); + + $server = poco_detect_poco_data($data); + if ($server) { + $platform = $server['platform']; + $network = $server['network']; + $version = ''; + $site_name = ''; + } + } + } + } + + if (!$failure) { + // Test for Diaspora, Hubzilla, Mastodon or older Friendica servers $serverret = z_fetch_url($server_url); - if (!$serverret["success"] OR ($serverret["body"] == "")) + if (!$serverret["success"] OR ($serverret["body"] == "")) { + $last_failure = datetime_convert(); $failure = true; - else { + } else { + $server = poco_detect_server_type($serverret["body"]); + if ($server) { + $platform = $server['platform']; + $network = $server['network']; + $version = $server['version']; + $site_name = $server['site_name']; + $last_contact = datetime_convert(); + } + $lines = explode("\n",$serverret["header"]); - if(count($lines)) + if(count($lines)) { foreach($lines as $line) { $line = trim($line); if(stristr($line,'X-Diaspora-Version:')) { @@ -790,6 +1086,7 @@ function poco_check_server($server_url, $network = "", $force = false) { $network = NETWORK_DIASPORA; $versionparts = explode("-", $version); $version = $versionparts[0]; + $last_contact = datetime_convert(); } if(stristr($line,'Server: Mastodon')) { @@ -797,12 +1094,14 @@ function poco_check_server($server_url, $network = "", $force = false) { $network = NETWORK_OSTATUS; // Mastodon doesn't reveal version numbers $version = ""; + $last_contact = datetime_convert(); } } + } } } - if (!$failure) { + if (!$failure AND ($poco == "")) { // Test for Statusnet // Will also return data for Friendica and GNU Social - but it will be overwritten later // The "not implemented" is a special treatment for really, really old Friendica versions @@ -810,8 +1109,11 @@ function poco_check_server($server_url, $network = "", $force = false) { if ($serverret["success"] AND ($serverret["body"] != '{"error":"not implemented"}') AND ($serverret["body"] != '') AND (strlen($serverret["body"]) < 30)) { $platform = "StatusNet"; - $version = trim($serverret["body"], '"'); + // Remove junk that some GNU Social servers return + $version = str_replace(chr(239).chr(187).chr(191), "", $serverret["body"]); + $version = trim($version, '"'); $network = NETWORK_OSTATUS; + $last_contact = datetime_convert(); } // Test for GNU Social @@ -819,17 +1121,32 @@ function poco_check_server($server_url, $network = "", $force = false) { if ($serverret["success"] AND ($serverret["body"] != '{"error":"not implemented"}') AND ($serverret["body"] != '') AND (strlen($serverret["body"]) < 30)) { $platform = "GNU Social"; - $version = trim($serverret["body"], '"'); + // Remove junk that some GNU Social servers return + $version = str_replace(chr(239).chr(187).chr(191), "", $serverret["body"]); + $version = trim($version, '"'); $network = NETWORK_OSTATUS; + $last_contact = datetime_convert(); } + } + if (!$failure) { + // Test for Hubzilla, Redmatrix or Friendica $serverret = z_fetch_url($server_url."/api/statusnet/config.json"); if ($serverret["success"]) { $data = json_decode($serverret["body"]); - if (isset($data->site->server)) { $last_contact = datetime_convert(); + if (isset($data->site->platform)) { + $platform = $data->site->platform->PLATFORM_NAME; + $version = $data->site->platform->STD_VERSION; + $network = NETWORK_DIASPORA; + } + if (isset($data->site->BlaBlaNet)) { + $platform = $data->site->BlaBlaNet->PLATFORM_NAME; + $version = $data->site->BlaBlaNet->STD_VERSION; + $network = NETWORK_DIASPORA; + } if (isset($data->site->hubzilla)) { $platform = $data->site->hubzilla->PLATFORM_NAME; $version = $data->site->hubzilla->RED_VERSION; @@ -866,32 +1183,66 @@ function poco_check_server($server_url, $network = "", $force = false) { } } + // Query statistics.json. Optional package for Diaspora, Friendica and Redmatrix if (!$failure) { $serverret = z_fetch_url($server_url."/statistics.json"); if ($serverret["success"]) { $data = json_decode($serverret["body"]); - if ($version == "") + if (isset($data->version)) { $version = $data->version; + // Version numbers on statistics.json are presented with additional info, e.g.: + // 0.6.3.0-p1702cc1c, 0.6.99.0-p1b9ab160 or 3.4.3-2-1191. + $version = preg_replace("=(.+)-(.{4,})=ism", "$1", $version); + } $site_name = $data->name; - if (isset($data->network) AND ($platform == "")) + if (isset($data->network)) { $platform = $data->network; + } - if ($platform == "Diaspora") + if ($platform == "Diaspora") { $network = NETWORK_DIASPORA; + } - if ($data->registrations_open) + if ($data->registrations_open) { $register_policy = REGISTER_OPEN; - else + } else { $register_policy = REGISTER_CLOSED; + } if (isset($data->version)) $last_contact = datetime_convert(); } } + // Query nodeinfo. Working for (at least) Diaspora and Friendica. + if (!$failure) { + $server = poco_fetch_nodeinfo($server_url); + if ($server) { + $register_policy = $server['register_policy']; + + if (isset($server['platform'])) { + $platform = $server['platform']; + } + + if (isset($server['network'])) { + $network = $server['network']; + } + + if (isset($server['version'])) { + $version = $server['version']; + } + + if (isset($server['site_name'])) { + $site_name = $server['site_name']; + } + + $last_contact = datetime_convert(); + } + } + // Check for noscrape // Friendica servers could be detected as OStatus servers if (!$failure AND in_array($network, array(NETWORK_DFRN, NETWORK_OSTATUS))) { @@ -929,16 +1280,21 @@ function poco_check_server($server_url, $network = "", $force = false) { } } - // Look for poco - if (!$failure) { - $serverret = z_fetch_url($server_url."/poco"); - if ($serverret["success"]) { - $data = json_decode($serverret["body"]); - if (isset($data->totalResults)) { - $poco = $server_url."/poco"; - $last_contact = datetime_convert(); - } - } + if ($possible_failure AND !$failure) { + $last_failure = datetime_convert(); + $failure = true; + } + + if ($failure) { + $last_contact = $orig_last_contact; + } else { + $last_failure = $orig_last_failure; + } + + if (($last_contact <= $last_failure) AND !$failure) { + logger("Server ".$server_url." seems to be alive, but last contact wasn't set - could be a bug", LOGGER_DEBUG); + } else if (($last_contact >= $last_failure) AND $failure) { + logger("Server ".$server_url." seems to be dead, but last failure wasn't set - could be a bug", LOGGER_DEBUG); } // Check again if the server exists @@ -949,7 +1305,7 @@ function poco_check_server($server_url, $network = "", $force = false) { $info = strip_tags($info); $platform = strip_tags($platform); - if ($servers) + if ($servers) { q("UPDATE `gserver` SET `url` = '%s', `version` = '%s', `site_name` = '%s', `info` = '%s', `register_policy` = %d, `poco` = '%s', `noscrape` = '%s', `network` = '%s', `platform` = '%s', `last_contact` = '%s', `last_failure` = '%s' WHERE `nurl` = '%s'", dbesc($server_url), @@ -965,7 +1321,7 @@ function poco_check_server($server_url, $network = "", $force = false) { dbesc($last_failure), dbesc(normalise_link($server_url)) ); - else + } elseif (!$failure) { q("INSERT INTO `gserver` (`url`, `nurl`, `version`, `site_name`, `info`, `register_policy`, `poco`, `noscrape`, `network`, `platform`, `created`, `last_contact`, `last_failure`) VALUES ('%s', '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s')", dbesc($server_url), @@ -983,7 +1339,7 @@ function poco_check_server($server_url, $network = "", $force = false) { dbesc($last_failure), dbesc(datetime_convert()) ); - + } logger("End discovery for server ".$server_url, LOGGER_DEBUG); return !$failure; @@ -1244,6 +1600,33 @@ function update_suggestions() { } } +/** + * @brief Fetch server list from remote servers and adds them when they are new. + * + * @param string $poco URL to the POCO endpoint + */ +function poco_fetch_serverlist($poco) { + $serverret = z_fetch_url($poco."/@server"); + if (!$serverret["success"]) { + return; + } + $serverlist = json_decode($serverret['body']); + + if (!is_array($serverlist)) { + return; + } + + foreach ($serverlist AS $server) { + $server_url = str_replace("/index.php", "", $server->url); + + $r = q("SELECT `nurl` FROM `gserver` WHERE `nurl` = '%s'", dbesc(normalise_link($server_url))); + if (!dbm::is_result($r)) { + logger("Call server check for server ".$server_url, LOGGER_DEBUG); + proc_run(PRIORITY_LOW, "include/discover_poco.php", "server", base64_encode($server_url)); + } + } +} + function poco_discover_federation() { $last = get_config('poco','last_federation_discovery'); @@ -1259,8 +1642,9 @@ function poco_discover_federation() { if ($serverdata) { $servers = json_decode($serverdata); - foreach($servers->pods AS $server) - poco_check_server("https://".$server->host); + foreach ($servers->pods AS $server) { + proc_run(PRIORITY_LOW, "include/discover_poco.php", "server", base64_encode("https://".$server->host)); + } } // Currently disabled, since the service isn't available anymore. @@ -1305,6 +1689,9 @@ function poco_discover($complete = false) { continue; } + // Discover new servers out there + poco_fetch_serverlist($server["poco"]); + // Fetch all users from the other server $url = $server["poco"]."/?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,contactType,generation"; @@ -1879,4 +2266,20 @@ function gs_discover() { q("UPDATE `gserver` SET `last_poco_query` = '%s' WHERE `nurl` = '%s'", dbesc(datetime_convert()), dbesc($server["nurl"])); } } + +/** + * @brief Returns a list of all known servers + * @return array List of server urls + */ +function poco_serverlist() { + $r = q("SELECT `url`, `site_name` AS `displayName`, `network`, `platform`, `version` FROM `gserver` + WHERE `network` IN ('%s', '%s', '%s') AND `last_contact` > `last_failure` + ORDER BY `last_contact` + LIMIT 1000", + dbesc(NETWORK_DFRN), dbesc(NETWORK_DIASPORA), dbesc(NETWORK_OSTATUS)); + if (!dbm::is_result($r)) { + return false; + } + return $r; +} ?> diff --git a/mod/admin.php b/mod/admin.php index b863eb909..b1bc8de5f 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -27,7 +27,7 @@ require_once("include/text.php"); function admin_post(App $a) { - if(!is_site_admin()) { + if (!is_site_admin()) { return; } @@ -39,7 +39,7 @@ function admin_post(App $a) { // urls if ($a->argc > 1) { - switch ($a->argv[1]){ + switch ($a->argv[1]) { case 'site': admin_page_site_post($a); break; @@ -47,10 +47,10 @@ function admin_post(App $a) { admin_page_users_post($a); break; case 'plugins': - if($a->argc > 2 && + if ($a->argc > 2 && is_file("addon/".$a->argv[2]."/".$a->argv[2].".php")) { @include_once("addon/".$a->argv[2]."/".$a->argv[2].".php"); - if(function_exists($a->argv[2].'_plugin_admin_post')) { + if (function_exists($a->argv[2].'_plugin_admin_post')) { $func = $a->argv[2].'_plugin_admin_post'; $func($a); } @@ -59,14 +59,16 @@ function admin_post(App $a) { return; // NOTREACHED break; case 'themes': - if($a->argc < 2) { - if(is_ajax()) return; + if ($a->argc < 2) { + if (is_ajax()) { + return; + } goaway('admin/'); return; } $theme = $a->argv[2]; - if(is_file("view/theme/$theme/config.php")){ + if (is_file("view/theme/$theme/config.php")) { function __call_theme_admin_post(App $a, $theme) { $orig_theme = $a->theme; $orig_page = $a->page; @@ -77,8 +79,10 @@ function admin_post(App $a) { $init = $theme."_init"; - if(function_exists($init)) $init($a); - if(function_exists("theme_admin_post")) { + if (function_exists($init)) { + $init($a); + } + if (function_exists("theme_admin_post")) { $admin_form = theme_admin_post($a); } @@ -90,8 +94,9 @@ function admin_post(App $a) { __call_theme_admin_post($a, $theme); } info(t('Theme settings updated.')); - if(is_ajax()) return; - + if (is_ajax()) { + return; + } goaway('admin/themes/'.$theme); return; break; @@ -130,7 +135,7 @@ function admin_post(App $a) { */ function admin_content(App $a) { - if(!is_site_admin()) { + if (!is_site_admin()) { return login(false); } @@ -168,7 +173,7 @@ function admin_content(App $a) { $r = q("SELECT `name` FROM `addon` WHERE `plugin_admin` = 1 ORDER BY `name`"); $aside_tools['plugins_admin']=array(); - foreach ($r as $h){ + foreach ($r as $h) { $plugin =$h['name']; $aside_tools['plugins_admin'][] = array("admin/plugins/".$plugin, $plugin, "plugin"); // temp plugins with admin @@ -199,8 +204,8 @@ function admin_content(App $a) { */ $o = ''; // urls - if($a->argc > 1) { - switch ($a->argv[1]){ + if ($a->argc > 1) { + switch ($a->argv[1]) { case 'site': $o = admin_page_site($a); break; @@ -238,7 +243,7 @@ function admin_content(App $a) { $o = admin_page_summary($a); } - if(is_ajax()) { + if (is_ajax()) { echo $o; killme(); return ''; @@ -270,8 +275,8 @@ function admin_page_federation(App $a) { // off one % two of them are needed in the query // Add more platforms if you like, when one returns 0 known nodes it is not // displayed on the stats page. - $platforms = array('Friendica', 'Diaspora', '%%red%%', 'Hubzilla', 'BlaBlaNet', 'GNU Social', 'StatusNet', 'Mastodon'); - $colors = array('Friendica' => '#ffc018', // orange from the logo + $platforms = array('Friendi%%a', 'Diaspora', '%%red%%', 'Hubzilla', 'BlaBlaNet', 'GNU Social', 'StatusNet', 'Mastodon'); + $colors = array('Friendi%%a' => '#ffc018', // orange from the logo 'Diaspora' => '#a1a1a1', // logo is black and white, makes a gray '%%red%%' => '#c50001', // fire red from the logo 'Hubzilla' => '#43488a', // blue from the logo @@ -310,19 +315,21 @@ function admin_page_federation(App $a) { // in the DB the Diaspora versions have the format x.x.x.x-xx the last // part (-xx) should be removed to clean up the versions from the "head // commit" information and combined into a single entry for x.x.x.x - if($p=='Diaspora') { + if ($p == 'Diaspora') { $newV = array(); $newVv = array(); - foreach($v as $vv) { + foreach ($v as $vv) { $newVC = $vv['total']; $newVV = $vv['version']; $posDash = strpos($newVV, '-'); - if($posDash) + if ($posDash) { $newVV = substr($newVV, 0, $posDash); - if(isset($newV[$newVV])) + } + if (isset($newV[$newVV])) { $newV[$newVV] += $newVC; - else + } else { $newV[$newVV] = $newVC; + } } foreach ($newV as $key => $value) { array_push($newVv, array('total'=>$value, 'version'=>$key)); @@ -333,7 +340,7 @@ function admin_page_federation(App $a) { // early friendica versions have the format x.x.xxxx where xxxx is the // DB version stamp; those should be operated out and versions be // conbined - if($p=='Friendica') { + if ($p == 'Friendi%%a') { $newV = array(); $newVv = array(); foreach ($v as $vv) { @@ -341,12 +348,14 @@ function admin_page_federation(App $a) { $newVV = $vv['version']; $lastDot = strrpos($newVV,'.'); $len = strlen($newVV)-1; - if(($lastDot == $len-4) && (!strrpos($newVV,'-rc')==$len-3)) + if (($lastDot == $len-4) && (!strrpos($newVV,'-rc') == $len-3)) { $newVV = substr($newVV, 0, $lastDot); - if(isset($newV[$newVV])) + } + if (isset($newV[$newVV])) { $newV[$newVV] += $newVC; - else + } else { $newV[$newVV] = $newVC; + } } foreach ($newV as $key => $value) { array_push($newVv, array('total'=>$value, 'version'=>$key)); @@ -455,7 +464,10 @@ function admin_page_summary(App $a) { ); $users=0; - foreach ($r as $u){ $accounts[$u['page-flags']][1] = $u['count']; $users+= $u['count']; } + foreach ($r as $u) { + $accounts[$u['page-flags']][1] = $u['count']; + $users+= $u['count']; + } logger('accounts: '.print_r($accounts,true),LOGGER_DATA); @@ -501,19 +513,19 @@ function admin_page_summary(App $a) { * @param App $a */ function admin_page_site_post(App $a) { - if(!x($_POST,"page_site")) { + if (!x($_POST,"page_site")) { return; } check_form_security_token_redirectOnErr('/admin/site', 'admin_site'); // relocate - if(x($_POST,'relocate') && x($_POST,'relocate_url') && $_POST['relocate_url']!="") { + if (x($_POST,'relocate') && x($_POST,'relocate_url') && $_POST['relocate_url'] != "") { $new_url = $_POST['relocate_url']; $new_url = rtrim($new_url,"/"); $parsed = @parse_url($new_url); - if(!$parsed || (!x($parsed,'host') || !x($parsed,'scheme'))) { + if (!$parsed || (!x($parsed,'host') || !x($parsed,'scheme'))) { notice(t("Can not parse base url. Must have at least ://")); goaway('admin/site'); } @@ -546,7 +558,7 @@ function admin_page_site_post(App $a) { $q = sprintf("UPDATE %s SET %s;", $table_name, $upds); $r = q($q); - if(!$r) { + if (!$r) { notice("Failed updating '$table_name': ".$db->error); goaway('admin/site'); } @@ -660,14 +672,14 @@ function admin_page_site_post(App $a) { $worker_fastlane = ((x($_POST,'worker_fastlane')) ? True : False); $worker_frontend = ((x($_POST,'worker_frontend')) ? True : False); - if($a->get_path() != "") + if ($a->get_path() != "") { $diaspora_enabled = false; - - if(!$thread_allow) + } + if (!$thread_allow) { $ostatus_disabled = true; - - if($ssl_policy != intval(get_config('system','ssl_policy'))) { - if($ssl_policy == SSL_POLICY_FULL) { + } + if ($ssl_policy != intval(get_config('system','ssl_policy'))) { + if ($ssl_policy == SSL_POLICY_FULL) { q("UPDATE `contact` SET `url` = REPLACE(`url` , 'http:' , 'https:'), `photo` = REPLACE(`photo` , 'http:' , 'https:'), @@ -685,8 +697,7 @@ function admin_page_site_post(App $a) { `thumb` = REPLACE(`thumb` , 'http:' , 'https:') WHERE 1 " ); - } - elseif($ssl_policy == SSL_POLICY_SELFSIGN) { + } elseif ($ssl_policy == SSL_POLICY_SELFSIGN) { q("UPDATE `contact` SET `url` = REPLACE(`url` , 'https:' , 'http:'), `photo` = REPLACE(`photo` , 'https:' , 'http:'), @@ -724,7 +735,7 @@ function admin_page_site_post(App $a) { set_config('system','shortcut_icon',$shortcut_icon); set_config('system','touch_icon',$touch_icon); - if($banner=="") { + if ($banner == "") { // don't know why, but del_config doesn't work... q("DELETE FROM `config` WHERE `cat` = '%s' AND `k` = '%s' LIMIT 1", dbesc("system"), @@ -734,7 +745,7 @@ function admin_page_site_post(App $a) { set_config('system','banner', $banner); } - if($info=="") { + if ($info == "") { del_config('config','info'); } else { set_config('config','info',$info); @@ -742,12 +753,12 @@ function admin_page_site_post(App $a) { set_config('system','language', $language); set_config('system','theme', $theme); - if($theme_mobile === '---') { + if ($theme_mobile === '---') { del_config('system','mobile-theme'); } else { set_config('system','mobile-theme', $theme_mobile); } - if($singleuser === '---') { + if ($singleuser === '---') { del_config('system','singleuser'); } else { set_config('system','singleuser', $singleuser); @@ -804,7 +815,7 @@ function admin_page_site_post(App $a) { set_config('system','worker_fastlane', $worker_fastlane); set_config('system','frontend_worker', $worker_frontend); - if($rino==2 and !function_exists('mcrypt_create_iv')) { + if (($rino == 2) and !function_exists('mcrypt_create_iv')) { notice(t("RINO2 needs mcrypt php extension to work.")); } else { set_config('system','rino_encrypt', $rino); @@ -832,7 +843,7 @@ function admin_page_site(App $a) { /* Installed langs */ $lang_choices = get_available_languages(); - if(strlen(get_config('system','directory_submit_url')) AND + if (strlen(get_config('system','directory_submit_url')) AND !strlen(get_config('system','directory'))) { set_config('system','directory', dirname(get_config('system','directory_submit_url'))); del_config('system','directory_submit_url'); @@ -843,12 +854,12 @@ function admin_page_site(App $a) { $theme_choices_mobile = array(); $theme_choices_mobile["---"] = t("No special theme for mobile devices"); $files = glob('view/theme/*'); - if($files) { + if ($files) { $allowed_theme_list = Config::get('system', 'allowed_themes'); - foreach($files as $file) { - if(intval(file_exists($file.'/unsupported'))) + foreach ($files as $file) { + if (intval(file_exists($file.'/unsupported'))) continue; $f = basename($file); @@ -860,7 +871,7 @@ function admin_page_site(App $a) { $theme_name = ((file_exists($file.'/experimental')) ? sprintf("%s - \x28Experimental\x29", $f) : $f); - if(file_exists($file.'/mobile')) { + if (file_exists($file.'/mobile')) { $theme_choices_mobile[$f] = $theme_name; } else { $theme_choices[$f] = $theme_name; @@ -909,8 +920,9 @@ function admin_page_site(App $a) { /* Banner */ $banner = get_config('system','banner'); - if($banner == false) + if ($banner == false) { $banner = 'logoFriendica'; + } $banner = htmlspecialchars($banner); $info = get_config('config','info'); $info = htmlspecialchars($info); @@ -934,9 +946,9 @@ function admin_page_site(App $a) { SSL_POLICY_SELFSIGN => t("Self-signed certificate, use SSL for local links only (discouraged)") ); - if($a->config['hostname'] == "") + if ($a->config['hostname'] == "") { $a->config['hostname'] = $a->get_hostname(); - + } $diaspora_able = ($a->get_path() == ""); $optimize_max_tablesize = Config::get('system','optimize_max_tablesize', 100); @@ -1070,42 +1082,45 @@ function admin_page_dbsync(App $a) { $o = ''; - if($a->argc > 3 && intval($a->argv[3]) && $a->argv[2] === 'mark') { + if ($a->argc > 3 && intval($a->argv[3]) && $a->argv[2] === 'mark') { set_config('database', 'update_'.intval($a->argv[3]), 'success'); $curr = get_config('system','build'); - if(intval($curr) == intval($a->argv[3])) + if (intval($curr) == intval($a->argv[3])) { set_config('system','build',intval($curr) + 1); + } info(t('Update has been marked successful').EOL); goaway('admin/dbsync'); } - if(($a->argc > 2) AND (intval($a->argv[2]) OR ($a->argv[2] === 'check'))) { + if (($a->argc > 2) AND (intval($a->argv[2]) OR ($a->argv[2] === 'check'))) { require_once("include/dbstructure.php"); $retval = update_structure(false, true); - if(!$retval) { + if (!$retval) { $o .= sprintf(t("Database structure update %s was successfully applied."), DB_UPDATE_VERSION)."
"; set_config('database', 'dbupdate_'.DB_UPDATE_VERSION, 'success'); - } else + } else { $o .= sprintf(t("Executing of database structure update %s failed with error: %s"), DB_UPDATE_VERSION, $retval)."
"; - if($a->argv[2] === 'check') + } + if ($a->argv[2] === 'check') { return $o; + } } - if($a->argc > 2 && intval($a->argv[2])) { + if ($a->argc > 2 && intval($a->argv[2])) { require_once('update.php'); $func = 'update_'.intval($a->argv[2]); - if(function_exists($func)) { + if (function_exists($func)) { $retval = $func(); - if($retval === UPDATE_FAILED) { + if ($retval === UPDATE_FAILED) { $o .= sprintf(t("Executing %s failed with error: %s"), $func, $retval); } - elseif($retval === UPDATE_SUCCESS) { + elseif ($retval === UPDATE_SUCCESS) { $o .= sprintf(t('Update %s was successfully applied.', $func)); set_config('database',$func, 'success'); - } - else + } else { $o .= sprintf(t('Update %s did not return a status. Unknown if it succeeded.'), $func); + } } else { $o .= sprintf(t('There was no additional update function %s that needed to be called.'), $func)."
"; set_config('database',$func, 'success'); @@ -1118,8 +1133,9 @@ function admin_page_dbsync(App $a) { if (dbm::is_result($r)) { foreach ($r as $rr) { $upd = intval(substr($rr['k'],7)); - if($upd < 1139 || $rr['v'] === 'success') + if ($upd < 1139 || $rr['v'] === 'success') { continue; + } $failed[] = $upd; } } @@ -1159,7 +1175,7 @@ function admin_page_users_post(App $a) { check_form_security_token_redirectOnErr('/admin/users', 'admin_users'); - if (!($nu_name==="") && !($nu_email==="") && !($nu_nickname==="")) { + if (!($nu_name === "") && !($nu_email === "") && !($nu_nickname === "")) { require_once('include/user.php'); $result = create_user(array('username'=>$nu_name, 'email'=>$nu_email, @@ -1210,31 +1226,31 @@ function admin_page_users_post(App $a) { } - if(x($_POST,'page_users_block')) { - foreach($users as $uid){ + if (x($_POST,'page_users_block')) { + foreach ($users as $uid) { q("UPDATE `user` SET `blocked` = 1-`blocked` WHERE `uid` = %s", intval($uid) ); } notice(sprintf(tt("%s user blocked/unblocked", "%s users blocked/unblocked", count($users)), count($users))); } - if(x($_POST,'page_users_delete')) { + if (x($_POST,'page_users_delete')) { require_once("include/Contact.php"); - foreach($users as $uid){ + foreach ($users as $uid) { user_remove($uid); } notice(sprintf(tt("%s user deleted", "%s users deleted", count($users)), count($users))); } - if(x($_POST,'page_users_approve')) { + if (x($_POST,'page_users_approve')) { require_once("mod/regmod.php"); - foreach($pending as $hash){ + foreach ($pending as $hash) { user_allow($hash); } } - if(x($_POST,'page_users_deny')) { + if (x($_POST,'page_users_deny')) { require_once("mod/regmod.php"); - foreach($pending as $hash){ + foreach ($pending as $hash) { user_deny($hash); } } @@ -1255,31 +1271,31 @@ function admin_page_users_post(App $a) { * @return string */ function admin_page_users(App $a) { - if($a->argc>2) { + if ($a->argc>2) { $uid = $a->argv[3]; $user = q("SELECT `username`, `blocked` FROM `user` WHERE `uid` = %d", intval($uid)); - if(count($user)==0) { + if (count($user) == 0) { notice('User not found'.EOL); goaway('admin/users'); return ''; // NOTREACHED } - switch($a->argv[2]){ - case "delete":{ + switch($a->argv[2]) { + case "delete": check_form_security_token_redirectOnErr('/admin/users', 'admin_users', 't'); // delete user require_once("include/Contact.php"); user_remove($uid); notice(sprintf(t("User '%s' deleted"), $user[0]['username']).EOL); - }; break; - case "block":{ + break; + case "block": check_form_security_token_redirectOnErr('/admin/users', 'admin_users', 't'); q("UPDATE `user` SET `blocked` = %d WHERE `uid` = %s", intval(1-$user[0]['blocked']), intval($uid) ); notice(sprintf(($user[0]['blocked']?t("User '%s' unblocked"):t("User '%s' blocked")) , $user[0]['username']).EOL); - }; break; + break; } goaway('admin/users'); return ''; // NOTREACHED @@ -1295,7 +1311,7 @@ function admin_page_users(App $a) { /* get users */ $total = qu("SELECT COUNT(*) AS `total` FROM `user` WHERE 1"); - if(count($total)) { + if (count($total)) { $a->set_pager_total($total[0]['total']); $a->set_pager_itemspage(100); } @@ -1312,22 +1328,22 @@ function admin_page_users(App $a) { $order = "contact.name"; $order_direction = "+"; - if (x($_GET,'o')){ + if (x($_GET,'o')) { $new_order = $_GET['o']; - if ($new_order[0]==="-") { + if ($new_order[0] === "-") { $order_direction = "-"; $new_order = substr($new_order,1); } - if (in_array($new_order, $valid_orders)){ + if (in_array($new_order, $valid_orders)) { $order = $new_order; } - if (x($_GET,'d')){ + if (x($_GET,'d')) { $new_direction = $_GET['d']; } } $sql_order = "`".str_replace('.','`.`',$order)."`"; - $sql_order_direction = ($order_direction==="+")?"ASC":"DESC"; + $sql_order_direction = ($order_direction === "+")?"ASC":"DESC"; $users = qu("SELECT `user`.*, `contact`.`name`, `contact`.`url`, `contact`.`micro`, `user`.`account_expired`, `contact`.`last-item` AS `lastitem_date` FROM `user` @@ -1341,7 +1357,7 @@ function admin_page_users(App $a) { //echo "
$users"; killme();
 
 	$adminlist = explode(",", str_replace(" ", "", $a->config['admin_email']));
-	$_setup_users = function ($e) use ($adminlist){
+	$_setup_users = function ($e) use ($adminlist) {
 		$accounts = array(
 			t('Normal Account'),
 			t('Soapbox Account'),
@@ -1367,22 +1383,21 @@ function admin_page_users(App $a) {
 	$tmp_users = array();
 	$deleted = array();
 
-	while(count($users)) {
+	while (count($users)) {
 		$new_user = array();
-		foreach(array_pop($users) as $k => $v) {
+		foreach (array_pop($users) as $k => $v) {
 			$k = str_replace('-','_',$k);
 			$new_user[$k] = $v;
 		}
-		if($new_user['deleted']) {
+		if ($new_user['deleted']) {
 			array_push($deleted, $new_user);
-		}
-		else {
+		} else {
 			array_push($tmp_users, $new_user);
 		}
 	}
 	//Reversing the two array, and moving $tmp_users to $users
 	array_reverse($deleted);
-	while(count($tmp_users)) {
+	while (count($tmp_users)) {
 		array_push($users, array_pop($tmp_users));
 	}
 
@@ -1459,19 +1474,19 @@ function admin_page_plugins(App $a) {
 	/*
 	 * Single plugin
 	 */
-	if($a->argc == 3) {
+	if ($a->argc == 3) {
 		$plugin = $a->argv[2];
-		if(!is_file("addon/$plugin/$plugin.php")) {
+		if (!is_file("addon/$plugin/$plugin.php")) {
 			notice(t("Item not found."));
 			return '';
 		}
 
-		if(x($_GET,"a") && $_GET['a']=="t") {
+		if (x($_GET,"a") && $_GET['a']=="t") {
 			check_form_security_token_redirectOnErr('/admin/plugins', 'admin_themes', 't');
 
 			// Toggle plugin status
 			$idx = array_search($plugin, $a->plugins);
-			if($idx !== false) {
+			if ($idx !== false) {
 				unset($a->plugins[$idx]);
 				uninstall_plugin($plugin);
 				info(sprintf(t("Plugin %s disabled."), $plugin));
@@ -1488,22 +1503,22 @@ function admin_page_plugins(App $a) {
 		// display plugin details
 		require_once('library/markdown.php');
 
-		if(in_array($plugin, $a->plugins)) {
+		if (in_array($plugin, $a->plugins)) {
 			$status="on"; $action= t("Disable");
 		} else {
 			$status="off"; $action= t("Enable");
 		}
 
 		$readme=Null;
-		if(is_file("addon/$plugin/README.md")) {
+		if (is_file("addon/$plugin/README.md")) {
 			$readme = file_get_contents("addon/$plugin/README.md");
 			$readme = Markdown($readme);
-		} elseif(is_file("addon/$plugin/README")) {
+		} elseif (is_file("addon/$plugin/README")) {
 			$readme = "
". file_get_contents("addon/$plugin/README") ."
"; } $admin_form=""; - if(is_array($a->plugins_admin) && in_array($plugin, $a->plugins_admin)) { + if (is_array($a->plugins_admin) && in_array($plugin, $a->plugins_admin)) { @require_once("addon/$plugin/$plugin.php"); $func = $plugin.'_plugin_admin'; $func($a, $admin_form); @@ -1595,8 +1610,8 @@ function admin_page_plugins(App $a) { */ function toggle_theme(&$themes,$th,&$result) { for($x = 0; $x < count($themes); $x ++) { - if($themes[$x]['name'] === $th) { - if($themes[$x]['allowed']) { + if ($themes[$x]['name'] === $th) { + if ($themes[$x]['allowed']) { $themes[$x]['allowed'] = 0; $result = 0; } @@ -1615,8 +1630,8 @@ function toggle_theme(&$themes,$th,&$result) { */ function theme_status($themes,$th) { for($x = 0; $x < count($themes); $x ++) { - if($themes[$x]['name'] === $th) { - if($themes[$x]['allowed']) { + if ($themes[$x]['name'] === $th) { + if ($themes[$x]['allowed']) { return 1; } else { @@ -1634,11 +1649,12 @@ function theme_status($themes,$th) { */ function rebuild_theme_table($themes) { $o = ''; - if(count($themes)) { - foreach($themes as $th) { - if($th['allowed']) { - if(strlen($o)) + if (count($themes)) { + foreach ($themes as $th) { + if ($th['allowed']) { + if (strlen($o)) { $o .= ','; + } $o .= $th['name']; } } @@ -1668,15 +1684,18 @@ function admin_page_themes(App $a) { $allowed_themes_str = get_config('system','allowed_themes'); $allowed_themes_raw = explode(',',$allowed_themes_str); $allowed_themes = array(); - if(count($allowed_themes_raw)) - foreach($allowed_themes_raw as $x) - if(strlen(trim($x))) + if (count($allowed_themes_raw)) { + foreach ($allowed_themes_raw as $x) { + if (strlen(trim($x))) { $allowed_themes[] = trim($x); + } + } + } $themes = array(); $files = glob('view/theme/*'); - if($files) { - foreach($files as $file) { + if ($files) { + foreach ($files as $file) { $f = basename($file); // Is there a style file? @@ -1691,12 +1710,13 @@ function admin_page_themes(App $a) { $is_supported = 1-(intval(file_exists($file.'/unsupported'))); $is_allowed = intval(in_array($f,$allowed_themes)); - if($is_allowed OR $is_supported OR get_config("system", "show_unsupported_themes")) + if ($is_allowed OR $is_supported OR get_config("system", "show_unsupported_themes")) { $themes[] = array('name' => $f, 'experimental' => $is_experimental, 'supported' => $is_supported, 'allowed' => $is_allowed); + } } } - if(! count($themes)) { + if (! count($themes)) { notice(t('No themes found.')); return ''; } @@ -1705,25 +1725,24 @@ function admin_page_themes(App $a) { * Single theme */ - if($a->argc == 3) { + if ($a->argc == 3) { $theme = $a->argv[2]; - if(! is_dir("view/theme/$theme")) { + if (! is_dir("view/theme/$theme")) { notice(t("Item not found.")); return ''; } - if(x($_GET,"a") && $_GET['a']=="t") { + if (x($_GET,"a") && $_GET['a']=="t") { check_form_security_token_redirectOnErr('/admin/themes', 'admin_themes', 't'); // Toggle theme status toggle_theme($themes,$theme,$result); $s = rebuild_theme_table($themes); - if($result) { + if ($result) { install_theme($theme); info(sprintf('Theme %s enabled.',$theme)); - } - else { + } else { uninstall_theme($theme); info(sprintf('Theme %s disabled.',$theme)); } @@ -1736,22 +1755,22 @@ function admin_page_themes(App $a) { // display theme details require_once('library/markdown.php'); - if(theme_status($themes,$theme)) { + if (theme_status($themes,$theme)) { $status="on"; $action= t("Disable"); } else { $status="off"; $action= t("Enable"); } - $readme=Null; - if(is_file("view/theme/$theme/README.md")) { + $readme = Null; + if (is_file("view/theme/$theme/README.md")) { $readme = file_get_contents("view/theme/$theme/README.md"); $readme = Markdown($readme); - } elseif(is_file("view/theme/$theme/README")) { + } elseif (is_file("view/theme/$theme/README")) { $readme = "
". file_get_contents("view/theme/$theme/README") ."
"; } - $admin_form=""; - if(is_file("view/theme/$theme/config.php")) { + $admin_form = ""; + if (is_file("view/theme/$theme/config.php")) { function __get_theme_admin_form(App $a, $theme) { $orig_theme = $a->theme; $orig_page = $a->page; @@ -1762,8 +1781,10 @@ function admin_page_themes(App $a) { $init = $theme."_init"; - if(function_exists($init)) $init($a); - if(function_exists("theme_admin")) { + if (function_exists($init)) { + $init($a); + } + if (function_exists("theme_admin")) { $admin_form = theme_admin($a); } @@ -1776,9 +1797,9 @@ function admin_page_themes(App $a) { } $screenshot = array(get_theme_screenshot($theme), t('Screenshot')); - if(! stristr($screenshot[0],$theme)) + if (! stristr($screenshot[0],$theme)) { $screenshot = null; - + } $t = get_markup_template("admin_plugins_details.tpl"); return replace_macros($t, array( @@ -1824,7 +1845,7 @@ function admin_page_themes(App $a) { $xthemes = array(); if ($themes) { - foreach($themes as $th) { + foreach ($themes as $th) { $xthemes[] = array($th['name'],(($th['allowed']) ? "on" : "off"), get_theme_info($th['name'])); } } @@ -1949,25 +1970,25 @@ function admin_page_viewlogs(App $a) { $f = get_config('system','logfile'); $data = ''; - if(!file_exists($f)) { + if (!file_exists($f)) { $data = t("Error trying to open $f log file.\r\n
Check to see if file $f exist and is readable."); - } - else { + } else { $fp = fopen($f, 'r'); - if(!$fp) { + if (!$fp) { $data = t("Couldn't open $f log file.\r\n
Check to see if file $f is readable."); - } - else { + } else { $fstat = fstat($fp); $size = $fstat['size']; - if($size != 0) { - if($size > 5000000 || $size < 0) + if ($size != 0) { + if ($size > 5000000 || $size < 0) { $size = 5000000; + } $seek = fseek($fp,0-$size,SEEK_END); - if($seek === 0) { + if ($seek === 0) { $data = escape_tags(fread($fp,$size)); - while(! feof($fp)) + while (! feof($fp)) { $data .= escape_tags(fread($fp,4096)); + } } } fclose($fp); @@ -1995,22 +2016,24 @@ function admin_page_features_post(App $a) { $arr = array(); $features = get_features(false); - foreach($features as $fname => $fdata) { - foreach(array_slice($fdata,1) as $f) { + foreach ($features as $fname => $fdata) { + foreach (array_slice($fdata,1) as $f) { $feature = $f[0]; $feature_state = 'feature_'.$feature; $featurelock = 'featurelock_'.$feature; - if(x($_POST[$feature_state])) + if (x($_POST[$feature_state])) { $val = intval($_POST['feature_'.$feature]); - else + } else { $val = 0; + } set_config('feature',$feature,$val); - if(x($_POST[$featurelock])) + if (x($_POST[$featurelock])) { set_config('feature_lock',$feature,$val); - else + } else { del_config('feature_lock',$feature); + } } } @@ -2034,18 +2057,19 @@ function admin_page_features_post(App $a) { */ function admin_page_features(App $a) { - if((argc() > 1) && (argv(1) === 'features')) { + if ((argc() > 1) && (argv(1) === 'features')) { $arr = array(); $features = get_features(false); - foreach($features as $fname => $fdata) { + foreach ($features as $fname => $fdata) { $arr[$fname] = array(); $arr[$fname][0] = $fdata[0]; - foreach(array_slice($fdata,1) as $f) { + foreach (array_slice($fdata,1) as $f) { $set = get_config('feature',$f[0]); - if($set === false) + if ($set === false) { $set = $f[3]; + } $arr[$fname][1][] = array( array('feature_' .$f[0],$f[1],$set,$f[2],array(t('Off'),t('On'))), array('featurelock_' .$f[0],sprintf(t('Lock feature %s'),$f[1]),(($f[4] !== false) ? "1" : ''),'',array(t('Off'),t('On'))) diff --git a/mod/poco.php b/mod/poco.php index 4ce075301..30648acab 100644 --- a/mod/poco.php +++ b/mod/poco.php @@ -7,14 +7,14 @@ function poco_init(App $a) { $system_mode = false; - if(intval(get_config('system','block_public')) || (get_config('system','block_local_dir'))) + if (intval(get_config('system','block_public')) || (get_config('system','block_local_dir'))) { http_status_exit(401); + } - - if($a->argc > 1) { + if ($a->argc > 1) { $user = notags(trim($a->argv[1])); } - if(! x($user)) { + if (! x($user)) { $c = q("SELECT * FROM `pconfig` WHERE `cat` = 'system' AND `k` = 'suggestme' AND `v` = 1"); if (! dbm::is_result($c)) { http_status_exit(401); @@ -27,42 +27,55 @@ function poco_init(App $a) { $justme = false; $global = false; - if($a->argc > 1 && $a->argv[1] === '@global') { + if ($a->argc > 1 && $a->argv[1] === '@server') { + // List of all servers that this server knows + $ret = poco_serverlist(); + header('Content-type: application/json'); + echo json_encode($ret); + killme(); + } + if ($a->argc > 1 && $a->argv[1] === '@global') { + // List of all profiles that this server recently had data from $global = true; $update_limit = date("Y-m-d H:i:s", time() - 30 * 86400); } - if($a->argc > 2 && $a->argv[2] === '@me') + if ($a->argc > 2 && $a->argv[2] === '@me') { $justme = true; - if($a->argc > 3 && $a->argv[3] === '@all') + } + if ($a->argc > 3 && $a->argv[3] === '@all') { $justme = false; - if($a->argc > 3 && $a->argv[3] === '@self') + } + if ($a->argc > 3 && $a->argv[3] === '@self') { $justme = true; - if($a->argc > 4 && intval($a->argv[4]) && $justme == false) + } + if ($a->argc > 4 && intval($a->argv[4]) && $justme == false) { $cid = intval($a->argv[4]); + } - - if(!$system_mode AND !$global) { + if (!$system_mode AND !$global) { $r = q("SELECT `user`.*,`profile`.`hide-friends` from user left join profile on `user`.`uid` = `profile`.`uid` where `user`.`nickname` = '%s' and `profile`.`is-default` = 1 limit 1", dbesc($user) ); - if(! dbm::is_result($r) || $r[0]['hidewall'] || $r[0]['hide-friends']) + if (! dbm::is_result($r) || $r[0]['hidewall'] || $r[0]['hide-friends']) { http_status_exit(404); + } $user = $r[0]; } - if($justme) + if ($justme) { $sql_extra = " AND `contact`.`self` = 1 "; + } // else // $sql_extra = " AND `contact`.`self` = 0 "; - if($cid) + if ($cid) { $sql_extra = sprintf(" AND `contact`.`id` = %d ",intval($cid)); - - if(x($_GET,'updatedSince')) + } + if (x($_GET,'updatedSince')) { $update_limit = date("Y-m-d H:i:s",strtotime($_GET['updatedSince'])); - + } if ($global) { $r = q("SELECT count(*) AS `total` FROM `gcontact` WHERE `updated` >= '%s' AND `updated` >= `last_failure` AND NOT `hide` AND `network` IN ('%s', '%s', '%s')", dbesc($update_limit), @@ -70,7 +83,7 @@ function poco_init(App $a) { dbesc(NETWORK_DIASPORA), dbesc(NETWORK_OSTATUS) ); - } elseif($system_mode) { + } elseif ($system_mode) { $r = q("SELECT count(*) AS `total` FROM `contact` WHERE `self` = 1 AND `uid` IN (SELECT `uid` FROM `pconfig` WHERE `cat` = 'system' AND `k` = 'suggestme' AND `v` = 1) "); } else { @@ -84,14 +97,15 @@ function poco_init(App $a) { dbesc(NETWORK_STATUSNET) ); } - if (dbm::is_result($r)) + if (dbm::is_result($r)) { $totalResults = intval($r[0]['total']); - else + } else { $totalResults = 0; - + } $startIndex = intval($_GET['startIndex']); - if(! $startIndex) + if (! $startIndex) { $startIndex = 0; + } $itemsPerPage = ((x($_GET,'count') && intval($_GET['count'])) ? intval($_GET['count']) : $totalResults); if ($global) { @@ -105,7 +119,7 @@ function poco_init(App $a) { intval($startIndex), intval($itemsPerPage) ); - } elseif($system_mode) { + } elseif ($system_mode) { logger("Start system mode query", LOGGER_DEBUG); $r = q("SELECT `contact`.*, `profile`.`about` AS `pabout`, `profile`.`locality` AS `plocation`, `profile`.`pub_keywords`, `profile`.`gender` AS `pgender`, `profile`.`address` AS `paddress`, `profile`.`region` AS `pregion`, @@ -134,13 +148,15 @@ function poco_init(App $a) { logger("Query done", LOGGER_DEBUG); $ret = array(); - if(x($_GET,'sorted')) + if (x($_GET,'sorted')) { $ret['sorted'] = false; - if(x($_GET,'filtered')) + } + if (x($_GET,'filtered')) { $ret['filtered'] = false; - if(x($_GET,'updatedSince') AND !$global) + } + if (x($_GET,'updatedSince') AND !$global) { $ret['updatedSince'] = false; - + } $ret['startIndex'] = (int) $startIndex; $ret['itemsPerPage'] = (int) $itemsPerPage; $ret['totalResults'] = (int) $totalResults; @@ -164,58 +180,61 @@ function poco_init(App $a) { 'generation' => false ); - if((! x($_GET,'fields')) || ($_GET['fields'] === '@all')) - foreach($fields_ret as $k => $v) + if ((! x($_GET,'fields')) || ($_GET['fields'] === '@all')) { + foreach ($fields_ret as $k => $v) { $fields_ret[$k] = true; - else { + } + } else { $fields_req = explode(',',$_GET['fields']); - foreach($fields_req as $f) + foreach ($fields_req as $f) { $fields_ret[trim($f)] = true; + } } - if(is_array($r)) { + if (is_array($r)) { if (dbm::is_result($r)) { foreach ($r as $rr) { if (!isset($rr['generation'])) { - if ($global) + if ($global) { $rr['generation'] = 3; - elseif ($system_mode) + } elseif ($system_mode) { $rr['generation'] = 1; - else + } else { $rr['generation'] = 2; + } } - if (($rr['about'] == "") AND isset($rr['pabout'])) + if (($rr['about'] == "") AND isset($rr['pabout'])) { $rr['about'] = $rr['pabout']; - + } if ($rr['location'] == "") { - if (isset($rr['plocation'])) + if (isset($rr['plocation'])) { $rr['location'] = $rr['plocation']; - + } if (isset($rr['pregion']) AND ($rr['pregion'] != "")) { - if ($rr['location'] != "") + if ($rr['location'] != "") { $rr['location'] .= ", "; - + } $rr['location'] .= $rr['pregion']; } if (isset($rr['pcountry']) AND ($rr['pcountry'] != "")) { - if ($rr['location'] != "") + if ($rr['location'] != "") { $rr['location'] .= ", "; - + } $rr['location'] .= $rr['pcountry']; } } - if (($rr['gender'] == "") AND isset($rr['pgender'])) + if (($rr['gender'] == "") AND isset($rr['pgender'])) { $rr['gender'] = $rr['pgender']; - - if (($rr['keywords'] == "") AND isset($rr['pub_keywords'])) + } + if (($rr['keywords'] == "") AND isset($rr['pub_keywords'])) { $rr['keywords'] = $rr['pub_keywords']; - - if (isset($rr['account-type'])) + } + if (isset($rr['account-type'])) { $rr['contact-type'] = $rr['account-type']; - + } $about = Cache::get("about:".$rr['updated'].":".$rr['nurl']); if (is_null($about)) { $about = bbcode($rr['about'], false, false); @@ -230,111 +249,122 @@ function poco_init(App $a) { } $entry = array(); - if($fields_ret['id']) + if ($fields_ret['id']) { $entry['id'] = (int)$rr['id']; - if($fields_ret['displayName']) - $entry['displayName'] = $rr['name']; - if($fields_ret['aboutMe']) - $entry['aboutMe'] = $about; - if($fields_ret['currentLocation']) - $entry['currentLocation'] = $rr['location']; - if($fields_ret['gender']) - $entry['gender'] = $rr['gender']; - if($fields_ret['generation']) - $entry['generation'] = (int)$rr['generation']; - if($fields_ret['urls']) { - $entry['urls'] = array(array('value' => $rr['url'], 'type' => 'profile')); - if($rr['addr'] && ($rr['network'] !== NETWORK_MAIL)) - $entry['urls'][] = array('value' => 'acct:' . $rr['addr'], 'type' => 'webfinger'); } - if($fields_ret['preferredUsername']) + if ($fields_ret['displayName']) { + $entry['displayName'] = $rr['name']; + } + if ($fields_ret['aboutMe']) { + $entry['aboutMe'] = $about; + } + if ($fields_ret['currentLocation']) { + $entry['currentLocation'] = $rr['location']; + } + if ($fields_ret['gender']) { + $entry['gender'] = $rr['gender']; + } + if ($fields_ret['generation']) { + $entry['generation'] = (int)$rr['generation']; + } + if ($fields_ret['urls']) { + $entry['urls'] = array(array('value' => $rr['url'], 'type' => 'profile')); + if ($rr['addr'] && ($rr['network'] !== NETWORK_MAIL)) { + $entry['urls'][] = array('value' => 'acct:' . $rr['addr'], 'type' => 'webfinger'); + } + } + if ($fields_ret['preferredUsername']) { $entry['preferredUsername'] = $rr['nick']; - if($fields_ret['updated']) { + } + if ($fields_ret['updated']) { if (!$global) { $entry['updated'] = $rr['success_update']; - if ($rr['name-date'] > $entry['updated']) + if ($rr['name-date'] > $entry['updated']) { $entry['updated'] = $rr['name-date']; - - if ($rr['uri-date'] > $entry['updated']) + } + if ($rr['uri-date'] > $entry['updated']) { $entry['updated'] = $rr['uri-date']; - - if ($rr['avatar-date'] > $entry['updated']) + } + if ($rr['avatar-date'] > $entry['updated']) { $entry['updated'] = $rr['avatar-date']; - } else + } + } else { $entry['updated'] = $rr['updated']; - + } $entry['updated'] = date("c", strtotime($entry['updated'])); } - if($fields_ret['photos']) + if ($fields_ret['photos']) { $entry['photos'] = array(array('value' => $rr['photo'], 'type' => 'profile')); - if($fields_ret['network']) { - $entry['network'] = $rr['network']; - if ($entry['network'] == NETWORK_STATUSNET) - $entry['network'] = NETWORK_OSTATUS; - if (($entry['network'] == "") AND ($rr['self'])) - $entry['network'] = NETWORK_DFRN; } - if($fields_ret['tags']) { + if ($fields_ret['network']) { + $entry['network'] = $rr['network']; + if ($entry['network'] == NETWORK_STATUSNET) { + $entry['network'] = NETWORK_OSTATUS; + } + if (($entry['network'] == "") AND ($rr['self'])) { + $entry['network'] = NETWORK_DFRN; + } + } + if ($fields_ret['tags']) { $tags = str_replace(","," ",$rr['keywords']); $tags = explode(" ", $tags); $cleaned = array(); foreach ($tags as $tag) { $tag = trim(strtolower($tag)); - if ($tag != "") + if ($tag != "") { $cleaned[] = $tag; + } } $entry['tags'] = array($cleaned); } - if($fields_ret['address']) { + if ($fields_ret['address']) { $entry['address'] = array(); // Deactivated. It just reveals too much data. (Although its from the default profile) //if (isset($rr['paddress'])) // $entry['address']['streetAddress'] = $rr['paddress']; - if (isset($rr['plocation'])) + if (isset($rr['plocation'])) { $entry['address']['locality'] = $rr['plocation']; - - if (isset($rr['pregion'])) + } + if (isset($rr['pregion'])) { $entry['address']['region'] = $rr['pregion']; - + } // See above //if (isset($rr['ppostalcode'])) // $entry['address']['postalCode'] = $rr['ppostalcode']; - if (isset($rr['pcountry'])) + if (isset($rr['pcountry'])) { $entry['address']['country'] = $rr['pcountry']; + } } - if($fields_ret['contactType']) + if ($fields_ret['contactType']) { $entry['contactType'] = intval($rr['contact-type']); - + } $ret['entry'][] = $entry; } - } - else + } else { $ret['entry'][] = array(); - } - else + } + } else { http_status_exit(500); - + } logger("End of poco", LOGGER_DEBUG); - if($format === 'xml') { + if ($format === 'xml') { header('Content-type: text/xml'); echo replace_macros(get_markup_template('poco_xml.tpl'),array_xmlify(array('$response' => $ret))); killme(); } - if($format === 'json') { + if ($format === 'json') { header('Content-type: application/json'); echo json_encode($ret); killme(); - } - else + } else { http_status_exit(500); - - + } }