]> git.mxchange.org Git - friendica.git/blob - include/socgraph.php
Some code beautification.
[friendica.git] / include / socgraph.php
1 <?php
2
3 require_once('include/datetime.php');
4 require_once("include/Scrape.php");
5 require_once("include/html2bbcode.php");
6
7 /*
8  To-Do:
9  - Move GNU Social URL schemata (http://server.tld/user/number) to http://server.tld/username
10  - Fetch profile data from profile page for Redmatrix users
11  - Detect if it is a forum
12 */
13
14 /*
15  * poco_load
16  *
17  * Given a contact-id (minimum), load the PortableContacts friend list for that contact,
18  * and add the entries to the gcontact (Global Contact) table, or update existing entries
19  * if anything (name or photo) has changed.
20  * We use normalised urls for comparison which ignore http vs https and www.domain vs domain
21  *
22  * Once the global contact is stored add (if necessary) the contact linkage which associates
23  * the given uid, cid to the global contact entry. There can be many uid/cid combinations
24  * pointing to the same global contact id.
25  *
26  */
27
28
29
30
31 function poco_load($cid,$uid = 0,$zcid = 0,$url = null) {
32
33         $a = get_app();
34
35         if($cid) {
36                 if((! $url) || (! $uid)) {
37                         $r = q("select `poco`, `uid` from `contact` where `id` = %d limit 1",
38                                 intval($cid)
39                         );
40                         if(count($r)) {
41                                 $url = $r[0]['poco'];
42                                 $uid = $r[0]['uid'];
43                         }
44                 }
45                 if(! $uid)
46                         return;
47         }
48
49         if(! $url)
50                 return;
51
52         $url = $url . (($uid) ? '/@me/@all?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,generation' : '?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,generation') ;
53
54         logger('poco_load: ' . $url, LOGGER_DEBUG);
55
56         $s = fetch_url($url);
57
58         logger('poco_load: returns ' . $s, LOGGER_DATA);
59
60         logger('poco_load: return code: ' . $a->get_curl_code(), LOGGER_DEBUG);
61
62         if(($a->get_curl_code() > 299) || (! $s))
63                 return;
64
65         $j = json_decode($s);
66
67         logger('poco_load: json: ' . print_r($j,true),LOGGER_DATA);
68
69         if(! isset($j->entry))
70                 return;
71
72         $total = 0;
73         foreach($j->entry as $entry) {
74
75                 $total ++;
76                 $profile_url = '';
77                 $profile_photo = '';
78                 $connect_url = '';
79                 $name = '';
80                 $network = '';
81                 $updated = '0000-00-00 00:00:00';
82                 $location = '';
83                 $about = '';
84                 $keywords = '';
85                 $gender = '';
86                 $generation = 0;
87
88                 $name = $entry->displayName;
89
90                 if(isset($entry->urls)) {
91                         foreach($entry->urls as $url) {
92                                 if($url->type == 'profile') {
93                                         $profile_url = $url->value;
94                                         continue;
95                                 }
96                                 if($url->type == 'webfinger') {
97                                         $connect_url = str_replace('acct:' , '', $url->value);
98                                         continue;
99                                 }
100                         }
101                 }
102                 if(isset($entry->photos)) {
103                         foreach($entry->photos as $photo) {
104                                 if($photo->type == 'profile') {
105                                         $profile_photo = $photo->value;
106                                         continue;
107                                 }
108                         }
109                 }
110
111                 if(isset($entry->updated))
112                         $updated = date("Y-m-d H:i:s", strtotime($entry->updated));
113
114                 if(isset($entry->network))
115                         $network = $entry->network;
116
117                 if(isset($entry->currentLocation))
118                         $location = $entry->currentLocation;
119
120                 if(isset($entry->aboutMe))
121                         $about = html2bbcode($entry->aboutMe);
122
123                 if(isset($entry->gender))
124                         $gender = $entry->gender;
125
126                 if(isset($entry->generation) AND ($entry->generation > 0))
127                         $generation = ++$entry->generation;
128
129                 if(isset($entry->tags))
130                         foreach($entry->tags as $tag)
131                                 $keywords = implode(", ", $tag);
132
133                 // If you query a Friendica server for its profiles, the network has to be Friendica
134                 // To-Do: It could also be a Redmatrix server
135                 //if ($uid == 0)
136                 //      $network = NETWORK_DFRN;
137
138                 poco_check($profile_url, $name, $network, $profile_photo, $about, $location, $gender, $keywords, $connect_url, $updated, $generation, $cid, $uid, $zcid);
139
140                 // Update the Friendica contacts. Diaspora is doing it via a message. (See include/diaspora.php)
141                 if (($location != "") OR ($about != "") OR ($keywords != "") OR ($gender != ""))
142                         q("UPDATE `contact` SET `location` = '%s', `about` = '%s', `keywords` = '%s', `gender` = '%s'
143                                 WHERE `nurl` = '%s' AND NOT `self` AND `network` = '%s'",
144                                 dbesc($location),
145                                 dbesc($about),
146                                 dbesc($keywords),
147                                 dbesc($gender),
148                                 dbesc(normalise_link($profile_url)),
149                                 dbesc(NETWORK_DFRN));
150         }
151         logger("poco_load: loaded $total entries",LOGGER_DEBUG);
152
153         q("DELETE FROM `glink` WHERE `cid` = %d AND `uid` = %d AND `zcid` = %d AND `updated` < UTC_TIMESTAMP - INTERVAL 2 DAY",
154                 intval($cid),
155                 intval($uid),
156                 intval($zcid)
157         );
158
159 }
160
161 function poco_check($profile_url, $name, $network, $profile_photo, $about, $location, $gender, $keywords, $connect_url, $updated, $generation, $cid = 0, $uid = 0, $zcid = 0) {
162
163         $a = get_app();
164
165         // Generation:
166         //  0: No definition
167         //  1: Profiles on this server
168         //  2: Contacts of profiles on this server
169         //  3: Contacts of contacts of profiles on this server
170         //  4: ...
171
172         $gcid = "";
173
174         if ($profile_url == "")
175                 return $gcid;
176
177         $urlparts = parse_url($profile_url);
178         if (!isset($urlparts["scheme"]))
179                 return $gcid;
180
181         if (in_array($urlparts["host"], array("www.facebook.com", "facebook.com", "twitter.com",
182                                                 "identi.ca", "alpha.app.net")))
183                 return $gcid;
184
185         $orig_updated = $updated;
186
187         // Don't store the statusnet connector as network
188         // We can't simply set this to NETWORK_OSTATUS since the connector could have fetched posts from friendica as well
189         if ($network == NETWORK_STATUSNET)
190                 $network = "";
191
192         // The global contacts should contain the original picture, not the cached one
193         if (($generation != 1) AND stristr(normalise_link($profile_photo), normalise_link($a->get_baseurl()."/photo/")))
194                 $profile_photo = "";
195
196         $r = q("SELECT `network` FROM `contact` WHERE `nurl` = '%s' AND `network` != '' AND `network` != '%s' LIMIT 1",
197                 dbesc(normalise_link($profile_url)), dbesc(NETWORK_STATUSNET)
198         );
199         if(count($r))
200                 $network = $r[0]["network"];
201
202         if (($network == "") OR ($network == NETWORK_OSTATUS)) {
203                 $r = q("SELECT `network`, `url` FROM `contact` WHERE `alias` IN ('%s', '%s') AND `network` != '' AND `network` != '%s' LIMIT 1",
204                         dbesc($profile_url), dbesc(normalise_link($profile_url)), dbesc(NETWORK_STATUSNET)
205                 );
206                 if(count($r)) {
207                         $network = $r[0]["network"];
208                         $profile_url = $r[0]["url"];
209                 }
210         }
211
212         $x = q("SELECT * FROM `gcontact` WHERE `nurl` = '%s' LIMIT 1",
213                 dbesc(normalise_link($profile_url))
214         );
215
216         if (count($x)) {
217                 if (($network == "") AND ($x[0]["network"] != NETWORK_STATUSNET))
218                         $network = $x[0]["network"];
219
220                 if ($updated == "0000-00-00 00:00:00")
221                         $updated = $x[0]["updated"];
222
223                 $created = $x[0]["created"];
224                 $server_url = $x[0]["server_url"];
225                 $nick = $x[0]["nick"];
226         } else {
227                 $created = "0000-00-00 00:00:00";
228                 $server_url = "";
229
230                 $urlparts = parse_url($profile_url);
231                 $nick = end(explode("/", $urlparts["path"]));
232         }
233
234         if ((($network == "") OR ($name == "") OR ($profile_photo == "") OR ($server_url == ""))
235                 AND poco_reachable($profile_url, $server_url, $network, true)) {
236                 $data = probe_url($profile_url);
237
238                 $network = $data["network"];
239                 $name = $data["name"];
240                 $nick = $data["nick"];
241                 $profile_url = $data["url"];
242                 $profile_photo = $data["photo"];
243                 $server_url = $data["baseurl"];
244         }
245
246         if (count($x) AND ($x[0]["network"] == "") AND ($network != "")) {
247                 q("UPDATE `gcontact` SET `network` = '%s' WHERE `nurl` = '%s'",
248                         dbesc($network),
249                         dbesc(normalise_link($profile_url))
250                 );
251         }
252
253         if (($name == "") OR ($profile_photo == ""))
254                 return $gcid;
255
256         if (!in_array($network, array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_DIASPORA)))
257                 return $gcid;
258
259         logger("profile-check generation: ".$generation." Network: ".$network." URL: ".$profile_url." name: ".$name." avatar: ".$profile_photo, LOGGER_DEBUG);
260
261         poco_check_server($server_url, $network);
262
263         if(count($x)) {
264                 $gcid = $x[0]['id'];
265
266                 if (($location == "") AND ($x[0]['location'] != ""))
267                         $location = $x[0]['location'];
268
269                 if (($about == "") AND ($x[0]['about'] != ""))
270                         $about = $x[0]['about'];
271
272                 if (($gender == "") AND ($x[0]['gender'] != ""))
273                         $gender = $x[0]['gender'];
274
275                 if (($keywords == "") AND ($x[0]['keywords'] != ""))
276                         $keywords = $x[0]['keywords'];
277
278                 if (($generation == 0) AND ($x[0]['generation'] > 0))
279                         $generation = $x[0]['generation'];
280
281                 if($x[0]['name'] != $name || $x[0]['photo'] != $profile_photo || $x[0]['updated'] < $updated) {
282                         q("UPDATE `gcontact` SET `name` = '%s', `network` = '%s', `photo` = '%s', `connect` = '%s', `url` = '%s', `server_url` = '%s',
283                                 `updated` = '%s', `location` = '%s', `about` = '%s', `keywords` = '%s', `gender` = '%s', `generation` = %d
284                                 WHERE (`generation` >= %d OR `generation` = 0) AND `nurl` = '%s'",
285                                 dbesc($name),
286                                 dbesc($network),
287                                 dbesc($profile_photo),
288                                 dbesc($connect_url),
289                                 dbesc($profile_url),
290                                 dbesc($server_url),
291                                 dbesc($updated),
292                                 dbesc($location),
293                                 dbesc($about),
294                                 dbesc($keywords),
295                                 dbesc($gender),
296                                 intval($generation),
297                                 intval($generation),
298                                 dbesc(normalise_link($profile_url))
299                         );
300                 }
301         } else {
302                 q("INSERT INTO `gcontact` (`name`, `nick`, `network`, `url`, `nurl`, `photo`, `connect`, `server_url`, `created`, `updated`, `location`, `about`, `keywords`, `gender`, `generation`)
303                         VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d)",
304                         dbesc($name),
305                         dbesc($nick),
306                         dbesc($network),
307                         dbesc($profile_url),
308                         dbesc(normalise_link($profile_url)),
309                         dbesc($profile_photo),
310                         dbesc($connect_url),
311                         dbesc($server_url),
312                         dbesc(datetime_convert()),
313                         dbesc($updated),
314                         dbesc($location),
315                         dbesc($about),
316                         dbesc($keywords),
317                         dbesc($gender),
318                         intval($generation)
319                 );
320                 $x = q("SELECT * FROM `gcontact` WHERE `nurl` = '%s' LIMIT 1",
321                         dbesc(normalise_link($profile_url))
322                 );
323                 if(count($x))
324                         $gcid = $x[0]['id'];
325         }
326
327         if(! $gcid)
328                 return $gcid;
329
330         $r = q("SELECT * FROM `glink` WHERE `cid` = %d AND `uid` = %d AND `gcid` = %d AND `zcid` = %d LIMIT 1",
331                 intval($cid),
332                 intval($uid),
333                 intval($gcid),
334                 intval($zcid)
335         );
336         if(! count($r)) {
337                 q("INSERT INTO `glink` (`cid`,`uid`,`gcid`,`zcid`, `updated`) VALUES (%d,%d,%d,%d, '%s') ",
338                         intval($cid),
339                         intval($uid),
340                         intval($gcid),
341                         intval($zcid),
342                         dbesc(datetime_convert())
343                 );
344         } else {
345                 q("UPDATE `glink` SET `updated` = '%s' WHERE `cid` = %d AND `uid` = %d AND `gcid` = %d AND `zcid` = %d",
346                         dbesc(datetime_convert()),
347                         intval($cid),
348                         intval($uid),
349                         intval($gcid),
350                         intval($zcid)
351                 );
352         }
353
354         // For unknown reasons there are sometimes duplicates
355         q("DELETE FROM `gcontact` WHERE `nurl` = '%s' AND `id` != %d AND
356                 NOT EXISTS (SELECT `gcid` FROM `glink` WHERE `gcid` = `gcontact`.`id`)",
357                 dbesc(normalise_link($profile_url)),
358                 intval($gcid)
359         );
360
361         return $gcid;
362 }
363
364 function poco_reachable($profile, $server = "", $network = "", $force = false) {
365
366         if ($server == "")
367                 $server = poco_detect_server($profile);
368
369         if ($server == "")
370                 return true;
371
372         return poco_check_server($server, $network, $force);
373 }
374
375 function poco_detect_server($profile) {
376
377         // Try to detect the server path based upon some known standard paths
378         $server_url = "";
379
380         if ($server_url == "") {
381                 $friendica = preg_replace("=(https?://)(.*)/profile/(.*)=ism", "$1$2", $profile);
382                 if ($friendica != $profile) {
383                         $server_url = $friendica;
384                         $network = NETWORK_DFRN;
385                 }
386         }
387
388         if ($server_url == "") {
389                 $diaspora = preg_replace("=(https?://)(.*)/u/(.*)=ism", "$1$2", $profile);
390                 if ($diaspora != $profile) {
391                         $server_url = $diaspora;
392                         $network = NETWORK_DIASPORA;
393                 }
394         }
395
396         if ($server_url == "") {
397                 $red = preg_replace("=(https?://)(.*)/channel/(.*)=ism", "$1$2", $profile);
398                 if ($red != $profile) {
399                         $server_url = $red;
400                         $network = NETWORK_DIASPORA;
401                 }
402         }
403
404         return $server_url;
405 }
406
407 function poco_last_updated($profile, $force = false) {
408
409         $gcontacts = q("SELECT * FROM `gcontact` WHERE `nurl` = '%s'",
410                         dbesc(normalise_link($profile)));
411
412         if ($gcontacts[0]["created"] == "0000-00-00 00:00:00")
413                 q("UPDATE `gcontact` SET `created` = '%s' WHERE `nurl` = '%s'",
414                         dbesc(datetime_convert()), dbesc(normalise_link($profile)));
415
416         $urlparts = parse_url($profile);
417         if (!isset($urlparts["scheme"]))
418                 return;
419
420         if (in_array($urlparts["host"], array("www.facebook.com", "facebook.com", "twitter.com",
421                                                 "identi.ca", "alpha.app.net"))) {
422                 q("UPDATE `gcontact` SET `network` = '%s' WHERE `nurl` = '%s'",
423                         dbesc(NETWORK_PHANTOM), dbesc(normalise_link($profile)));
424                 return;
425         }
426
427         if ($gcontacts[0]["server_url"] != "")
428                 $server_url = $gcontacts[0]["server_url"];
429         else
430                 $server_url = poco_detect_server($profile);
431
432         if ($server_url != "") {
433                 if (!poco_check_server($server_url, $gcontacts[0]["network"], $force)) {
434
435                         if ($force)
436                                 q("UPDATE `gcontact` SET `last_failure` = '%s' WHERE `nurl` = '%s'",
437                                         dbesc(datetime_convert()), dbesc(normalise_link($profile)));
438
439                         return false;
440                 }
441
442                 q("UPDATE `gcontact` SET `server_url` = '%s' WHERE `nurl` = '%s'",
443                         dbesc($server_url), dbesc(normalise_link($profile)));
444         }
445
446         if (in_array($gcontacts[0]["network"], array("", NETWORK_FEED))) {
447                 $server = q("SELECT `network` FROM `gserver` WHERE `nurl` = '%s' AND `network` != ''",
448                         dbesc(normalise_link($server_url)));
449
450                 if ($server)
451                         q("UPDATE `gcontact` SET `network` = '%s' WHERE `nurl` = '%s'",
452                                 dbesc($server[0]["network"]), dbesc(normalise_link($profile)));
453                 else
454                         return;
455         }
456
457         // noscrape is really fast so we don't cache the call.
458         if (($gcontacts[0]["server_url"] != "") AND ($gcontacts[0]["nick"] != "")) {
459
460                 //  Use noscrape if possible
461                 $server = q("SELECT `noscrape` FROM `gserver` WHERE `nurl` = '%s' AND `noscrape` != ''", dbesc(normalise_link($gcontacts[0]["server_url"])));
462
463                 if ($server) {
464                         $noscraperet = z_fetch_url($server[0]["noscrape"]."/".$gcontacts[0]["nick"]);
465                          if ($noscraperet["success"] AND ($noscraperet["body"] = "")) {
466                                 $noscrape = json_decode($noscraperet["body"], true);
467
468                                 if (($noscrape["name"] != "") AND ($noscrape["name"] != $gcontacts[0]["name"]))
469                                         q("UPDATE `gcontact` SET `name` = '%s' WHERE `nurl` = '%s'",
470                                                 dbesc($noscrape["name"]), dbesc(normalise_link($profile)));
471
472                                 if (($noscrape["photo"] != "") AND ($noscrape["photo"] != $gcontacts[0]["photo"]))
473                                         q("UPDATE `gcontact` SET `photo` = '%s' WHERE `nurl` = '%s'",
474                                                 dbesc($noscrape["photo"]), dbesc(normalise_link($profile)));
475
476                                 if (($noscrape["updated"] != "") AND ($noscrape["updated"] != $gcontacts[0]["updated"]))
477                                         q("UPDATE `gcontact` SET `updated` = '%s' WHERE `nurl` = '%s'",
478                                                 dbesc($noscrape["updated"]), dbesc(normalise_link($profile)));
479
480                                 if (($noscrape["gender"] != "") AND ($noscrape["gender"] != $gcontacts[0]["gender"]))
481                                         q("UPDATE `gcontact` SET `gender` = '%s' WHERE `nurl` = '%s'",
482                                                 dbesc($noscrape["gender"]), dbesc(normalise_link($profile)));
483
484                                 if (($noscrape["about"] != "") AND ($noscrape["about"] != $gcontacts[0]["name"]))
485                                         q("UPDATE `gcontact` SET `about` = '%s' WHERE `nurl` = '%s'",
486                                                 dbesc($noscrape["about"]), dbesc(normalise_link($profile)));
487
488                                 if (isset($noscrape["tags"]))
489                                         $keywords = implode(" ", $noscrape["tags"]);
490                                 else
491                                         $keywords = "";
492
493                                 if (($keywords != "") AND ($keywords != $gcontacts[0]["keywords"]))
494                                         q("UPDATE `gcontact` SET `keywords` = '%s' WHERE `nurl` = '%s'",
495                                                 dbesc($keywords), dbesc(normalise_link($profile)));
496
497                                 $location = $noscrape["locality"];
498
499                                 if ($noscrape["region"] != "") {
500                                         if ($location != "")
501                                                 $location .= ", ";
502
503                                         $location .= $noscrape["region"];
504                                 }
505
506                                 if ($noscrape["country-name"] != "") {
507                                         if ($location != "")
508                                                 $location .= ", ";
509
510                                         $location .= $noscrape["country-name"];
511                                 }
512
513                                 if (($location != "") AND ($location != $gcontacts[0]["location"]))
514                                         q("UPDATE `gcontact` SET `location` = '%s' WHERE `nurl` = '%s'",
515                                                 dbesc($location), dbesc(normalise_link($profile)));
516
517                                 // If we got data from noscrape then mark the contact as reachable
518                                 if (is_array($noscrape) AND count($noscrape))
519                                         q("UPDATE `gcontact` SET `last_contact` = '%s' WHERE `nurl` = '%s'",
520                                                 dbesc(datetime_convert()), dbesc(normalise_link($profile)));
521
522                                 return $noscrape["updated"];
523                         }
524                 }
525         }
526
527         // If we only can poll the feed, then we only do this once a while
528         if (!$force AND !poco_do_update($gcontacts[0]["created"], $gcontacts[0]["updated"], $gcontacts[0]["last_failure"],  $gcontacts[0]["last_contact"]))
529                 return $gcontacts[0]["updated"];
530
531         $data = probe_url($profile);
532
533         if (($data["poll"] == "") OR ($data["network"] == NETWORK_FEED)) {
534                 q("UPDATE `gcontact` SET `last_failure` = '%s' WHERE `nurl` = '%s'",
535                         dbesc(datetime_convert()), dbesc(normalise_link($profile)));
536                 return false;
537         }
538
539         if (($data["name"] != "") AND ($data["name"] != $gcontacts[0]["name"]))
540                 q("UPDATE `gcontact` SET `name` = '%s' WHERE `nurl` = '%s'",
541                         dbesc($data["name"]), dbesc(normalise_link($profile)));
542
543         if (($data["nick"] != "") AND ($data["nick"] != $gcontacts[0]["nick"]))
544                 q("UPDATE `gcontact` SET `nick` = '%s' WHERE `nurl` = '%s'",
545                         dbesc($data["nick"]), dbesc(normalise_link($profile)));
546
547         if (($data["addr"] != "") AND ($data["addr"] != $gcontacts[0]["connect"]))
548                 q("UPDATE `gcontact` SET `connect` = '%s' WHERE `nurl` = '%s'",
549                         dbesc($data["addr"]), dbesc(normalise_link($profile)));
550
551         if (($data["photo"] != "") AND ($data["photo"] != $gcontacts[0]["photo"]))
552                 q("UPDATE `gcontact` SET `photo` = '%s' WHERE `nurl` = '%s'",
553                         dbesc($data["photo"]), dbesc(normalise_link($profile)));
554
555         if (($data["baseurl"] != "") AND ($data["baseurl"] != $gcontacts[0]["server_url"]))
556                 q("UPDATE `gcontact` SET `server_url` = '%s' WHERE `nurl` = '%s'",
557                         dbesc($data["baseurl"]), dbesc(normalise_link($profile)));
558
559         $feedret = z_fetch_url($data["poll"]);
560
561         if (!$feedret["success"]) {
562                 q("UPDATE `gcontact` SET `last_failure` = '%s' WHERE `nurl` = '%s'",
563                         dbesc(datetime_convert()), dbesc(normalise_link($profile)));
564                 return false;
565         }
566
567         $doc = new DOMDocument();
568         @$doc->loadXML($feedret["body"]);
569
570         $xpath = new DomXPath($doc);
571         $xpath->registerNamespace('atom', "http://www.w3.org/2005/Atom");
572
573         $entries = $xpath->query('/atom:feed/atom:entry');
574
575         $last_updated = "";
576
577         foreach ($entries AS $entry) {
578                 $published = $xpath->query('atom:published/text()', $entry)->item(0)->nodeValue;
579                 $updated = $xpath->query('atom:updated/text()', $entry)->item(0)->nodeValue;
580
581                 if ($last_updated < $published)
582                         $last_updated = $published;
583
584                 if ($last_updated < $updated)
585                         $last_updated = $updated;
586         }
587
588         // Maybe there aren't any entries. Then check if it is a valid feed
589         if ($last_updated == "")
590                 if ($xpath->query('/atom:feed')->length > 0)
591                         $last_updated = "0000-00-00 00:00:00";
592
593         q("UPDATE `gcontact` SET `updated` = '%s', `last_contact` = '%s' WHERE `nurl` = '%s'",
594                 dbesc($last_updated), dbesc(datetime_convert()), dbesc(normalise_link($profile)));
595
596         if (($gcontacts[0]["generation"] == 0))
597                 q("UPDATE `gcontact` SET `generation` = 9 WHERE `nurl` = '%s'",
598                         dbesc(normalise_link($profile)));
599
600         return($last_updated);
601 }
602
603 function poco_do_update($created, $updated, $last_failure,  $last_contact) {
604         $now = strtotime(datetime_convert());
605
606         if ($updated > $last_contact)
607                 $contact_time = strtotime($updated);
608         else
609                 $contact_time = strtotime($last_contact);
610
611         $failure_time = strtotime($last_failure);
612         $created_time = strtotime($created);
613
614         // If there is no "created" time then use the current time
615         if ($created_time <= 0)
616                 $created_time = $now;
617
618         // If the last contact was less than 24 hours then don't update
619         if (($now - $contact_time) < (60 * 60 * 24))
620                 return false;
621
622         // If the last failure was less than 24 hours then don't update
623         if (($now - $failure_time) < (60 * 60 * 24))
624                 return false;
625
626         // If the last contact was less than a week ago and the last failure is older than a week then don't update
627         //if ((($now - $contact_time) < (60 * 60 * 24 * 7)) AND ($contact_time > $failure_time))
628         //      return false;
629
630         // If the last contact time was more than a week ago and the contact was created more than a week ago, then only try once a week
631         if ((($now - $contact_time) > (60 * 60 * 24 * 7)) AND (($now - $created_time) > (60 * 60 * 24 * 7)) AND (($now - $failure_time) < (60 * 60 * 24 * 7)))
632                 return false;
633
634         // If the last contact time was more than a month ago and the contact was created more than a month ago, then only try once a month
635         if ((($now - $contact_time) > (60 * 60 * 24 * 30)) AND (($now - $created_time) > (60 * 60 * 24 * 30)) AND (($now - $failure_time) < (60 * 60 * 24 * 30)))
636                 return false;
637
638         return true;
639 }
640
641 function poco_to_boolean($val) {
642         if (($val == "true") OR ($val == 1))
643                 return(true);
644         if (($val == "false") OR ($val == 0))
645                 return(false);
646
647         return ($val);
648 }
649
650 function poco_check_server($server_url, $network = "", $force = false) {
651
652         if ($server_url == "")
653                 return false;
654
655         $servers = q("SELECT * FROM `gserver` WHERE `nurl` = '%s'", dbesc(normalise_link($server_url)));
656         if ($servers) {
657
658                 if ($servers[0]["created"] == "0000-00-00 00:00:00")
659                         q("UPDATE `gserver` SET `created` = '%s' WHERE `nurl` = '%s'",
660                                 dbesc(datetime_convert()), dbesc(normalise_link($server_url)));
661
662                 $poco = $servers[0]["poco"];
663                 $noscrape = $servers[0]["noscrape"];
664
665                 if ($network == "")
666                         $network = $servers[0]["network"];
667
668                 $last_contact = $servers[0]["last_contact"];
669                 $last_failure = $servers[0]["last_failure"];
670                 $version = $servers[0]["version"];
671                 $platform = $servers[0]["platform"];
672                 $site_name = $servers[0]["site_name"];
673                 $info = $servers[0]["info"];
674                 $register_policy = $servers[0]["register_policy"];
675
676                 if (!$force AND !poco_do_update($servers[0]["created"], "", $last_failure, $last_contact)) {
677                         logger("Use cached data for server ".$server_url, LOGGER_DEBUG);
678                         return ($last_contact >= $last_failure);
679                 }
680         } else {
681                 $poco = "";
682                 $noscrape = "";
683                 $version = "";
684                 $platform = "";
685                 $site_name = "";
686                 $info = "";
687                 $register_policy = -1;
688
689                 $last_contact = "0000-00-00 00:00:00";
690                 $last_failure = "0000-00-00 00:00:00";
691         }
692         logger("Server ".$server_url." is unknown. Start discovery.", LOGGER_DEBUG);
693
694         $failure = false;
695         $orig_last_failure = $last_failure;
696
697         // Check if the page is accessible via SSL.
698         $server_url = str_replace("http://", "https://", $server_url);
699         $serverret = z_fetch_url($server_url."/.well-known/host-meta");
700
701         // Maybe the page is unencrypted only?
702         $xmlobj = @simplexml_load_string($serverret["body"],'SimpleXMLElement',0, "http://docs.oasis-open.org/ns/xri/xrd-1.0");
703         if (!$serverret["success"] OR ($serverret["body"] == "") OR (@sizeof($xmlobj) == 0) OR !is_object($xmlobj)) {
704                 $server_url = str_replace("https://", "http://", $server_url);
705                 $serverret = z_fetch_url($server_url."/.well-known/host-meta");
706
707                 $xmlobj = @simplexml_load_string($serverret["body"],'SimpleXMLElement',0, "http://docs.oasis-open.org/ns/xri/xrd-1.0");
708         }
709
710         if (!$serverret["success"] OR ($serverret["body"] == "") OR (sizeof($xmlobj) == 0) OR !is_object($xmlobj)) {
711                 $last_failure = datetime_convert();
712                 $failure = true;
713         } elseif ($network == NETWORK_DIASPORA)
714                 $last_contact = datetime_convert();
715
716         if (!$failure) {
717                 // Test for Diaspora
718                 $serverret = z_fetch_url($server_url);
719
720                 $lines = explode("\n",$serverret["header"]);
721                 if(count($lines))
722                         foreach($lines as $line) {
723                                 $line = trim($line);
724                                 if(stristr($line,'X-Diaspora-Version:')) {
725                                         $platform = "Diaspora";
726                                         $version = trim(str_replace("X-Diaspora-Version:", "", $line));
727                                         $version = trim(str_replace("x-diaspora-version:", "", $version));
728                                         $network = NETWORK_DIASPORA;
729                                 }
730                         }
731         }
732
733         if (!$failure) {
734                 // Test for Statusnet
735                 // Will also return data for Friendica and GNU Social - but it will be overwritten later
736                 // The "not implemented" is a special treatment for really, really old Friendica versions
737                 $serverret = z_fetch_url($server_url."/api/statusnet/version.json");
738                 if ($serverret["success"] AND ($serverret["body"] != '{"error":"not implemented"}') AND ($serverret["body"] != '') AND (strlen($serverret["body"]) < 250)) {
739                         $platform = "StatusNet";
740                         $version = trim($serverret["body"], '"');
741                         $network = NETWORK_OSTATUS;
742                 }
743
744                 // Test for GNU Social
745                 $serverret = z_fetch_url($server_url."/api/gnusocial/version.json");
746                 if ($serverret["success"] AND ($serverret["body"] != '{"error":"not implemented"}') AND ($serverret["body"] != '') AND (strlen($serverret["body"]) < 250)) {
747                         $platform = "GNU Social";
748                         $version = trim($serverret["body"], '"');
749                         $network = NETWORK_OSTATUS;
750                 }
751
752                 $serverret = z_fetch_url($server_url."/api/statusnet/config.json");
753                 if ($serverret["success"]) {
754                         $data = json_decode($serverret["body"]);
755
756                         if (isset($data->site->server)) {
757                                 $last_contact = datetime_convert();
758
759                                 if (isset($data->site->hubzilla)) {
760                                         $platform = $data->site->hubzilla->PLATFORM_NAME;
761                                         $version = $data->site->hubzilla->RED_VERSION;
762                                         $network = NETWORK_DIASPORA;
763                                 }
764                                 if (isset($data->site->redmatrix)) {
765                                         if (isset($data->site->redmatrix->PLATFORM_NAME))
766                                                 $platform = $data->site->redmatrix->PLATFORM_NAME;
767                                         elseif (isset($data->site->redmatrix->RED_PLATFORM))
768                                                 $platform = $data->site->redmatrix->RED_PLATFORM;
769
770                                         $version = $data->site->redmatrix->RED_VERSION;
771                                         $network = NETWORK_DIASPORA;
772                                 }
773                                 if (isset($data->site->friendica)) {
774                                         $platform = $data->site->friendica->FRIENDICA_PLATFORM;
775                                         $version = $data->site->friendica->FRIENDICA_VERSION;
776                                         $network = NETWORK_DFRN;
777                                 }
778
779                                 $site_name = $data->site->name;
780
781                                 $data->site->closed = poco_to_boolean($data->site->closed);
782                                 $data->site->private = poco_to_boolean($data->site->private);
783                                 $data->site->inviteonly = poco_to_boolean($data->site->inviteonly);
784
785                                 if (!$data->site->closed AND !$data->site->private and $data->site->inviteonly)
786                                         $register_policy = REGISTER_APPROVE;
787                                 elseif (!$data->site->closed AND !$data->site->private)
788                                         $register_policy = REGISTER_OPEN;
789                                 else
790                                         $register_policy = REGISTER_CLOSED;
791                         }
792                 }
793         }
794
795         // Query statistics.json. Optional package for Diaspora, Friendica and Redmatrix
796         if (!$failure) {
797                 $serverret = z_fetch_url($server_url."/statistics.json");
798                 if ($serverret["success"]) {
799                         $data = json_decode($serverret["body"]);
800                         if ($version == "")
801                                 $version = $data->version;
802
803                         $site_name = $data->name;
804
805                         if (isset($data->network) AND ($platform == ""))
806                                 $platform = $data->network;
807
808                         if ($platform == "Diaspora")
809                                 $network = NETWORK_DIASPORA;
810
811                         if ($data->registrations_open)
812                                 $register_policy = REGISTER_OPEN;
813                         else
814                                 $register_policy = REGISTER_CLOSED;
815
816                         if (isset($data->version))
817                                 $last_contact = datetime_convert();
818                 }
819         }
820
821         // Check for noscrape
822         // Friendica servers could be detected as OStatus servers
823         if (!$failure AND in_array($network, array(NETWORK_DFRN, NETWORK_OSTATUS))) {
824                 $serverret = z_fetch_url($server_url."/friendica/json");
825
826                 if (!$serverret["success"])
827                         $serverret = z_fetch_url($server_url."/friendika/json");
828
829                 if ($serverret["success"]) {
830                         $data = json_decode($serverret["body"]);
831
832                         if (isset($data->version)) {
833                                 $last_contact = datetime_convert();
834                                 $network = NETWORK_DFRN;
835
836                                 $noscrape = $data->no_scrape_url;
837                                 $version = $data->version;
838                                 $site_name = $data->site_name;
839                                 $info = $data->info;
840                                 $register_policy_str = $data->register_policy;
841                                 $platform = $data->platform;
842
843                                 switch ($register_policy_str) {
844                                         case "REGISTER_CLOSED":
845                                                 $register_policy = REGISTER_CLOSED;
846                                                 break;
847                                         case "REGISTER_APPROVE":
848                                                 $register_policy = REGISTER_APPROVE;
849                                                 break;
850                                         case "REGISTER_OPEN":
851                                                 $register_policy = REGISTER_OPEN;
852                                                 break;
853                                 }
854                         }
855                 }
856         }
857
858         // Look for poco
859         if (!$failure) {
860                 $serverret = z_fetch_url($server_url."/poco");
861                 if ($serverret["success"]) {
862                         $data = json_decode($serverret["body"]);
863                         if (isset($data->totalResults)) {
864                                 $poco = $server_url."/poco";
865                                 $last_contact = datetime_convert();
866                         }
867                 }
868         }
869
870         // Check again if the server exists
871         $servers = q("SELECT `nurl` FROM `gserver` WHERE `nurl` = '%s'", dbesc(normalise_link($server_url)));
872
873         if ($servers)
874                  q("UPDATE `gserver` SET `url` = '%s', `version` = '%s', `site_name` = '%s', `info` = '%s', `register_policy` = %d, `poco` = '%s', `noscrape` = '%s',
875                         `network` = '%s', `platform` = '%s', `last_contact` = '%s', `last_failure` = '%s' WHERE `nurl` = '%s'",
876                         dbesc($server_url),
877                         dbesc($version),
878                         dbesc($site_name),
879                         dbesc($info),
880                         intval($register_policy),
881                         dbesc($poco),
882                         dbesc($noscrape),
883                         dbesc($network),
884                         dbesc($platform),
885                         dbesc($last_contact),
886                         dbesc($last_failure),
887                         dbesc(normalise_link($server_url))
888                 );
889         else
890                 q("INSERT INTO `gserver` (`url`, `nurl`, `version`, `site_name`, `info`, `register_policy`, `poco`, `noscrape`, `network`, `platform`, `created`, `last_contact`, `last_failure`)
891                                         VALUES ('%s', '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s')",
892                                 dbesc($server_url),
893                                 dbesc(normalise_link($server_url)),
894                                 dbesc($version),
895                                 dbesc($site_name),
896                                 dbesc($info),
897                                 intval($register_policy),
898                                 dbesc($poco),
899                                 dbesc($noscrape),
900                                 dbesc($network),
901                                 dbesc($platform),
902                                 dbesc(datetime_convert()),
903                                 dbesc($last_contact),
904                                 dbesc($last_failure),
905                                 dbesc(datetime_convert())
906                 );
907
908         logger("End discovery for server ".$server_url, LOGGER_DEBUG);
909
910         return !$failure;
911 }
912
913 function poco_contact_from_body($body, $created, $cid, $uid) {
914         preg_replace_callback("/\[share(.*?)\].*?\[\/share\]/ism",
915                 function ($match) use ($created, $cid, $uid){
916                         return(sub_poco_from_share($match, $created, $cid, $uid));
917                 }, $body);
918 }
919
920 function sub_poco_from_share($share, $created, $cid, $uid) {
921         $profile = "";
922         preg_match("/profile='(.*?)'/ism", $share[1], $matches);
923         if ($matches[1] != "")
924                 $profile = $matches[1];
925
926         preg_match('/profile="(.*?)"/ism', $share[1], $matches);
927         if ($matches[1] != "")
928                 $profile = $matches[1];
929
930         if ($profile == "")
931                 return;
932
933         logger("prepare poco_check for profile ".$profile, LOGGER_DEBUG);
934         poco_check($profile, "", "", "", "", "", "", "", "", $created, 3, $cid, $uid);
935 }
936
937 function poco_store($item) {
938
939         // Isn't it public?
940         if ($item['private'])
941                 return;
942
943         // Or is it from a network where we don't store the global contacts?
944         if (!in_array($item["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, NETWORK_STATUSNET, "")))
945                 return;
946
947         // Is it a global copy?
948         $store_gcontact = ($item["uid"] == 0);
949
950         // Is it a comment on a global copy?
951         if (!$store_gcontact AND ($item["uri"] != $item["parent-uri"])) {
952                 $q = q("SELECT `id` FROM `item` WHERE `uri`='%s' AND `uid` = 0", $item["parent-uri"]);
953                 $store_gcontact = count($q);
954         }
955
956         if (!$store_gcontact)
957                 return;
958
959         // "3" means: We don't know this contact directly (Maybe a reshared item)
960         $generation = 3;
961         $network = "";
962         $profile_url = $item["author-link"];
963
964         // Is it a user from our server?
965         $q = q("SELECT `id` FROM `contact` WHERE `self` AND `nurl` = '%s' LIMIT 1",
966                 dbesc(normalise_link($item["author-link"])));
967         if (count($q)) {
968                 logger("Our user (generation 1): ".$item["author-link"], LOGGER_DEBUG);
969                 $generation = 1;
970                 $network = NETWORK_DFRN;
971         } else { // Is it a contact from a user on our server?
972                 $q = q("SELECT `network`, `url` FROM `contact` WHERE `uid` != 0 AND `network` != ''
973                         AND (`nurl` = '%s' OR `alias` IN ('%s', '%s')) AND `network` != '%s' LIMIT 1",
974                         dbesc(normalise_link($item["author-link"])),
975                         dbesc(normalise_link($item["author-link"])),
976                         dbesc($item["author-link"]),
977                         dbesc(NETWORK_STATUSNET));
978                 if (count($q)) {
979                         $generation = 2;
980                         $network = $q[0]["network"];
981                         $profile_url = $q[0]["url"];
982                         logger("Known contact (generation 2): ".$profile_url, LOGGER_DEBUG);
983                 }
984         }
985
986         if ($generation == 3)
987                 logger("Unknown contact (generation 3): ".$item["author-link"], LOGGER_DEBUG);
988
989         poco_check($profile_url, $item["author-name"], $network, $item["author-avatar"], "", "", "", "", "", $item["received"], $generation, $item["contact-id"], $item["uid"]);
990
991         // Maybe its a body with a shared item? Then extract a global contact from it.
992         poco_contact_from_body($item["body"], $item["received"], $item["contact-id"], $item["uid"]);
993 }
994
995 function count_common_friends($uid,$cid) {
996
997         $r = q("SELECT count(*) as `total`
998                 FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
999                 where `glink`.`cid` = %d and `glink`.`uid` = %d
1000                 and `gcontact`.`nurl` in (select nurl from contact where uid = %d and self = 0 and blocked = 0 and hidden = 0 and id != %d ) ",
1001                 intval($cid),
1002                 intval($uid),
1003                 intval($uid),
1004                 intval($cid)
1005         );
1006
1007 //      logger("count_common_friends: $uid $cid {$r[0]['total']}"); 
1008         if(count($r))
1009                 return $r[0]['total'];
1010         return 0;
1011
1012 }
1013
1014
1015 function common_friends($uid,$cid,$start = 0,$limit=9999,$shuffle = false) {
1016
1017         if($shuffle)
1018                 $sql_extra = " order by rand() ";
1019         else
1020                 $sql_extra = " order by `gcontact`.`name` asc ";
1021
1022         $r = q("SELECT `gcontact`.*
1023                 FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
1024                 where `glink`.`cid` = %d and `glink`.`uid` = %d
1025                 and `gcontact`.`nurl` in (select nurl from contact where uid = %d and self = 0 and blocked = 0 and hidden = 0 and id != %d ) 
1026                 $sql_extra limit %d, %d",
1027                 intval($cid),
1028                 intval($uid),
1029                 intval($uid),
1030                 intval($cid),
1031                 intval($start),
1032                 intval($limit)
1033         );
1034
1035         return $r;
1036
1037 }
1038
1039
1040 function count_common_friends_zcid($uid,$zcid) {
1041
1042         $r = q("SELECT count(*) as `total`
1043                 FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
1044                 where `glink`.`zcid` = %d
1045                 and `gcontact`.`nurl` in (select nurl from contact where uid = %d and self = 0 and blocked = 0 and hidden = 0 ) ",
1046                 intval($zcid),
1047                 intval($uid)
1048         );
1049
1050         if(count($r))
1051                 return $r[0]['total'];
1052         return 0;
1053
1054 }
1055
1056 function common_friends_zcid($uid,$zcid,$start = 0, $limit = 9999,$shuffle = false) {
1057
1058         if($shuffle)
1059                 $sql_extra = " order by rand() ";
1060         else
1061                 $sql_extra = " order by `gcontact`.`name` asc ";
1062
1063         $r = q("SELECT `gcontact`.*
1064                 FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
1065                 where `glink`.`zcid` = %d
1066                 and `gcontact`.`nurl` in (select nurl from contact where uid = %d and self = 0 and blocked = 0 and hidden = 0 ) 
1067                 $sql_extra limit %d, %d",
1068                 intval($zcid),
1069                 intval($uid),
1070                 intval($start),
1071                 intval($limit)
1072         );
1073
1074         return $r;
1075
1076 }
1077
1078
1079 function count_all_friends($uid,$cid) {
1080
1081         $r = q("SELECT count(*) as `total`
1082                 FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
1083                 where `glink`.`cid` = %d and `glink`.`uid` = %d ",
1084                 intval($cid),
1085                 intval($uid)
1086         );
1087
1088         if(count($r))
1089                 return $r[0]['total'];
1090         return 0;
1091
1092 }
1093
1094
1095 function all_friends($uid,$cid,$start = 0, $limit = 80) {
1096
1097         $r = q("SELECT `gcontact`.*
1098                 FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
1099                 where `glink`.`cid` = %d and `glink`.`uid` = %d
1100                 order by `gcontact`.`name` asc LIMIT %d, %d ",
1101                 intval($cid),
1102                 intval($uid),
1103                 intval($start),
1104                 intval($limit)
1105         );
1106
1107         return $r;
1108 }
1109
1110
1111
1112 function suggestion_query($uid, $start = 0, $limit = 80) {
1113
1114         if(! $uid)
1115                 return array();
1116
1117         $network = array(NETWORK_DFRN);
1118
1119         if (get_config('system','diaspora_enabled'))
1120                 $network[] = NETWORK_DIASPORA;
1121
1122         if (!get_config('system','ostatus_disabled'))
1123                 $network[] = NETWORK_OSTATUS;
1124
1125         $sql_network = implode("', '", $network);
1126         //$sql_network = "'".$sql_network."', ''";
1127         $sql_network = "'".$sql_network."'";
1128
1129         $r = q("SELECT count(glink.gcid) as `total`, gcontact.* from gcontact
1130                 INNER JOIN glink on glink.gcid = gcontact.id
1131                 where uid = %d and not gcontact.nurl in ( select nurl from contact where uid = %d )
1132                 and not gcontact.name in ( select name from contact where uid = %d )
1133                 and not gcontact.id in ( select gcid from gcign where uid = %d )
1134                 AND `gcontact`.`updated` != '0000-00-00 00:00:00'
1135                 AND `gcontact`.`last_contact` >= `gcontact`.`last_failure`
1136                 AND `gcontact`.`network` IN (%s)
1137                 group by glink.gcid order by gcontact.updated desc,total desc limit %d, %d ",
1138                 intval($uid),
1139                 intval($uid),
1140                 intval($uid),
1141                 intval($uid),
1142                 $sql_network,
1143                 intval($start),
1144                 intval($limit)
1145         );
1146
1147         if(count($r) && count($r) >= ($limit -1))
1148                 return $r;
1149
1150         $r2 = q("SELECT gcontact.* from gcontact
1151                 INNER JOIN glink on glink.gcid = gcontact.id
1152                 where glink.uid = 0 and glink.cid = 0 and glink.zcid = 0 and not gcontact.nurl in ( select nurl from contact where uid = %d )
1153                 and not gcontact.name in ( select name from contact where uid = %d )
1154                 and not gcontact.id in ( select gcid from gcign where uid = %d )
1155                 AND `gcontact`.`updated` != '0000-00-00 00:00:00'
1156                 AND `gcontact`.`network` IN (%s)
1157                 order by rand() limit %d, %d ",
1158                 intval($uid),
1159                 intval($uid),
1160                 intval($uid),
1161                 $sql_network,
1162                 intval($start),
1163                 intval($limit)
1164         );
1165
1166         $list = array();
1167         foreach ($r2 AS $suggestion)
1168                 $list[$suggestion["nurl"]] = $suggestion;
1169
1170         foreach ($r AS $suggestion)
1171                 $list[$suggestion["nurl"]] = $suggestion;
1172
1173         return $list;
1174 }
1175
1176 function update_suggestions() {
1177
1178         $a = get_app();
1179
1180         $done = array();
1181
1182         // To-Do: Check if it is really neccessary to poll the own server
1183         poco_load(0,0,0,$a->get_baseurl() . '/poco');
1184
1185         $done[] = $a->get_baseurl() . '/poco';
1186
1187         if(strlen(get_config('system','directory_submit_url'))) {
1188                 $x = fetch_url('http://dir.friendica.com/pubsites');
1189                 if($x) {
1190                         $j = json_decode($x);
1191                         if($j->entries) {
1192                                 foreach($j->entries as $entry) {
1193
1194                                         poco_check_server($entry->url);
1195
1196                                         $url = $entry->url . '/poco';
1197                                         if(! in_array($url,$done))
1198                                                 poco_load(0,0,0,$entry->url . '/poco');
1199                                 }
1200                         }
1201                 }
1202         }
1203
1204         // Query your contacts from Friendica and Redmatrix/Hubzilla for their contacts
1205         $r = q("SELECT DISTINCT(`poco`) AS `poco` FROM `contact` WHERE `network` IN ('%s', '%s')",
1206                 dbesc(NETWORK_DFRN), dbesc(NETWORK_DIASPORA)
1207         );
1208
1209         if(count($r)) {
1210                 foreach($r as $rr) {
1211                         $base = substr($rr['poco'],0,strrpos($rr['poco'],'/'));
1212                         if(! in_array($base,$done))
1213                                 poco_load(0,0,0,$base);
1214                 }
1215         }
1216 }
1217
1218 function poco_discover($complete = false) {
1219
1220         $no_of_queries = 5;
1221
1222         $last_update = date("c", time() - (60 * 60 * 6)); // 24
1223         $last_update = date("c", time() - (60 * 60 * 24)); // 24
1224
1225         $r = q("SELECT `poco`, `nurl`, `url`, `network` FROM `gserver` WHERE `last_contact` > `last_failure` AND `poco` != '' AND `last_poco_query` < '%s' ORDER BY RAND()", dbesc($last_update));
1226         if ($r)
1227                 foreach ($r AS $server) {
1228
1229                         if (!poco_check_server($server["url"], $server["network"]))
1230                                 continue;
1231
1232                         // Fetch all users from the other server
1233                         $url = $server["poco"]."/?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,generation";
1234
1235                         logger("Fetch all users from the server ".$server["nurl"], LOGGER_DEBUG);
1236
1237                         $retdata = z_fetch_url($url);
1238                         if ($retdata["success"]) {
1239                                 $data = json_decode($retdata["body"]);
1240
1241                                 poco_discover_server($data, 2);
1242
1243                                 if (get_config('system','poco_discovery') > 1) {
1244
1245                                         $timeframe = get_config('system','poco_discovery_since');
1246                                         if ($timeframe == 0)
1247                                                 $timeframe = 30;
1248
1249                                         $updatedSince = date("Y-m-d H:i:s", time() - $timeframe * 86400);
1250
1251                                         // Fetch all global contacts from the other server (Not working with Redmatrix and Friendica versions before 3.3)
1252                                         $url = $server["poco"]."/@global?updatedSince=".$updatedSince."&fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,generation";
1253
1254                                         $success = false;
1255
1256                                         $retdata = z_fetch_url($url);
1257                                         if ($retdata["success"]) {
1258                                                 logger("Fetch all global contacts from the server ".$server["nurl"], LOGGER_DEBUG);
1259                                                 $success = poco_discover_server(json_decode($retdata["body"]));
1260                                         }
1261
1262                                         if (!$success AND (get_config('system','poco_discovery') > 2)) {
1263                                                 logger("Fetch contacts from users of the server ".$server["nurl"], LOGGER_DEBUG);
1264                                                 poco_discover_server_users($data, $server);
1265                                         }
1266                                 }
1267
1268                                 q("UPDATE `gserver` SET `last_poco_query` = '%s' WHERE `nurl` = '%s'", dbesc(datetime_convert()), dbesc($server["nurl"]));
1269                                 if (!$complete AND (--$no_of_queries == 0))
1270                                         break;
1271                         } else  // If the server hadn't replied correctly, then force a sanity check
1272                                 poco_check_server($server["url"], $server["network"], true);
1273                 }
1274 }
1275
1276 function poco_discover_server_users($data, $server) {
1277
1278         if (!isset($data->entry))
1279                 return;
1280
1281         foreach ($data->entry AS $entry) {
1282                 $username = "";
1283                 if (isset($entry->urls)) {
1284                         foreach($entry->urls as $url)
1285                                 if($url->type == 'profile') {
1286                                         $profile_url = $url->value;
1287                                         $urlparts = parse_url($profile_url);
1288                                         $username = end(explode("/", $urlparts["path"]));
1289                                 }
1290                 }
1291                 if ($username != "") {
1292                         logger("Fetch contacts for the user ".$username." from the server ".$server["nurl"], LOGGER_DEBUG);
1293
1294                         // Fetch all contacts from a given user from the other server
1295                         $url = $server["poco"]."/".$username."/?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,generation";
1296
1297                         $retdata = z_fetch_url($url);
1298                         if ($retdata["success"])
1299                                 poco_discover_server(json_decode($retdata["body"]), 3);
1300                 }
1301         }
1302 }
1303
1304 function poco_discover_server($data, $default_generation = 0) {
1305
1306         if (!isset($data->entry) OR !count($data->entry))
1307                 return false;
1308
1309         $success = false;
1310
1311         foreach ($data->entry AS $entry) {
1312                 $profile_url = '';
1313                 $profile_photo = '';
1314                 $connect_url = '';
1315                 $name = '';
1316                 $network = '';
1317                 $updated = '0000-00-00 00:00:00';
1318                 $location = '';
1319                 $about = '';
1320                 $keywords = '';
1321                 $gender = '';
1322                 $generation = $default_generation;
1323
1324                 $name = $entry->displayName;
1325
1326                 if(isset($entry->urls)) {
1327                         foreach($entry->urls as $url) {
1328                                 if($url->type == 'profile') {
1329                                         $profile_url = $url->value;
1330                                         continue;
1331                                 }
1332                                 if($url->type == 'webfinger') {
1333                                         $connect_url = str_replace('acct:' , '', $url->value);
1334                                         continue;
1335                                 }
1336                         }
1337                 }
1338
1339                 if(isset($entry->photos)) {
1340                         foreach($entry->photos as $photo) {
1341                                 if($photo->type == 'profile') {
1342                                         $profile_photo = $photo->value;
1343                                         continue;
1344                                 }
1345                         }
1346                 }
1347
1348                 if(isset($entry->updated))
1349                         $updated = date("Y-m-d H:i:s", strtotime($entry->updated));
1350
1351                 if(isset($entry->network))
1352                         $network = $entry->network;
1353
1354                 if(isset($entry->currentLocation))
1355                         $location = $entry->currentLocation;
1356
1357                 if(isset($entry->aboutMe))
1358                         $about = html2bbcode($entry->aboutMe);
1359
1360                 if(isset($entry->gender))
1361                         $gender = $entry->gender;
1362
1363                 if(isset($entry->generation) AND ($entry->generation > 0))
1364                         $generation = ++$entry->generation;
1365
1366                 if(isset($entry->tags))
1367                         foreach($entry->tags as $tag)
1368                                 $keywords = implode(", ", $tag);
1369
1370                 if ($generation > 0) {
1371                         $success = true;
1372
1373                         logger("Store profile ".$profile_url, LOGGER_DEBUG);
1374                         poco_check($profile_url, $name, $network, $profile_photo, $about, $location, $gender, $keywords, $connect_url, $updated, $generation, 0, 0, 0);
1375                         logger("Done for profile ".$profile_url, LOGGER_DEBUG);
1376                 }
1377         }
1378         return $success;
1379 }
1380 ?>