]> git.mxchange.org Git - friendica.git/blob - include/socgraph.php
Onepoll: mark the last request failure for this contact
[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  - Make search for last activity optional
11  - only export contacts via poco where update is higher than failure
12  - check your own contacts in some way as well
13 */
14
15 /*
16  * poco_load
17  *
18  * Given a contact-id (minimum), load the PortableContacts friend list for that contact,
19  * and add the entries to the gcontact (Global Contact) table, or update existing entries
20  * if anything (name or photo) has changed.
21  * We use normalised urls for comparison which ignore http vs https and www.domain vs domain
22  *
23  * Once the global contact is stored add (if necessary) the contact linkage which associates
24  * the given uid, cid to the global contact entry. There can be many uid/cid combinations
25  * pointing to the same global contact id.
26  *
27  */
28
29
30
31
32 function poco_load($cid,$uid = 0,$zcid = 0,$url = null) {
33
34         require_once("include/html2bbcode.php");
35
36         $a = get_app();
37
38         if($cid) {
39                 if((! $url) || (! $uid)) {
40                         $r = q("select `poco`, `uid` from `contact` where `id` = %d limit 1",
41                                 intval($cid)
42                         );
43                         if(count($r)) {
44                                 $url = $r[0]['poco'];
45                                 $uid = $r[0]['uid'];
46                         }
47                 }
48                 if(! $uid)
49                         return;
50         }
51
52         if(! $url)
53                 return;
54
55         $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') ;
56
57         logger('poco_load: ' . $url, LOGGER_DEBUG);
58
59         $s = fetch_url($url);
60
61         logger('poco_load: returns ' . $s, LOGGER_DATA);
62
63         logger('poco_load: return code: ' . $a->get_curl_code(), LOGGER_DEBUG);
64
65         if(($a->get_curl_code() > 299) || (! $s))
66                 return;
67
68         $j = json_decode($s);
69
70         logger('poco_load: json: ' . print_r($j,true),LOGGER_DATA);
71
72         if(! isset($j->entry))
73                 return;
74
75         $total = 0;
76         foreach($j->entry as $entry) {
77
78                 $total ++;
79                 $profile_url = '';
80                 $profile_photo = '';
81                 $connect_url = '';
82                 $name = '';
83                 $network = '';
84                 $updated = '0000-00-00 00:00:00';
85                 $location = '';
86                 $about = '';
87                 $keywords = '';
88                 $gender = '';
89                 $generation = 0;
90
91                 $name = $entry->displayName;
92
93                 if(isset($entry->urls)) {
94                         foreach($entry->urls as $url) {
95                                 if($url->type == 'profile') {
96                                         $profile_url = $url->value;
97                                         continue;
98                                 }
99                                 if($url->type == 'webfinger') {
100                                         $connect_url = str_replace('acct:' , '', $url->value);
101                                         continue;
102                                 }
103                         }
104                 }
105                 if(isset($entry->photos)) {
106                         foreach($entry->photos as $photo) {
107                                 if($photo->type == 'profile') {
108                                         $profile_photo = $photo->value;
109                                         continue;
110                                 }
111                         }
112                 }
113
114                 if(isset($entry->updated))
115                         $updated = date("Y-m-d H:i:s", strtotime($entry->updated));
116
117                 if(isset($entry->network))
118                         $network = $entry->network;
119
120                 if(isset($entry->currentLocation))
121                         $location = $entry->currentLocation;
122
123                 if(isset($entry->aboutMe))
124                         $about = html2bbcode($entry->aboutMe);
125
126                 if(isset($entry->gender))
127                         $gender = $entry->gender;
128
129                 if(isset($entry->generation) AND ($entry->generation > 0))
130                         $generation = ++$entry->generation;
131
132                 if(isset($entry->tags))
133                         foreach($entry->tags as $tag)
134                                 $keywords = implode(", ", $tag);
135
136                 // If you query a Friendica server for its profiles, the network has to be Friendica
137                 // To-Do: It could also be a Redmatrix server
138                 //if ($uid == 0)
139                 //      $network = NETWORK_DFRN;
140
141                 poco_check($profile_url, $name, $network, $profile_photo, $about, $location, $gender, $keywords, $connect_url, $updated, $generation, $cid, $uid, $zcid);
142
143                 // Update the Friendica contacts. Diaspora is doing it via a message. (See include/diaspora.php)
144                 if (($location != "") OR ($about != "") OR ($keywords != "") OR ($gender != ""))
145                         q("UPDATE `contact` SET `location` = '%s', `about` = '%s', `keywords` = '%s', `gender` = '%s'
146                                 WHERE `nurl` = '%s' AND NOT `self` AND `network` = '%s'",
147                                 dbesc($location),
148                                 dbesc($about),
149                                 dbesc($keywords),
150                                 dbesc($gender),
151                                 dbesc(normalise_link($profile_url)),
152                                 dbesc(NETWORK_DFRN));
153         }
154         logger("poco_load: loaded $total entries",LOGGER_DEBUG);
155
156         q("DELETE FROM `glink` WHERE `cid` = %d AND `uid` = %d AND `zcid` = %d AND `updated` < UTC_TIMESTAMP - INTERVAL 2 DAY",
157                 intval($cid),
158                 intval($uid),
159                 intval($zcid)
160         );
161
162 }
163
164 function poco_check($profile_url, $name, $network, $profile_photo, $about, $location, $gender, $keywords, $connect_url, $updated, $generation, $cid = 0, $uid = 0, $zcid = 0) {
165
166         $a = get_app();
167
168         // Generation:
169         //  0: No definition
170         //  1: Profiles on this server
171         //  2: Contacts of profiles on this server
172         //  3: Contacts of contacts of profiles on this server
173         //  4: ...
174
175         $gcid = "";
176
177         if ($profile_url == "")
178                 return $gcid;
179
180         $orig_updated = $updated;
181
182         // Don't store the statusnet connector as network
183         // We can't simply set this to NETWORK_OSTATUS since the connector could have fetched posts from friendica as well
184         if ($network == NETWORK_STATUSNET)
185                 $network = "";
186
187         // The global contacts should contain the original picture, not the cached one
188         if (($generation != 1) AND stristr(normalise_link($profile_photo), normalise_link($a->get_baseurl()."/photo/")))
189                 $profile_photo = "";
190
191         $r = q("SELECT `network` FROM `contact` WHERE `nurl` = '%s' AND `network` != '' AND `network` != '%s' LIMIT 1",
192                 dbesc(normalise_link($profile_url)), dbesc(NETWORK_STATUSNET)
193         );
194         if(count($r))
195                 $network = $r[0]["network"];
196
197         if (($network == "") OR ($network == NETWORK_OSTATUS)) {
198                 $r = q("SELECT `network`, `url` FROM `contact` WHERE `alias` IN ('%s', '%s') AND `network` != '' AND `network` != '%s' LIMIT 1",
199                         dbesc($profile_url), dbesc(normalise_link($profile_url)), dbesc(NETWORK_STATUSNET)
200                 );
201                 if(count($r)) {
202                         $network = $r[0]["network"];
203                         $profile_url = $r[0]["url"];
204                 }
205         }
206
207         $x = q("SELECT * FROM `gcontact` WHERE `nurl` = '%s' LIMIT 1",
208                 dbesc(normalise_link($profile_url))
209         );
210
211         if (count($x)) {
212                 if (($network == "") AND ($x[0]["network"] != NETWORK_STATUSNET))
213                         $network = $x[0]["network"];
214
215                 if ($updated == "0000-00-00 00:00:00")
216                         $updated = $x[0]["updated"];
217
218                 $last_contact = $x[0]["last_contact"];
219                 $last_failure = $x[0]["last_failure"];
220         } else {
221                 $last_contact = "0000-00-00 00:00:00";
222                 $last_failure = "0000-00-00 00:00:00";
223         }
224
225         if (($network == "") OR ($name == "") OR ($profile_photo == "")) {
226                 $data = probe_url($profile_url);
227                 $network = $data["network"];
228                 $name = $data["name"];
229                 $profile_url = $data["url"];
230                 $profile_photo = $data["photo"];
231         }
232
233         if (count($x) AND ($x[0]["network"] == "") AND ($network != "")) {
234                 q("UPDATE `gcontact` SET `network` = '%s' WHERE `nurl` = '%s'",
235                         dbesc($network),
236                         dbesc(normalise_link($profile_url))
237                 );
238         }
239
240         if (($name == "") OR ($profile_photo == ""))
241                 return $gcid;
242
243         if (!in_array($network, array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_DIASPORA)))
244                 return $gcid;
245
246         logger("profile-check generation: ".$generation." Network: ".$network." URL: ".$profile_url." name: ".$name." avatar: ".$profile_photo, LOGGER_DEBUG);
247
248         // Only fetch last update manually if it wasn't provided
249         if (($orig_updated == "0000-00-00 00:00:00") AND poco_do_update($updated, $last_contact, $last_failure)) {
250                 $last_updated = poco_last_updated($profile_url);
251                 if ($last_updated) {
252                         $updated = $last_updated;
253                         $last_contact = datetime_convert();
254                         logger("Last updated for profile ".$profile_url.": ".$updated, LOGGER_DEBUG);
255
256                         if (count($x))
257                                 q("UPDATE `gcontact` SET `last_contact` = '%s' WHERE `nurl` = '%s'", dbesc($last_contact), dbesc(normalise_link($profile_url)));
258                 } else {
259                         $last_failure = datetime_convert();
260
261                         if (count($x))
262                                 q("UPDATE `gcontact` SET `last_failure` = '%s' WHERE `nurl` = '%s'", dbesc($last_failure), dbesc(normalise_link($profile_url)));
263                 }
264         }
265
266         if(count($x)) {
267                 $gcid = $x[0]['id'];
268
269                 if (($location == "") AND ($x[0]['location'] != ""))
270                         $location = $x[0]['location'];
271
272                 if (($about == "") AND ($x[0]['about'] != ""))
273                         $about = $x[0]['about'];
274
275                 if (($gender == "") AND ($x[0]['gender'] != ""))
276                         $gender = $x[0]['gender'];
277
278                 if (($keywords == "") AND ($x[0]['keywords'] != ""))
279                         $keywords = $x[0]['keywords'];
280
281                 if (($generation == 0) AND ($x[0]['generation'] > 0))
282                         $generation = $x[0]['generation'];
283
284                 if($x[0]['name'] != $name || $x[0]['photo'] != $profile_photo || $x[0]['updated'] < $updated) {
285                         q("UPDATE `gcontact` SET `name` = '%s', `network` = '%s', `photo` = '%s', `connect` = '%s', `url` = '%s',
286                                 `updated` = '%s', `location` = '%s', `about` = '%s', `keywords` = '%s', `gender` = '%s', `generation` = %d
287                                 WHERE (`generation` >= %d OR `generation` = 0) AND `nurl` = '%s'",
288                                 dbesc($name),
289                                 dbesc($network),
290                                 dbesc($profile_photo),
291                                 dbesc($connect_url),
292                                 dbesc($profile_url),
293                                 dbesc($updated),
294                                 dbesc($location),
295                                 dbesc($about),
296                                 dbesc($keywords),
297                                 dbesc($gender),
298                                 intval($generation),
299                                 intval($generation),
300                                 dbesc(normalise_link($profile_url))
301                         );
302                 }
303         } else {
304                 q("INSERT INTO `gcontact` (`name`,`network`, `url`,`nurl`,`photo`,`connect`, `updated`, `last_contact`, `last_failure`, `location`, `about`, `keywords`, `gender`, `generation`)
305                         VALUES ('%s', '%s', '%s', '%s', '%s','%s', '%s', '%s', '%s', '%s', '%s', %d)",
306                         dbesc($name),
307                         dbesc($network),
308                         dbesc($profile_url),
309                         dbesc(normalise_link($profile_url)),
310                         dbesc($profile_photo),
311                         dbesc($connect_url),
312                         dbesc($updated),
313                         dbesc($last_contact),
314                         dbesc($last_failure),
315                         dbesc($location),
316                         dbesc($about),
317                         dbesc($keywords),
318                         dbesc($gender),
319                         intval($generation)
320                 );
321                 $x = q("SELECT * FROM `gcontact` WHERE `nurl` = '%s' LIMIT 1",
322                         dbesc(normalise_link($profile_url))
323                 );
324                 if(count($x))
325                         $gcid = $x[0]['id'];
326         }
327
328         if(! $gcid)
329                 return $gcid;
330
331         $r = q("SELECT * FROM `glink` WHERE `cid` = %d AND `uid` = %d AND `gcid` = %d AND `zcid` = %d LIMIT 1",
332                 intval($cid),
333                 intval($uid),
334                 intval($gcid),
335                 intval($zcid)
336         );
337         if(! count($r)) {
338                 q("INSERT INTO `glink` (`cid`,`uid`,`gcid`,`zcid`, `updated`) VALUES (%d,%d,%d,%d, '%s') ",
339                         intval($cid),
340                         intval($uid),
341                         intval($gcid),
342                         intval($zcid),
343                         dbesc(datetime_convert())
344                 );
345         } else {
346                 q("UPDATE `glink` SET `updated` = '%s' WHERE `cid` = %d AND `uid` = %d AND `gcid` = %d AND `zcid` = %d",
347                         dbesc(datetime_convert()),
348                         intval($cid),
349                         intval($uid),
350                         intval($gcid),
351                         intval($zcid)
352                 );
353         }
354
355         // For unknown reasons there are sometimes duplicates
356         q("DELETE FROM `gcontact` WHERE `nurl` = '%s' AND `id` != %d AND
357                 NOT EXISTS (SELECT `gcid` FROM `glink` WHERE `gcid` = `gcontact`.`id`)",
358                 dbesc(normalise_link($profile_url)),
359                 intval($gcid)
360         );
361
362         return $gcid;
363 }
364
365 function poco_last_updated($profile) {
366         $data = probe_url($profile);
367
368         if (($data["poll"] == "") OR ($data["network"] == NETWORK_FEED))
369                 return false;
370
371         // To-Do: Use noscrape
372
373         $feedret = z_fetch_url($data["poll"]);
374
375         if (!$feedret["success"])
376                 return false;
377
378         $doc = new DOMDocument();
379         @$doc->loadXML($feedret["body"]);
380
381         $xpath = new DomXPath($doc);
382         $xpath->registerNamespace('atom', "http://www.w3.org/2005/Atom");
383
384         $entries = $xpath->query('/atom:feed/atom:entry');
385
386         $last_updated = "";
387
388         foreach ($entries AS $entry) {
389                 $published = $xpath->query('atom:published/text()', $entry)->item(0)->nodeValue;
390                 $updated = $xpath->query('atom:updated/text()', $entry)->item(0)->nodeValue;
391
392                 if ($last_updated < $published)
393                         $last_updated = $published;
394
395                 if ($last_updated < $updated)
396                         $last_updated = $updated;
397         }
398
399         // Maybe there aren't any entries. Then check if it is a valid feed
400         if ($last_updated == "")
401                 if ($xpath->query('/atom:feed')->length > 0)
402                         $last_updated = "0000-00-00 00:00:00";
403
404         return($last_updated);
405 }
406
407 function poco_do_update($updated, $last_contact, $last_failure) {
408         $now = strtotime(datetime_convert());
409
410         if ($updated > $last_contact)
411                 $contact_time = strtotime($updated);
412         else
413                 $contact_time = strtotime($last_contact);
414
415         $failure_time = strtotime($last_failure);
416
417         // If the last contact was less than 24 hours then don't update
418         if (($now - $contact_time) < (60 * 60 * 24))
419                 return false;
420
421         // If the last failure was less than 24 hours then don't update
422         if (($now - $failure_time) < (60 * 60 * 24))
423                 return false;
424
425         // If the last contact was less than a week ago and the last failure is older than a week then don't update
426         if ((($now - $contact_time) < (60 * 60 * 24 * 7)) AND ($contact_time > $failure_time))
427                 return false;
428
429         // If the last contact time was more than a week ago, then only try once a week
430         if (($now - $contact_time) > (60 * 60 * 24 * 7) AND ($now - $failure_time) < (60 * 60 * 24 * 7))
431                 return false;
432
433         // If the last contact time was more than a month ago, then only try once a month
434         if (($now - $contact_time) > (60 * 60 * 24 * 30) AND ($now - $failure_time) < (60 * 60 * 24 * 30))
435                 return false;
436
437         return true;
438 }
439
440 function poco_contact_from_body($body, $created, $cid, $uid) {
441         preg_replace_callback("/\[share(.*?)\].*?\[\/share\]/ism",
442                 function ($match) use ($created, $cid, $uid){
443                         return(sub_poco_from_share($match, $created, $cid, $uid));
444                 }, $body);
445 }
446
447 function sub_poco_from_share($share, $created, $cid, $uid) {
448         $profile = "";
449         preg_match("/profile='(.*?)'/ism", $share[1], $matches);
450         if ($matches[1] != "")
451                 $profile = $matches[1];
452
453         preg_match('/profile="(.*?)"/ism', $share[1], $matches);
454         if ($matches[1] != "")
455                 $profile = $matches[1];
456
457         if ($profile == "")
458                 return;
459
460         logger("prepare poco_check for profile ".$profile, LOGGER_DEBUG);
461         poco_check($profile, "", "", "", "", "", "", "", "", $created, 3, $cid, $uid);
462 }
463
464 function poco_store($item) {
465
466         // Isn't it public?
467         if ($item['private'])
468                 return;
469
470         // Or is it from a network where we don't store the global contacts?
471         if (!in_array($item["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, NETWORK_STATUSNET, "")))
472                 return;
473
474         // Is it a global copy?
475         $store_gcontact = ($item["uid"] == 0);
476
477         // Is it a comment on a global copy?
478         if (!$store_gcontact AND ($item["uri"] != $item["parent-uri"])) {
479                 $q = q("SELECT `id` FROM `item` WHERE `uri`='%s' AND `uid` = 0", $item["parent-uri"]);
480                 $store_gcontact = count($q);
481         }
482
483         if (!$store_gcontact)
484                 return;
485
486         // "3" means: We don't know this contact directly (Maybe a reshared item)
487         $generation = 3;
488         $network = "";
489         $profile_url = $item["author-link"];
490
491         // Is it a user from our server?
492         $q = q("SELECT `id` FROM `contact` WHERE `self` AND `nurl` = '%s' LIMIT 1",
493                 dbesc(normalise_link($item["author-link"])));
494         if (count($q)) {
495                 logger("Our user (generation 1): ".$item["author-link"], LOGGER_DEBUG);
496                 $generation = 1;
497                 $network = NETWORK_DFRN;
498         } else { // Is it a contact from a user on our server?
499                 $q = q("SELECT `network`, `url` FROM `contact` WHERE `uid` != 0 AND `network` != ''
500                         AND (`nurl` = '%s' OR `alias` IN ('%s', '%s')) AND `network` != '%s' LIMIT 1",
501                         dbesc(normalise_link($item["author-link"])),
502                         dbesc(normalise_link($item["author-link"])),
503                         dbesc($item["author-link"]),
504                         dbesc(NETWORK_STATUSNET));
505                 if (count($q)) {
506                         $generation = 2;
507                         $network = $q[0]["network"];
508                         $profile_url = $q[0]["url"];
509                         logger("Known contact (generation 2): ".$profile_url, LOGGER_DEBUG);
510                 }
511         }
512
513         if ($generation == 3)
514                 logger("Unknown contact (generation 3): ".$item["author-link"], LOGGER_DEBUG);
515
516         poco_check($profile_url, $item["author-name"], $network, $item["author-avatar"], "", "", "", "", "", $item["received"], $generation, $item["contact-id"], $item["uid"]);
517
518         // Maybe its a body with a shared item? Then extract a global contact from it.
519         poco_contact_from_body($item["body"], $item["received"], $item["contact-id"], $item["uid"]);
520 }
521
522 function count_common_friends($uid,$cid) {
523
524         $r = q("SELECT count(*) as `total`
525                 FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
526                 where `glink`.`cid` = %d and `glink`.`uid` = %d
527                 and `gcontact`.`nurl` in (select nurl from contact where uid = %d and self = 0 and blocked = 0 and hidden = 0 and id != %d ) ",
528                 intval($cid),
529                 intval($uid),
530                 intval($uid),
531                 intval($cid)
532         );
533
534 //      logger("count_common_friends: $uid $cid {$r[0]['total']}"); 
535         if(count($r))
536                 return $r[0]['total'];
537         return 0;
538
539 }
540
541
542 function common_friends($uid,$cid,$start = 0,$limit=9999,$shuffle = false) {
543
544         if($shuffle)
545                 $sql_extra = " order by rand() ";
546         else
547                 $sql_extra = " order by `gcontact`.`name` asc ";
548
549         $r = q("SELECT `gcontact`.*
550                 FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
551                 where `glink`.`cid` = %d and `glink`.`uid` = %d
552                 and `gcontact`.`nurl` in (select nurl from contact where uid = %d and self = 0 and blocked = 0 and hidden = 0 and id != %d ) 
553                 $sql_extra limit %d, %d",
554                 intval($cid),
555                 intval($uid),
556                 intval($uid),
557                 intval($cid),
558                 intval($start),
559                 intval($limit)
560         );
561
562         return $r;
563
564 }
565
566
567 function count_common_friends_zcid($uid,$zcid) {
568
569         $r = q("SELECT count(*) as `total`
570                 FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
571                 where `glink`.`zcid` = %d
572                 and `gcontact`.`nurl` in (select nurl from contact where uid = %d and self = 0 and blocked = 0 and hidden = 0 ) ",
573                 intval($zcid),
574                 intval($uid)
575         );
576
577         if(count($r))
578                 return $r[0]['total'];
579         return 0;
580
581 }
582
583 function common_friends_zcid($uid,$zcid,$start = 0, $limit = 9999,$shuffle = false) {
584
585         if($shuffle)
586                 $sql_extra = " order by rand() ";
587         else
588                 $sql_extra = " order by `gcontact`.`name` asc ";
589
590         $r = q("SELECT `gcontact`.*
591                 FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
592                 where `glink`.`zcid` = %d
593                 and `gcontact`.`nurl` in (select nurl from contact where uid = %d and self = 0 and blocked = 0 and hidden = 0 ) 
594                 $sql_extra limit %d, %d",
595                 intval($zcid),
596                 intval($uid),
597                 intval($start),
598                 intval($limit)
599         );
600
601         return $r;
602
603 }
604
605
606 function count_all_friends($uid,$cid) {
607
608         $r = q("SELECT count(*) as `total`
609                 FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
610                 where `glink`.`cid` = %d and `glink`.`uid` = %d ",
611                 intval($cid),
612                 intval($uid)
613         );
614
615         if(count($r))
616                 return $r[0]['total'];
617         return 0;
618
619 }
620
621
622 function all_friends($uid,$cid,$start = 0, $limit = 80) {
623
624         $r = q("SELECT `gcontact`.*
625                 FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
626                 where `glink`.`cid` = %d and `glink`.`uid` = %d
627                 order by `gcontact`.`name` asc LIMIT %d, %d ",
628                 intval($cid),
629                 intval($uid),
630                 intval($start),
631                 intval($limit)
632         );
633
634         return $r;
635 }
636
637
638
639 function suggestion_query($uid, $start = 0, $limit = 80) {
640
641         if(! $uid)
642                 return array();
643
644         $network = array(NETWORK_DFRN);
645
646         if (get_config('system','diaspora_enabled'))
647                 $network[] = NETWORK_DIASPORA;
648
649         if (!get_config('system','ostatus_disabled'))
650                 $network[] = NETWORK_OSTATUS;
651
652         $sql_network = implode("', '", $network);
653         //$sql_network = "'".$sql_network."', ''";
654         $sql_network = "'".$sql_network."'";
655
656         $r = q("SELECT count(glink.gcid) as `total`, gcontact.* from gcontact
657                 INNER JOIN glink on glink.gcid = gcontact.id
658                 where uid = %d and not gcontact.nurl in ( select nurl from contact where uid = %d )
659                 and not gcontact.name in ( select name from contact where uid = %d )
660                 and not gcontact.id in ( select gcid from gcign where uid = %d )
661                 AND `gcontact`.`updated` != '0000-00-00 00:00:00'
662                 AND `gcontact`.`last_contact` >= `gcontact`.`last_failure`
663                 AND `gcontact`.`network` IN (%s)
664                 group by glink.gcid order by gcontact.updated desc,total desc limit %d, %d ",
665                 intval($uid),
666                 intval($uid),
667                 intval($uid),
668                 intval($uid),
669                 $sql_network,
670                 intval($start),
671                 intval($limit)
672         );
673
674         if(count($r) && count($r) >= ($limit -1))
675                 return $r;
676
677         $r2 = q("SELECT gcontact.* from gcontact
678                 INNER JOIN glink on glink.gcid = gcontact.id
679                 where glink.uid = 0 and glink.cid = 0 and glink.zcid = 0 and not gcontact.nurl in ( select nurl from contact where uid = %d )
680                 and not gcontact.name in ( select name from contact where uid = %d )
681                 and not gcontact.id in ( select gcid from gcign where uid = %d )
682                 AND `gcontact`.`updated` != '0000-00-00 00:00:00'
683                 AND `gcontact`.`network` IN (%s)
684                 order by rand() limit %d, %d ",
685                 intval($uid),
686                 intval($uid),
687                 intval($uid),
688                 $sql_network,
689                 intval($start),
690                 intval($limit)
691         );
692
693         $list = array();
694         foreach ($r2 AS $suggestion)
695                 $list[$suggestion["nurl"]] = $suggestion;
696
697         foreach ($r AS $suggestion)
698                 $list[$suggestion["nurl"]] = $suggestion;
699
700         return $list;
701 }
702
703 function update_suggestions() {
704
705         $a = get_app();
706
707         $done = array();
708
709         poco_load(0,0,0,$a->get_baseurl() . '/poco');
710
711         $done[] = $a->get_baseurl() . '/poco';
712
713         if(strlen(get_config('system','directory_submit_url'))) {
714                 $x = fetch_url('http://dir.friendica.com/pubsites');
715                 if($x) {
716                         $j = json_decode($x);
717                         if($j->entries) {
718                                 foreach($j->entries as $entry) {
719                                         $url = $entry->url . '/poco';
720                                         if(! in_array($url,$done))
721                                                 poco_load(0,0,0,$entry->url . '/poco');
722                                 }
723                         }
724                 }
725         }
726
727         $r = q("select distinct(poco) as poco from contact where network = '%s'",
728                 dbesc(NETWORK_DFRN)
729         );
730
731         if(count($r)) {
732                 foreach($r as $rr) {
733                         $base = substr($rr['poco'],0,strrpos($rr['poco'],'/'));
734                         if(! in_array($base,$done))
735                                 poco_load(0,0,0,$base);
736                 }
737         }
738 }