Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

293 lines
8.5KB

  1. <?php
  2. use Friendica\Core\Config;
  3. require_once 'include/probe.php';
  4. require_once 'include/socgraph.php';
  5. require_once 'include/datetime.php';
  6. function discover_poco_run(&$argv, &$argc) {
  7. /*
  8. This function can be called in these ways:
  9. - dirsearch <search pattern>: Searches for "search pattern" in the directory. "search pattern" is url encoded.
  10. - checkcontact: Updates gcontact entries
  11. - suggestions: Discover other servers for their contacts.
  12. - server <poco url>: Searches for the poco server list. "poco url" is base64 encoded.
  13. - update_server: Frequently check the first 250 servers for vitality.
  14. - update_server_directory: Discover the given server id for their contacts
  15. - poco_load: Load POCO data from a given POCO address
  16. - check_profile: Update remote profile data
  17. */
  18. if (($argc > 2) && ($argv[1] == "dirsearch")) {
  19. $search = urldecode($argv[2]);
  20. $mode = 1;
  21. } elseif (($argc == 2) && ($argv[1] == "checkcontact")) {
  22. $mode = 2;
  23. } elseif (($argc == 2) && ($argv[1] == "suggestions")) {
  24. $mode = 3;
  25. } elseif (($argc == 3) && ($argv[1] == "server")) {
  26. $mode = 4;
  27. } elseif (($argc == 2) && ($argv[1] == "update_server")) {
  28. $mode = 5;
  29. } elseif (($argc == 3) && ($argv[1] == "update_server_directory")) {
  30. $mode = 6;
  31. } elseif (($argc > 5) && ($argv[1] == "poco_load")) {
  32. $mode = 7;
  33. } elseif (($argc == 3) && ($argv[1] == "check_profile")) {
  34. $mode = 8;
  35. } elseif ($argc == 1) {
  36. $search = "";
  37. $mode = 0;
  38. } else {
  39. die("Unknown or missing parameter ".$argv[1]."\n");
  40. }
  41. logger('start '.$search);
  42. if ($mode == 8) {
  43. $profile_url = base64_decode($argv[2]);
  44. if ($profile_url != "") {
  45. poco_last_updated($profile_url, true);
  46. }
  47. } elseif ($mode == 7) {
  48. if ($argc == 6) {
  49. $url = base64_decode($argv[5]);
  50. } else {
  51. $url = '';
  52. }
  53. poco_load_worker(intval($argv[2]), intval($argv[3]), intval($argv[4]), $url);
  54. } elseif ($mode == 6) {
  55. poco_discover_single_server(intval($argv[2]));
  56. } elseif ($mode == 5) {
  57. update_server();
  58. } elseif ($mode == 4) {
  59. $server_url = base64_decode($argv[2]);
  60. if ($server_url == "") {
  61. return;
  62. }
  63. $server_url = filter_var($server_url, FILTER_SANITIZE_URL);
  64. if (substr(normalise_link($server_url), 0, 7) != "http://") {
  65. return;
  66. }
  67. $result = "Checking server ".$server_url." - ";
  68. $ret = poco_check_server($server_url);
  69. if ($ret) {
  70. $result .= "success";
  71. } else {
  72. $result .= "failed";
  73. }
  74. logger($result, LOGGER_DEBUG);
  75. } elseif ($mode == 3) {
  76. update_suggestions();
  77. } elseif (($mode == 2) && get_config('system','poco_completion')) {
  78. discover_users();
  79. } elseif (($mode == 1) && ($search != "") && get_config('system','poco_local_search')) {
  80. discover_directory($search);
  81. gs_search_user($search);
  82. } elseif (($mode == 0) && ($search == "") && (get_config('system','poco_discovery') > 0)) {
  83. // Query Friendica and Hubzilla servers for their users
  84. poco_discover();
  85. // Query GNU Social servers for their users ("statistics" addon has to be enabled on the GS server)
  86. if (!get_config('system','ostatus_disabled'))
  87. gs_discover();
  88. }
  89. logger('end '.$search);
  90. return;
  91. }
  92. /**
  93. * @brief Updates the first 250 servers
  94. *
  95. */
  96. function update_server() {
  97. $r = q("SELECT `url`, `created`, `last_failure`, `last_contact` FROM `gserver` ORDER BY rand()");
  98. if (!dbm::is_result($r)) {
  99. return;
  100. }
  101. $updated = 0;
  102. foreach ($r AS $server) {
  103. if (!poco_do_update($server["created"], "", $server["last_failure"], $server["last_contact"])) {
  104. continue;
  105. }
  106. logger('Update server status for server '.$server["url"], LOGGER_DEBUG);
  107. proc_run(PRIORITY_LOW, "include/discover_poco.php", "server", base64_encode($server["url"]));
  108. if (++$updated > 250) {
  109. return;
  110. }
  111. }
  112. }
  113. function discover_users() {
  114. logger("Discover users", LOGGER_DEBUG);
  115. $starttime = time();
  116. $users = q("SELECT `url`, `created`, `updated`, `last_failure`, `last_contact`, `server_url`, `network` FROM `gcontact`
  117. WHERE `last_contact` < UTC_TIMESTAMP - INTERVAL 1 MONTH AND
  118. `last_failure` < UTC_TIMESTAMP - INTERVAL 1 MONTH AND
  119. `network` IN ('%s', '%s', '%s', '%s', '') ORDER BY rand()",
  120. dbesc(NETWORK_DFRN), dbesc(NETWORK_DIASPORA),
  121. dbesc(NETWORK_OSTATUS), dbesc(NETWORK_FEED));
  122. if (!$users) {
  123. return;
  124. }
  125. $checked = 0;
  126. foreach ($users AS $user) {
  127. $urlparts = parse_url($user["url"]);
  128. if (!isset($urlparts["scheme"])) {
  129. q("UPDATE `gcontact` SET `network` = '%s' WHERE `nurl` = '%s'",
  130. dbesc(NETWORK_PHANTOM), dbesc(normalise_link($user["url"])));
  131. continue;
  132. }
  133. if (in_array($urlparts["host"], array("www.facebook.com", "facebook.com", "twitter.com",
  134. "identi.ca", "alpha.app.net"))) {
  135. $networks = array("www.facebook.com" => NETWORK_FACEBOOK,
  136. "facebook.com" => NETWORK_FACEBOOK,
  137. "twitter.com" => NETWORK_TWITTER,
  138. "identi.ca" => NETWORK_PUMPIO,
  139. "alpha.app.net" => NETWORK_APPNET);
  140. q("UPDATE `gcontact` SET `network` = '%s' WHERE `nurl` = '%s'",
  141. dbesc($networks[$urlparts["host"]]), dbesc(normalise_link($user["url"])));
  142. continue;
  143. }
  144. $server_url = poco_detect_server($user["url"]);
  145. $force_update = false;
  146. if ($user["server_url"] != "") {
  147. $force_update = (normalise_link($user["server_url"]) != normalise_link($server_url));
  148. $server_url = $user["server_url"];
  149. }
  150. if ((($server_url == "") && ($user["network"] == NETWORK_FEED)) || $force_update || poco_check_server($server_url, $user["network"])) {
  151. logger('Check profile '.$user["url"]);
  152. proc_run(PRIORITY_LOW, "include/discover_poco.php", "check_profile", base64_encode($user["url"]));
  153. if (++$checked > 100) {
  154. return;
  155. }
  156. } else {
  157. q("UPDATE `gcontact` SET `last_failure` = '%s' WHERE `nurl` = '%s'",
  158. dbesc(datetime_convert()), dbesc(normalise_link($user["url"])));
  159. }
  160. // Quit the loop after 3 minutes
  161. if (time() > ($starttime + 180)) {
  162. return;
  163. }
  164. }
  165. }
  166. function discover_directory($search) {
  167. $data = Cache::get("dirsearch:".$search);
  168. if (!is_null($data)) {
  169. // Only search for the same item every 24 hours
  170. if (time() < $data + (60 * 60 * 24)) {
  171. logger("Already searched for ".$search." in the last 24 hours", LOGGER_DEBUG);
  172. return;
  173. }
  174. }
  175. $x = fetch_url(get_server()."/lsearch?p=1&n=500&search=".urlencode($search));
  176. $j = json_decode($x);
  177. if (count($j->results)) {
  178. foreach ($j->results as $jj) {
  179. // Check if the contact already exists
  180. $exists = q("SELECT `id`, `last_contact`, `last_failure`, `updated` FROM `gcontact` WHERE `nurl` = '%s'", normalise_link($jj->url));
  181. if (dbm::is_result($exists)) {
  182. logger("Profile ".$jj->url." already exists (".$search.")", LOGGER_DEBUG);
  183. if (($exists[0]["last_contact"] < $exists[0]["last_failure"]) &&
  184. ($exists[0]["updated"] < $exists[0]["last_failure"])) {
  185. continue;
  186. }
  187. // Update the contact
  188. poco_last_updated($jj->url);
  189. continue;
  190. }
  191. $server_url = poco_detect_server($jj->url);
  192. if ($server_url != '') {
  193. if (!poco_check_server($server_url)) {
  194. logger("Friendica server ".$server_url." doesn't answer.", LOGGER_DEBUG);
  195. continue;
  196. }
  197. logger("Friendica server ".$server_url." seems to be okay.", LOGGER_DEBUG);
  198. }
  199. $data = probe_url($jj->url);
  200. if ($data["network"] == NETWORK_DFRN) {
  201. logger("Profile ".$jj->url." is reachable (".$search.")", LOGGER_DEBUG);
  202. logger("Add profile ".$jj->url." to local directory (".$search.")", LOGGER_DEBUG);
  203. if ($jj->tags != "") {
  204. $data["keywords"] = $jj->tags;
  205. }
  206. $data["server_url"] = $data["baseurl"];
  207. update_gcontact($data);
  208. } else {
  209. logger("Profile ".$jj->url." is not responding or no Friendica contact - but network ".$data["network"], LOGGER_DEBUG);
  210. }
  211. }
  212. }
  213. Cache::set("dirsearch:".$search, time(), CACHE_DAY);
  214. }
  215. /**
  216. * @brief Search for GNU Social user with gstools.org
  217. *
  218. * @param str $search User name
  219. */
  220. function gs_search_user($search) {
  221. // Currently disabled, since the service isn't available anymore.
  222. // It is not removed since I hope that there will be a successor.
  223. return false;
  224. $a = get_app();
  225. $url = "http://gstools.org/api/users_search/".urlencode($search);
  226. $result = z_fetch_url($url);
  227. if (!$result["success"]) {
  228. return false;
  229. }
  230. $contacts = json_decode($result["body"]);
  231. if ($contacts->status == 'ERROR') {
  232. return false;
  233. }
  234. /// @TODO AS is considered as a notation for constants (as they usually being written all upper-case)
  235. /// @TODO find all those and convert to all lower-case which is a keyword then
  236. foreach ($contacts->data AS $user) {
  237. $contact = probe_url($user->site_address."/".$user->name);
  238. if ($contact["network"] != NETWORK_PHANTOM) {
  239. $contact["about"] = $user->description;
  240. update_gcontact($contact);
  241. }
  242. }
  243. }