]> git.mxchange.org Git - friendica.git/blob - include/socgraph.php
Poco: Option to activate and deactivate detection of last activity.
[friendica.git] / include / socgraph.php
1 <?php
2
3 require_once('include/datetime.php');
4 require_once("include/Scrape.php");
5
6 /*
7  To-Do:
8  - noscrape for updating contact fields and "last updated"
9  - use /poco/@global for discovering contacts from other servers
10 */
11
12 /*
13  * poco_load
14  *
15  * Given a contact-id (minimum), load the PortableContacts friend list for that contact,
16  * and add the entries to the gcontact (Global Contact) table, or update existing entries
17  * if anything (name or photo) has changed.
18  * We use normalised urls for comparison which ignore http vs https and www.domain vs domain
19  *
20  * Once the global contact is stored add (if necessary) the contact linkage which associates
21  * the given uid, cid to the global contact entry. There can be many uid/cid combinations
22  * pointing to the same global contact id.
23  *
24  */
25
26
27
28
29 function poco_load($cid,$uid = 0,$zcid = 0,$url = null) {
30
31         require_once("include/html2bbcode.php");
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         $orig_updated = $updated;
178
179         // Don't store the statusnet connector as network
180         // We can't simply set this to NETWORK_OSTATUS since the connector could have fetched posts from friendica as well
181         if ($network == NETWORK_STATUSNET)
182                 $network = "";
183
184         // The global contacts should contain the original picture, not the cached one
185         if (($generation != 1) AND stristr(normalise_link($profile_photo), normalise_link($a->get_baseurl()."/photo/")))
186                 $profile_photo = "";
187
188         $r = q("SELECT `network` FROM `contact` WHERE `nurl` = '%s' AND `network` != '' AND `network` != '%s' LIMIT 1",
189                 dbesc(normalise_link($profile_url)), dbesc(NETWORK_STATUSNET)
190         );
191         if(count($r))
192                 $network = $r[0]["network"];
193
194         if (($network == "") OR ($network == NETWORK_OSTATUS)) {
195                 $r = q("SELECT `network`, `url` FROM `contact` WHERE `alias` IN ('%s', '%s') AND `network` != '' AND `network` != '%s' LIMIT 1",
196                         dbesc($profile_url), dbesc(normalise_link($profile_url)), dbesc(NETWORK_STATUSNET)
197                 );
198                 if(count($r)) {
199                         $network = $r[0]["network"];
200                         $profile_url = $r[0]["url"];
201                 }
202         }
203
204         $x = q("SELECT * FROM `gcontact` WHERE `nurl` = '%s' LIMIT 1",
205                 dbesc(normalise_link($profile_url))
206         );
207
208         if (count($x)) {
209                 if (($network == "") AND ($x[0]["network"] != NETWORK_STATUSNET))
210                         $network = $x[0]["network"];
211
212                 if ($updated == "0000-00-00 00:00:00")
213                         $updated = $x[0]["updated"];
214
215                 $last_contact = $x[0]["last_contact"];
216                 $last_failure = $x[0]["last_failure"];
217         } else {
218                 $last_contact = "0000-00-00 00:00:00";
219                 $last_failure = "0000-00-00 00:00:00";
220         }
221
222         if (($network == "") OR ($name == "") OR ($profile_photo == "")) {
223                 $data = probe_url($profile_url);
224                 $network = $data["network"];
225                 $name = $data["name"];
226                 $profile_url = $data["url"];
227                 $profile_photo = $data["photo"];
228         }
229
230         if (count($x) AND ($x[0]["network"] == "") AND ($network != "")) {
231                 q("UPDATE `gcontact` SET `network` = '%s' WHERE `nurl` = '%s'",
232                         dbesc($network),
233                         dbesc(normalise_link($profile_url))
234                 );
235         }
236
237         if (($name == "") OR ($profile_photo == ""))
238                 return $gcid;
239
240         if (!in_array($network, array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_DIASPORA)))
241                 return $gcid;
242
243         logger("profile-check generation: ".$generation." Network: ".$network." URL: ".$profile_url." name: ".$name." avatar: ".$profile_photo, LOGGER_DEBUG);
244
245         // Only fetch last update manually if it wasn't provided and enabled in the system
246         if (get_config('system','ld_discover_activity') AND ($orig_updated == "0000-00-00 00:00:00") AND poco_do_update($updated, $last_contact, $last_failure)) {
247                 $last_updated = poco_last_updated($profile_url);
248                 if ($last_updated) {
249                         $updated = $last_updated;
250                         $last_contact = datetime_convert();
251                         logger("Last updated for profile ".$profile_url.": ".$updated, LOGGER_DEBUG);
252
253                         if (count($x))
254                                 q("UPDATE `gcontact` SET `last_contact` = '%s' WHERE `nurl` = '%s'", dbesc($last_contact), dbesc(normalise_link($profile_url)));
255                 } else {
256                         $last_failure = datetime_convert();
257
258                         if (count($x))
259                                 q("UPDATE `gcontact` SET `last_failure` = '%s' WHERE `nurl` = '%s'", dbesc($last_failure), dbesc(normalise_link($profile_url)));
260                 }
261         }
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',
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($updated),
291                                 dbesc($location),
292                                 dbesc($about),
293                                 dbesc($keywords),
294                                 dbesc($gender),
295                                 intval($generation),
296                                 intval($generation),
297                                 dbesc(normalise_link($profile_url))
298                         );
299                 }
300         } else {
301                 q("INSERT INTO `gcontact` (`name`,`network`, `url`,`nurl`,`photo`,`connect`, `updated`, `last_contact`, `last_failure`, `location`, `about`, `keywords`, `gender`, `generation`)
302                         VALUES ('%s', '%s', '%s', '%s', '%s','%s', '%s', '%s', '%s', '%s', '%s', %d)",
303                         dbesc($name),
304                         dbesc($network),
305                         dbesc($profile_url),
306                         dbesc(normalise_link($profile_url)),
307                         dbesc($profile_photo),
308                         dbesc($connect_url),
309                         dbesc($updated),
310                         dbesc($last_contact),
311                         dbesc($last_failure),
312                         dbesc($location),
313                         dbesc($about),
314                         dbesc($keywords),
315                         dbesc($gender),
316                         intval($generation)
317                 );
318                 $x = q("SELECT * FROM `gcontact` WHERE `nurl` = '%s' LIMIT 1",
319                         dbesc(normalise_link($profile_url))
320                 );
321                 if(count($x))
322                         $gcid = $x[0]['id'];
323         }
324
325         if(! $gcid)
326                 return $gcid;
327
328         $r = q("SELECT * FROM `glink` WHERE `cid` = %d AND `uid` = %d AND `gcid` = %d AND `zcid` = %d LIMIT 1",
329                 intval($cid),
330                 intval($uid),
331                 intval($gcid),
332                 intval($zcid)
333         );
334         if(! count($r)) {
335                 q("INSERT INTO `glink` (`cid`,`uid`,`gcid`,`zcid`, `updated`) VALUES (%d,%d,%d,%d, '%s') ",
336                         intval($cid),
337                         intval($uid),
338                         intval($gcid),
339                         intval($zcid),
340                         dbesc(datetime_convert())
341                 );
342         } else {
343                 q("UPDATE `glink` SET `updated` = '%s' WHERE `cid` = %d AND `uid` = %d AND `gcid` = %d AND `zcid` = %d",
344                         dbesc(datetime_convert()),
345                         intval($cid),
346                         intval($uid),
347                         intval($gcid),
348                         intval($zcid)
349                 );
350         }
351
352         // For unknown reasons there are sometimes duplicates
353         q("DELETE FROM `gcontact` WHERE `nurl` = '%s' AND `id` != %d AND
354                 NOT EXISTS (SELECT `gcid` FROM `glink` WHERE `gcid` = `gcontact`.`id`)",
355                 dbesc(normalise_link($profile_url)),
356                 intval($gcid)
357         );
358
359         return $gcid;
360 }
361
362 function poco_last_updated($profile) {
363         $data = probe_url($profile);
364
365         if (($data["poll"] == "") OR ($data["network"] == NETWORK_FEED))
366                 return false;
367
368         // To-Do: Use noscrape
369
370         $feedret = z_fetch_url($data["poll"]);
371
372         if (!$feedret["success"])
373                 return false;
374
375         $doc = new DOMDocument();
376         @$doc->loadXML($feedret["body"]);
377
378         $xpath = new DomXPath($doc);
379         $xpath->registerNamespace('atom', "http://www.w3.org/2005/Atom");
380
381         $entries = $xpath->query('/atom:feed/atom:entry');
382
383         $last_updated = "";
384
385         foreach ($entries AS $entry) {
386                 $published = $xpath->query('atom:published/text()', $entry)->item(0)->nodeValue;
387                 $updated = $xpath->query('atom:updated/text()', $entry)->item(0)->nodeValue;
388
389                 if ($last_updated < $published)
390                         $last_updated = $published;
391
392                 if ($last_updated < $updated)
393                         $last_updated = $updated;
394         }
395
396         // Maybe there aren't any entries. Then check if it is a valid feed
397         if ($last_updated == "")
398                 if ($xpath->query('/atom:feed')->length > 0)
399                         $last_updated = "0000-00-00 00:00:00";
400
401         return($last_updated);
402 }
403
404 function poco_do_update($updated, $last_contact, $last_failure) {
405         $now = strtotime(datetime_convert());
406
407         if ($updated > $last_contact)
408                 $contact_time = strtotime($updated);
409         else
410                 $contact_time = strtotime($last_contact);
411
412         $failure_time = strtotime($last_failure);
413
414         // If the last contact was less than 24 hours then don't update
415         if (($now - $contact_time) < (60 * 60 * 24))
416                 return false;
417
418         // If the last failure was less than 24 hours then don't update
419         if (($now - $failure_time) < (60 * 60 * 24))
420                 return false;
421
422         // If the last contact was less than a week ago and the last failure is older than a week then don't update
423         if ((($now - $contact_time) < (60 * 60 * 24 * 7)) AND ($contact_time > $failure_time))
424                 return false;
425
426         // If the last contact time was more than a week ago, then only try once a week
427         if (($now - $contact_time) > (60 * 60 * 24 * 7) AND ($now - $failure_time) < (60 * 60 * 24 * 7))
428                 return false;
429
430         // If the last contact time was more than a month ago, then only try once a month
431         if (($now - $contact_time) > (60 * 60 * 24 * 30) AND ($now - $failure_time) < (60 * 60 * 24 * 30))
432                 return false;
433
434         return true;
435 }
436
437 function poco_contact_from_body($body, $created, $cid, $uid) {
438         preg_replace_callback("/\[share(.*?)\].*?\[\/share\]/ism",
439                 function ($match) use ($created, $cid, $uid){
440                         return(sub_poco_from_share($match, $created, $cid, $uid));
441                 }, $body);
442 }
443
444 function sub_poco_from_share($share, $created, $cid, $uid) {
445         $profile = "";
446         preg_match("/profile='(.*?)'/ism", $share[1], $matches);
447         if ($matches[1] != "")
448                 $profile = $matches[1];
449
450         preg_match('/profile="(.*?)"/ism', $share[1], $matches);
451         if ($matches[1] != "")
452                 $profile = $matches[1];
453
454         if ($profile == "")
455                 return;
456
457         logger("prepare poco_check for profile ".$profile, LOGGER_DEBUG);
458         poco_check($profile, "", "", "", "", "", "", "", "", $created, 3, $cid, $uid);
459 }
460
461 function poco_store($item) {
462
463         // Isn't it public?
464         if ($item['private'])
465                 return;
466
467         // Or is it from a network where we don't store the global contacts?
468         if (!in_array($item["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, NETWORK_STATUSNET, "")))
469                 return;
470
471         // Is it a global copy?
472         $store_gcontact = ($item["uid"] == 0);
473
474         // Is it a comment on a global copy?
475         if (!$store_gcontact AND ($item["uri"] != $item["parent-uri"])) {
476                 $q = q("SELECT `id` FROM `item` WHERE `uri`='%s' AND `uid` = 0", $item["parent-uri"]);
477                 $store_gcontact = count($q);
478         }
479
480         if (!$store_gcontact)
481                 return;
482
483         // "3" means: We don't know this contact directly (Maybe a reshared item)
484         $generation = 3;
485         $network = "";
486         $profile_url = $item["author-link"];
487
488         // Is it a user from our server?
489         $q = q("SELECT `id` FROM `contact` WHERE `self` AND `nurl` = '%s' LIMIT 1",
490                 dbesc(normalise_link($item["author-link"])));
491         if (count($q)) {
492                 logger("Our user (generation 1): ".$item["author-link"], LOGGER_DEBUG);
493                 $generation = 1;
494                 $network = NETWORK_DFRN;
495         } else { // Is it a contact from a user on our server?
496                 $q = q("SELECT `network`, `url` FROM `contact` WHERE `uid` != 0 AND `network` != ''
497                         AND (`nurl` = '%s' OR `alias` IN ('%s', '%s')) AND `network` != '%s' LIMIT 1",
498                         dbesc(normalise_link($item["author-link"])),
499                         dbesc(normalise_link($item["author-link"])),
500                         dbesc($item["author-link"]),
501                         dbesc(NETWORK_STATUSNET));
502                 if (count($q)) {
503                         $generation = 2;
504                         $network = $q[0]["network"];
505                         $profile_url = $q[0]["url"];
506                         logger("Known contact (generation 2): ".$profile_url, LOGGER_DEBUG);
507                 }
508         }
509
510         if ($generation == 3)
511                 logger("Unknown contact (generation 3): ".$item["author-link"], LOGGER_DEBUG);
512
513         poco_check($profile_url, $item["author-name"], $network, $item["author-avatar"], "", "", "", "", "", $item["received"], $generation, $item["contact-id"], $item["uid"]);
514
515         // Maybe its a body with a shared item? Then extract a global contact from it.
516         poco_contact_from_body($item["body"], $item["received"], $item["contact-id"], $item["uid"]);
517 }
518
519 function count_common_friends($uid,$cid) {
520
521         $r = q("SELECT count(*) as `total`
522                 FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
523                 where `glink`.`cid` = %d and `glink`.`uid` = %d
524                 and `gcontact`.`nurl` in (select nurl from contact where uid = %d and self = 0 and blocked = 0 and hidden = 0 and id != %d ) ",
525                 intval($cid),
526                 intval($uid),
527                 intval($uid),
528                 intval($cid)
529         );
530
531 //      logger("count_common_friends: $uid $cid {$r[0]['total']}"); 
532         if(count($r))
533                 return $r[0]['total'];
534         return 0;
535
536 }
537
538
539 function common_friends($uid,$cid,$start = 0,$limit=9999,$shuffle = false) {
540
541         if($shuffle)
542                 $sql_extra = " order by rand() ";
543         else
544                 $sql_extra = " order by `gcontact`.`name` asc ";
545
546         $r = q("SELECT `gcontact`.*
547                 FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
548                 where `glink`.`cid` = %d and `glink`.`uid` = %d
549                 and `gcontact`.`nurl` in (select nurl from contact where uid = %d and self = 0 and blocked = 0 and hidden = 0 and id != %d ) 
550                 $sql_extra limit %d, %d",
551                 intval($cid),
552                 intval($uid),
553                 intval($uid),
554                 intval($cid),
555                 intval($start),
556                 intval($limit)
557         );
558
559         return $r;
560
561 }
562
563
564 function count_common_friends_zcid($uid,$zcid) {
565
566         $r = q("SELECT count(*) as `total`
567                 FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
568                 where `glink`.`zcid` = %d
569                 and `gcontact`.`nurl` in (select nurl from contact where uid = %d and self = 0 and blocked = 0 and hidden = 0 ) ",
570                 intval($zcid),
571                 intval($uid)
572         );
573
574         if(count($r))
575                 return $r[0]['total'];
576         return 0;
577
578 }
579
580 function common_friends_zcid($uid,$zcid,$start = 0, $limit = 9999,$shuffle = false) {
581
582         if($shuffle)
583                 $sql_extra = " order by rand() ";
584         else
585                 $sql_extra = " order by `gcontact`.`name` asc ";
586
587         $r = q("SELECT `gcontact`.*
588                 FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
589                 where `glink`.`zcid` = %d
590                 and `gcontact`.`nurl` in (select nurl from contact where uid = %d and self = 0 and blocked = 0 and hidden = 0 ) 
591                 $sql_extra limit %d, %d",
592                 intval($zcid),
593                 intval($uid),
594                 intval($start),
595                 intval($limit)
596         );
597
598         return $r;
599
600 }
601
602
603 function count_all_friends($uid,$cid) {
604
605         $r = q("SELECT count(*) as `total`
606                 FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
607                 where `glink`.`cid` = %d and `glink`.`uid` = %d ",
608                 intval($cid),
609                 intval($uid)
610         );
611
612         if(count($r))
613                 return $r[0]['total'];
614         return 0;
615
616 }
617
618
619 function all_friends($uid,$cid,$start = 0, $limit = 80) {
620
621         $r = q("SELECT `gcontact`.*
622                 FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
623                 where `glink`.`cid` = %d and `glink`.`uid` = %d
624                 order by `gcontact`.`name` asc LIMIT %d, %d ",
625                 intval($cid),
626                 intval($uid),
627                 intval($start),
628                 intval($limit)
629         );
630
631         return $r;
632 }
633
634
635
636 function suggestion_query($uid, $start = 0, $limit = 80) {
637
638         if(! $uid)
639                 return array();
640
641         $network = array(NETWORK_DFRN);
642
643         if (get_config('system','diaspora_enabled'))
644                 $network[] = NETWORK_DIASPORA;
645
646         if (!get_config('system','ostatus_disabled'))
647                 $network[] = NETWORK_OSTATUS;
648
649         $sql_network = implode("', '", $network);
650         //$sql_network = "'".$sql_network."', ''";
651         $sql_network = "'".$sql_network."'";
652
653         $r = q("SELECT count(glink.gcid) as `total`, gcontact.* from gcontact
654                 INNER JOIN glink on glink.gcid = gcontact.id
655                 where uid = %d and not gcontact.nurl in ( select nurl from contact where uid = %d )
656                 and not gcontact.name in ( select name from contact where uid = %d )
657                 and not gcontact.id in ( select gcid from gcign where uid = %d )
658                 AND `gcontact`.`updated` != '0000-00-00 00:00:00'
659                 AND `gcontact`.`last_contact` >= `gcontact`.`last_failure`
660                 AND `gcontact`.`network` IN (%s)
661                 group by glink.gcid order by gcontact.updated desc,total desc limit %d, %d ",
662                 intval($uid),
663                 intval($uid),
664                 intval($uid),
665                 intval($uid),
666                 $sql_network,
667                 intval($start),
668                 intval($limit)
669         );
670
671         if(count($r) && count($r) >= ($limit -1))
672                 return $r;
673
674         $r2 = q("SELECT gcontact.* from gcontact
675                 INNER JOIN glink on glink.gcid = gcontact.id
676                 where glink.uid = 0 and glink.cid = 0 and glink.zcid = 0 and not gcontact.nurl in ( select nurl from contact where uid = %d )
677                 and not gcontact.name in ( select name from contact where uid = %d )
678                 and not gcontact.id in ( select gcid from gcign where uid = %d )
679                 AND `gcontact`.`updated` != '0000-00-00 00:00:00'
680                 AND `gcontact`.`network` IN (%s)
681                 order by rand() limit %d, %d ",
682                 intval($uid),
683                 intval($uid),
684                 intval($uid),
685                 $sql_network,
686                 intval($start),
687                 intval($limit)
688         );
689
690         $list = array();
691         foreach ($r2 AS $suggestion)
692                 $list[$suggestion["nurl"]] = $suggestion;
693
694         foreach ($r AS $suggestion)
695                 $list[$suggestion["nurl"]] = $suggestion;
696
697         return $list;
698 }
699
700 function update_suggestions() {
701
702         $a = get_app();
703
704         $done = array();
705
706         poco_load(0,0,0,$a->get_baseurl() . '/poco');
707
708         $done[] = $a->get_baseurl() . '/poco';
709
710         if(strlen(get_config('system','directory_submit_url'))) {
711                 $x = fetch_url('http://dir.friendica.com/pubsites');
712                 if($x) {
713                         $j = json_decode($x);
714                         if($j->entries) {
715                                 foreach($j->entries as $entry) {
716                                         $url = $entry->url . '/poco';
717                                         if(! in_array($url,$done))
718                                                 poco_load(0,0,0,$entry->url . '/poco');
719                                 }
720                         }
721                 }
722         }
723
724         $r = q("select distinct(poco) as poco from contact where network = '%s'",
725                 dbesc(NETWORK_DFRN)
726         );
727
728         if(count($r)) {
729                 foreach($r as $rr) {
730                         $base = substr($rr['poco'],0,strrpos($rr['poco'],'/'));
731                         if(! in_array($base,$done))
732                                 poco_load(0,0,0,$base);
733                 }
734         }
735 }