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