]> git.mxchange.org Git - friendica.git/blob - include/Contact.php
New dba functions
[friendica.git] / include / Contact.php
1 <?php
2
3 use Friendica\App;
4 use Friendica\Network\Probe;
5
6 // Included here for completeness, but this is a very dangerous operation.
7 // It is the caller's responsibility to confirm the requestor's intent and
8 // authorisation to do this.
9
10 function user_remove($uid) {
11         if(! $uid)
12                 return;
13         logger('Removing user: ' . $uid);
14
15         $r = q("select * from user where uid = %d limit 1", intval($uid));
16
17         call_hooks('remove_user',$r[0]);
18
19         // save username (actually the nickname as it is guaranteed
20         // unique), so it cannot be re-registered in the future.
21
22         q("insert into userd ( username ) values ( '%s' )",
23                 $r[0]['nickname']
24         );
25
26         // The user and related data will be deleted in "cron_expire_and_remove_users" (cronjobs.php)
27         q("UPDATE `user` SET `account_removed` = 1, `account_expires_on` = UTC_TIMESTAMP() WHERE `uid` = %d", intval($uid));
28         proc_run(PRIORITY_HIGH, "include/notifier.php", "removeme", $uid);
29
30         // Send an update to the directory
31         proc_run(PRIORITY_LOW, "include/directory.php", $r[0]['url']);
32
33         if($uid == local_user()) {
34                 unset($_SESSION['authenticated']);
35                 unset($_SESSION['uid']);
36                 goaway(App::get_baseurl());
37         }
38 }
39
40
41 function contact_remove($id) {
42
43         // We want just to make sure that we don't delete our "self" contact
44         $r = q("SELECT `uid` FROM `contact` WHERE `id` = %d AND NOT `self` LIMIT 1",
45                 intval($id)
46         );
47         if (!dbm::is_result($r) || !intval($r[0]['uid'])) {
48                 return;
49         }
50
51         $archive = get_pconfig($r[0]['uid'], 'system','archive_removed_contacts');
52         if ($archive) {
53                 q("update contact set `archive` = 1, `network` = 'none', `writable` = 0 where id = %d",
54                         intval($id)
55                 );
56                 return;
57         }
58
59         q("DELETE FROM `contact` WHERE `id` = %d", intval($id));
60
61         // Delete the rest in the background
62         proc_run(PRIORITY_LOW, 'include/remove_contact.php', $id);
63 }
64
65
66 // sends an unfriend message. Does not remove the contact
67
68 function terminate_friendship($user,$self,$contact) {
69
70         /// @TODO Get rid of this, include/datetime.php should care about it by itself
71         $a = get_app();
72
73         require_once 'include/datetime.php';
74
75         if ($contact['network'] === NETWORK_OSTATUS) {
76
77                 require_once 'include/ostatus.php';
78
79                 // create an unfollow slap
80                 $item = array();
81                 $item['verb'] = NAMESPACE_OSTATUS."/unfollow";
82                 $item['follow'] = $contact["url"];
83                 $slap = ostatus::salmon($item, $user);
84
85                 if ((x($contact,'notify')) && (strlen($contact['notify']))) {
86                         require_once 'include/salmon.php';
87                         slapper($user,$contact['notify'],$slap);
88                 }
89         } elseif ($contact['network'] === NETWORK_DIASPORA) {
90                 require_once 'include/diaspora.php';
91                 Diaspora::send_unshare($user,$contact);
92         } elseif ($contact['network'] === NETWORK_DFRN) {
93                 require_once 'include/dfrn.php';
94                 dfrn::deliver($user,$contact,'placeholder', 1);
95         }
96
97 }
98
99
100 // Contact has refused to recognise us as a friend. We will start a countdown.
101 // If they still don't recognise us in 32 days, the relationship is over,
102 // and we won't waste any more time trying to communicate with them.
103 // This provides for the possibility that their database is temporarily messed
104 // up or some other transient event and that there's a possibility we could recover from it.
105
106 function mark_for_death($contact) {
107
108         if($contact['archive'])
109                 return;
110
111         if ($contact['term-date'] <= NULL_DATE) {
112                 q("UPDATE `contact` SET `term-date` = '%s' WHERE `id` = %d",
113                                 dbesc(datetime_convert()),
114                                 intval($contact['id'])
115                 );
116
117                 if ($contact['url'] != '') {
118                         q("UPDATE `contact` SET `term-date` = '%s'
119                                 WHERE `nurl` = '%s' AND `term-date` <= '1000-00-00'",
120                                         dbesc(datetime_convert()),
121                                         dbesc(normalise_link($contact['url']))
122                         );
123                 }
124         } else {
125
126                 /// @todo
127                 /// We really should send a notification to the owner after 2-3 weeks
128                 /// so they won't be surprised when the contact vanishes and can take
129                 /// remedial action if this was a serious mistake or glitch
130
131                 /// @todo
132                 /// Check for contact vitality via probing
133
134                 $expiry = $contact['term-date'] . ' + 32 days ';
135                 if(datetime_convert() > datetime_convert('UTC','UTC',$expiry)) {
136
137                         // relationship is really truly dead.
138                         // archive them rather than delete
139                         // though if the owner tries to unarchive them we'll start the whole process over again
140
141                         q("UPDATE `contact` SET `archive` = 1 WHERE `id` = %d",
142                                 intval($contact['id'])
143                         );
144
145                         if ($contact['url'] != '') {
146                                 q("UPDATE `contact` SET `archive` = 1 WHERE `nurl` = '%s'",
147                                         dbesc(normalise_link($contact['url']))
148                                 );
149                         }
150                 }
151         }
152
153 }
154
155 function unmark_for_death($contact) {
156
157         $r = q("SELECT `term-date` FROM `contact` WHERE `id` = %d AND `term-date` > '%s'",
158                 intval($contact['id']),
159                 dbesc('1000-00-00 00:00:00')
160         );
161
162         // We don't need to update, we never marked this contact as dead
163         if (!dbm::is_result($r)) {
164                 return;
165         }
166
167         // It's a miracle. Our dead contact has inexplicably come back to life.
168         q("UPDATE `contact` SET `term-date` = '%s' WHERE `id` = %d",
169                 dbesc(NULL_DATE),
170                 intval($contact['id'])
171         );
172
173         if ($contact['url'] != '') {
174                 q("UPDATE `contact` SET `term-date` = '%s' WHERE `nurl` = '%s'",
175                         dbesc(NULL_DATE),
176                         dbesc(normalise_link($contact['url']))
177                 );
178         }
179 }
180
181 /**
182  * @brief Get contact data for a given profile link
183  *
184  * The function looks at several places (contact table and gcontact table) for the contact
185  * It caches its result for the same script execution to prevent duplicate calls
186  *
187  * @param string $url The profile link
188  * @param int $uid User id
189  * @param array $default If not data was found take this data as default value
190  *
191  * @return array Contact data
192  */
193 function get_contact_details_by_url($url, $uid = -1, $default = array()) {
194         static $cache = array();
195
196         if ($url == '') {
197                 return $default;
198         }
199
200         if ($uid == -1) {
201                 $uid = local_user();
202         }
203
204         if (isset($cache[$url][$uid])) {
205                 return $cache[$url][$uid];
206         }
207
208         // Fetch contact data from the contact table for the given user
209         $s = dba::p("SELECT `id`, `id` AS `cid`, 0 AS `gid`, 0 AS `zid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
210                         `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`
211                 FROM `contact` WHERE `nurl` = ? AND `uid` = ?",
212                         normalise_link($url), $uid);
213
214         // Fetch the data from the contact table with "uid=0" (which is filled automatically)
215         if (!dbm::is_result($s))
216                 $s = dba::p("SELECT `id`, 0 AS `cid`, `id` AS `zid`, 0 AS `gid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
217                         `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`
218                         FROM `contact` WHERE `nurl` = ? AND `uid` = 0",
219                                 normalise_link($url));
220
221         // Fetch the data from the gcontact table
222         if (!dbm::is_result($s))
223                 $s = dba::p("SELECT 0 AS `id`, 0 AS `cid`, `id` AS `gid`, 0 AS `zid`, 0 AS `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, '' AS `xmpp`,
224                         `keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, `community` AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self`
225                         FROM `gcontact` WHERE `nurl` = ?",
226                                 normalise_link($url));
227
228         if (dbm::is_result($s)) {
229                 $r = dba::inArray($s);
230                 // If there is more than one entry we filter out the connector networks
231                 if (count($r) > 1) {
232                         foreach ($r AS $id => $result) {
233                                 if ($result["network"] == NETWORK_STATUSNET) {
234                                         unset($r[$id]);
235                                 }
236                         }
237                 }
238
239                 $profile = array_shift($r);
240
241                 // "bd" always contains the upcoming birthday of a contact.
242                 // "birthday" might contain the birthday including the year of birth.
243                 if ($profile["birthday"] > '0001-01-01') {
244                         $bd_timestamp = strtotime($profile["birthday"]);
245                         $month = date("m", $bd_timestamp);
246                         $day = date("d", $bd_timestamp);
247
248                         $current_timestamp = time();
249                         $current_year = date("Y", $current_timestamp);
250                         $current_month = date("m", $current_timestamp);
251                         $current_day = date("d", $current_timestamp);
252
253                         $profile["bd"] = $current_year."-".$month."-".$day;
254                         $current = $current_year."-".$current_month."-".$current_day;
255
256                         if ($profile["bd"] < $current) {
257                                 $profile["bd"] = (++$current_year)."-".$month."-".$day;
258                         }
259                 } else {
260                         $profile["bd"] = '0001-01-01';
261                 }
262         } else {
263                 $profile = $default;
264         }
265
266         if (($profile["photo"] == "") && isset($default["photo"])) {
267                 $profile["photo"] = $default["photo"];
268         }
269
270         if (($profile["name"] == "") && isset($default["name"])) {
271                 $profile["name"] = $default["name"];
272         }
273
274         if (($profile["network"] == "") && isset($default["network"])) {
275                 $profile["network"] = $default["network"];
276         }
277
278         if (($profile["thumb"] == "") && isset($profile["photo"])) {
279                 $profile["thumb"] = $profile["photo"];
280         }
281
282         if (($profile["micro"] == "") && isset($profile["thumb"])) {
283                 $profile["micro"] = $profile["thumb"];
284         }
285
286         if ((($profile["addr"] == "") || ($profile["name"] == "")) && ($profile["gid"] != 0) &&
287                 in_array($profile["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS))) {
288                 proc_run(PRIORITY_LOW, "include/update_gcontact.php", $profile["gid"]);
289         }
290
291         // Show contact details of Diaspora contacts only if connected
292         if (($profile["cid"] == 0) && ($profile["network"] == NETWORK_DIASPORA)) {
293                 $profile["location"] = "";
294                 $profile["about"] = "";
295                 $profile["gender"] = "";
296                 $profile["birthday"] = '0001-01-01';
297         }
298
299         $cache[$url][$uid] = $profile;
300
301         return $profile;
302 }
303
304 /**
305  * @brief Get contact data for a given address
306  *
307  * The function looks at several places (contact table and gcontact table) for the contact
308  *
309  * @param string $addr The profile link
310  * @param int $uid User id
311  *
312  * @return array Contact data
313  */
314 function get_contact_details_by_addr($addr, $uid = -1) {
315         static $cache = array();
316
317         if ($addr == '') {
318                 return array();
319         }
320
321         if ($uid == -1) {
322                 $uid = local_user();
323         }
324
325         // Fetch contact data from the contact table for the given user
326         $r = q("SELECT `id`, `id` AS `cid`, 0 AS `gid`, 0 AS `zid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
327                         `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`
328                 FROM `contact` WHERE `addr` = '%s' AND `uid` = %d",
329                         dbesc($addr), intval($uid));
330
331         // Fetch the data from the contact table with "uid=0" (which is filled automatically)
332         if (!dbm::is_result($r))
333                 $r = q("SELECT `id`, 0 AS `cid`, `id` AS `zid`, 0 AS `gid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
334                         `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`
335                         FROM `contact` WHERE `addr` = '%s' AND `uid` = 0",
336                                 dbesc($addr));
337
338         // Fetch the data from the gcontact table
339         if (!dbm::is_result($r))
340                 $r = q("SELECT 0 AS `id`, 0 AS `cid`, `id` AS `gid`, 0 AS `zid`, 0 AS `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, '' AS `xmpp`,
341                         `keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, `community` AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self`
342                         FROM `gcontact` WHERE `addr` = '%s'",
343                                 dbesc($addr));
344
345         if (!dbm::is_result($r)) {
346                 $data = Probe::uri($addr);
347
348                 $profile = get_contact_details_by_url($data['url'], $uid);
349         } else {
350                 $profile = $r[0];
351         }
352
353         return $profile;
354 }
355
356 if (! function_exists('contact_photo_menu')) {
357 function contact_photo_menu($contact, $uid = 0)
358 {
359         $a = get_app();
360
361         $contact_url = '';
362         $pm_url = '';
363         $status_link = '';
364         $photos_link = '';
365         $posts_link = '';
366         $contact_drop_link = '';
367         $poke_link = '';
368
369         if ($uid == 0) {
370                 $uid = local_user();
371         }
372
373         if ($contact['uid'] != $uid) {
374                 if ($uid == 0) {
375                         $profile_link = zrl($contact['url']);
376                         $menu = Array('profile' => array(t('View Profile'), $profile_link, true));
377
378                         return $menu;
379                 }
380
381                 $r = q("SELECT * FROM `contact` WHERE `nurl` = '%s' AND `network` = '%s' AND `uid` = %d",
382                         dbesc($contact['nurl']), dbesc($contact['network']), intval($uid));
383                 if ($r) {
384                         return contact_photo_menu($r[0], $uid);
385                 } else {
386                         $profile_link = zrl($contact['url']);
387                         $connlnk = 'follow/?url='.$contact['url'];
388                         $menu = array(
389                                 'profile' => array(t('View Profile'), $profile_link, true),
390                                 'follow' => array(t('Connect/Follow'), $connlnk, true)
391                         );
392
393                         return $menu;
394                 }
395         }
396
397         $sparkle = false;
398         if ($contact['network'] === NETWORK_DFRN) {
399                 $sparkle = true;
400                 $profile_link = App::get_baseurl() . '/redir/' . $contact['id'];
401         } else {
402                 $profile_link = $contact['url'];
403         }
404
405         if ($profile_link === 'mailbox') {
406                 $profile_link = '';
407         }
408
409         if ($sparkle) {
410                 $status_link = $profile_link . '?url=status';
411                 $photos_link = $profile_link . '?url=photos';
412                 $profile_link = $profile_link . '?url=profile';
413         }
414
415         if (in_array($contact['network'], array(NETWORK_DFRN, NETWORK_DIASPORA))) {
416                 $pm_url = App::get_baseurl() . '/message/new/' . $contact['id'];
417         }
418
419         if ($contact['network'] == NETWORK_DFRN) {
420                 $poke_link = App::get_baseurl() . '/poke/?f=&c=' . $contact['id'];
421         }
422
423         $contact_url = App::get_baseurl() . '/contacts/' . $contact['id'];
424
425         $posts_link = App::get_baseurl() . '/contacts/' . $contact['id'] . '/posts';
426         $contact_drop_link = App::get_baseurl() . '/contacts/' . $contact['id'] . '/drop?confirm=1';
427
428         /**
429          * menu array:
430          * "name" => [ "Label", "link", (bool)Should the link opened in a new tab? ]
431          */
432         $menu = array(
433                 'status' => array(t("View Status"), $status_link, true),
434                 'profile' => array(t("View Profile"), $profile_link, true),
435                 'photos' => array(t("View Photos"), $photos_link, true),
436                 'network' => array(t("Network Posts"), $posts_link, false),
437                 'edit' => array(t("View Contact"), $contact_url, false),
438                 'drop' => array(t("Drop Contact"), $contact_drop_link, false),
439                 'pm' => array(t("Send PM"), $pm_url, false),
440                 'poke' => array(t("Poke"), $poke_link, false),
441         );
442
443
444         $args = array('contact' => $contact, 'menu' => &$menu);
445
446         call_hooks('contact_photo_menu', $args);
447
448         $menucondensed = array();
449
450         foreach ($menu AS $menuname => $menuitem) {
451                 if ($menuitem[1] != '') {
452                         $menucondensed[$menuname] = $menuitem;
453                 }
454         }
455
456         return $menucondensed;
457 }}
458
459
460 function random_profile() {
461         $r = q("SELECT `url` FROM `gcontact` WHERE `network` = '%s'
462                                 AND `last_contact` >= `last_failure`
463                                 AND `updated` > UTC_TIMESTAMP - INTERVAL 1 MONTH
464                         ORDER BY rand() LIMIT 1",
465                 dbesc(NETWORK_DFRN));
466
467         if (dbm::is_result($r))
468                 return dirname($r[0]['url']);
469         return '';
470 }
471
472
473 function contacts_not_grouped($uid,$start = 0,$count = 0) {
474
475         if(! $count) {
476                 $r = q("select count(*) as total from contact where uid = %d and self = 0 and id not in (select distinct(`contact-id`) from group_member where uid = %d) ",
477                         intval($uid),
478                         intval($uid)
479                 );
480
481                 return $r;
482
483
484         }
485
486         $r = q("select * from contact where uid = %d and self = 0 and id not in (select distinct(`contact-id`) from group_member where uid = %d) and blocked = 0 and pending = 0 limit %d, %d",
487                 intval($uid),
488                 intval($uid),
489                 intval($start),
490                 intval($count)
491         );
492
493         return $r;
494 }
495
496 /**
497  * @brief Fetch the contact id for a given url and user
498  *
499  * First lookup in the contact table to find a record matching either `url`, `nurl`,
500  * `addr` or `alias`.
501  *
502  * If there's no record and we aren't looking for a public contact, we quit.
503  * If there's one, we check that it isn't time to update the picture else we
504  * directly return the found contact id.
505  *
506  * Second, we probe the provided $url wether it's http://server.tld/profile or
507  * nick@server.tld. We quit if we can't get any info back.
508  *
509  * Third, we create the contact record if it doesn't exist
510  *
511  * Fourth, we update the existing record with the new data (avatar, alias, nick)
512  * if there's any updates
513  *
514  * @param string $url Contact URL
515  * @param integer $uid The user id for the contact (0 = public contact)
516  * @param boolean $no_update Don't update the contact
517  *
518  * @return integer Contact ID
519  */
520 function get_contact($url, $uid = 0, $no_update = false) {
521         logger("Get contact data for url ".$url." and user ".$uid." - ".App::callstack(), LOGGER_DEBUG);
522
523         $data = array();
524         $contact_id = 0;
525
526         if ($url == '') {
527                 return 0;
528         }
529
530         // We first try the nurl (http://server.tld/nick), most common case
531         $contact = dba::select('contact', array('id', 'avatar-date'), array('nurl' => normalise_link($url), 'uid' => $uid), array('limit' => 1));
532
533         // Then the addr (nick@server.tld)
534         if (!dbm::is_result($contact)) {
535                 $contact = dba::select('contact', array('id', 'avatar-date'), array('addr' => $url, 'uid' => $uid), array('limit' => 1));
536         }
537
538         // Then the alias (which could be anything)
539         if (!dbm::is_result($contact)) {
540                 $r = dba::p("SELECT `id`, `avatar-date` FROM `contact` WHERE `alias` IN (?, ?) AND `uid` = ? LIMIT 1",
541                                 $url, normalise_link($url), $uid);
542                 $contact = dba::fetch($r);
543                 dba::close($r);
544         }
545
546         if (dbm::is_result($contact)) {
547                 $contact_id = $contact["id"];
548
549                 // Update the contact every 7 days
550                 $update_contact = ($contact['avatar-date'] < datetime_convert('','','now -7 days'));
551
552                 if (!$update_contact || $no_update) {
553                         return $contact_id;
554                 }
555         } elseif ($uid != 0) {
556                 // Non-existing user-specific contact, exiting
557                 return 0;
558         }
559
560         $data = Probe::uri($url);
561
562         // Last try in gcontact for unsupported networks
563         if (!in_array($data["network"], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_DIASPORA, NETWORK_PUMPIO))) {
564                 if ($uid != 0) {
565                         return 0;
566                 }
567
568                 // Get data from the gcontact table
569                 $gcontacts = dba::select('gcontact', array('name', 'nick', 'url', 'photo', 'addr', 'alias', 'network'),
570                                                 array('nurl' => normalise_link($url)), array('limit' => 1));
571                 if (!dbm::is_result($gcontacts)) {
572                         return 0;
573                 }
574
575                 $data = array_merge($data, $gcontacts);
576         }
577
578         $url = $data["url"];
579         if (!$contact_id) {
580                 dba::insert('contact', array('uid' => $uid, 'created' => datetime_convert(), 'url' => $data["url"],
581                                         'nurl' => normalise_link($data["url"]), 'addr' => $data["addr"],
582                                         'alias' => $data["alias"], 'notify' => $data["notify"], 'poll' => $data["poll"],
583                                         'name' => $data["name"], 'nick' => $data["nick"], 'photo' => $data["photo"],
584                                         'keywords' => $data["keywords"], 'location' => $data["location"], 'about' => $data["about"],
585                                         'network' => $data["network"], 'pubkey' => $data["pubkey"],
586                                         'rel' => CONTACT_IS_SHARING, 'priority' => $data["priority"],
587                                         'batch' => $data["batch"], 'request' => $data["request"],
588                                         'confirm' => $data["confirm"], 'poco' => $data["poco"],
589                                         'name-date' => datetime_convert(), 'uri-date' => datetime_convert(),
590                                         'avatar-date' => datetime_convert(), 'writable' => 1, 'blocked' => 0,
591                                         'readonly' => 0, 'pending' => 0));
592
593                 $contacts = q("SELECT `id` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d ORDER BY `id` LIMIT 2",
594                                 dbesc(normalise_link($data["url"])),
595                                 intval($uid));
596                 if (!dbm::is_result($contacts)) {
597                         return 0;
598                 }
599
600                 $contact_id = $contacts[0]["id"];
601
602                 // Update the newly created contact from data in the gcontact table
603                 $gcontact = dba::select('gcontact', array('location', 'about', 'keywords', 'gender'),
604                                         array('nurl' => normalise_link($data["url"])), array('limit' => 1));
605                 if (dbm::is_result($gcontact)) {
606                         // Only use the information when the probing hadn't fetched these values
607                         if ($data['keywords'] != '') {
608                                 unset($gcontact['keywords']);
609                         }
610                         if ($data['location'] != '') {
611                                 unset($gcontact['location']);
612                         }
613                         if ($data['about'] != '') {
614                                 unset($gcontact['about']);
615                         }
616                         dba::update('contact', $gcontact, array('id' => $contact_id));
617                 }
618
619                 if (count($contacts) > 1 && $uid == 0 && $contact_id != 0 && $data["url"] != "") {
620                         dba::e("DELETE FROM `contact` WHERE `nurl` = ? AND `uid` = 0 AND `id` != ? AND NOT `self`",
621                                 normalise_link($data["url"]), $contact_id);
622                 }
623         }
624
625         require_once "Photo.php";
626
627         update_contact_avatar($data["photo"], $uid, $contact_id);
628
629         $contact = dba::select('contact', array('addr', 'alias', 'name', 'nick', 'keywords', 'location', 'about', 'avatar-date'),
630                                 array('id' => $contact_id), array('limit' => 1));
631
632         // This condition should always be true
633         if (!dbm::is_result($contact)) {
634                 return $contact_id;
635         }
636
637         $updated = array('addr' => $data['addr'],
638                         'alias' => $data['alias'],
639                         'name' => $data['name'],
640                         'nick' => $data['nick']);
641
642         if ($data['keywords'] != '') {
643                 $updated['keywords'] = $data['keywords'];
644         }
645         if ($data['location'] != '') {
646                 $updated['location'] = $data['location'];
647         }
648         if ($data['about'] != '') {
649                 $updated['about'] = $data['about'];
650         }
651
652         if (($data["addr"] != $contact["addr"]) || ($data["alias"] != $contact["alias"])) {
653                 $updated['uri-date'] = datetime_convert();
654         }
655         if (($data["name"] != $contact["name"]) || ($data["nick"] != $contact["nick"])) {
656                 $updated['name-date'] = datetime_convert();
657         }
658
659         $updated['avatar-date'] = datetime_convert();
660
661         dba::update('contact', $updated, array('id' => $contact_id), $contact);
662
663         return $contact_id;
664 }
665
666 /**
667  * @brief Returns posts from a given gcontact
668  *
669  * @param App $a argv application class
670  * @param int $gcontact_id Global contact
671  *
672  * @return string posts in HTML
673  */
674 function posts_from_gcontact(App $a, $gcontact_id) {
675
676         require_once 'include/conversation.php';
677
678         // There are no posts with "uid = 0" with connector networks
679         // This speeds up the query a lot
680         $r = q("SELECT `network` FROM `gcontact` WHERE `id` = %d", dbesc($gcontact_id));
681         if (in_array($r[0]["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, "")))
682                 $sql = "(`item`.`uid` = 0 OR  (`item`.`uid` = %d AND `item`.`private`))";
683         else
684                 $sql = "`item`.`uid` = %d";
685
686         $r = q("SELECT `item`.`uri`, `item`.*, `item`.`id` AS `item_id`,
687                         `author-name` AS `name`, `owner-avatar` AS `photo`,
688                         `owner-link` AS `url`, `owner-avatar` AS `thumb`
689                 FROM `item`
690                 WHERE `gcontact-id` = %d AND $sql AND
691                         NOT `deleted` AND NOT `moderated` AND `visible`
692                 ORDER BY `item`.`created` DESC LIMIT %d, %d",
693                 intval($gcontact_id),
694                 intval(local_user()),
695                 intval($a->pager['start']),
696                 intval($a->pager['itemspage'])
697         );
698
699         $o = conversation($a, $r, 'community', false);
700
701         $o .= alt_pager($a, count($r));
702
703         return $o;
704 }
705 /**
706  * @brief Returns posts from a given contact url
707  *
708  * @param App $a argv application class
709  * @param string $contact_url Contact URL
710  *
711  * @return string posts in HTML
712  */
713 function posts_from_contact_url(App $a, $contact_url) {
714
715         require_once 'include/conversation.php';
716
717         // There are no posts with "uid = 0" with connector networks
718         // This speeds up the query a lot
719         $r = q("SELECT `network`, `id` AS `author-id` FROM `contact`
720                 WHERE `contact`.`nurl` = '%s' AND `contact`.`uid` = 0",
721                 dbesc(normalise_link($contact_url)));
722         if (in_array($r[0]["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, ""))) {
723                 $sql = "(`item`.`uid` = 0 OR (`item`.`uid` = %d AND `item`.`private`))";
724         } else {
725                 $sql = "`item`.`uid` = %d";
726         }
727
728         if (!dbm::is_result($r)) {
729                 return '';
730         }
731
732         $author_id = intval($r[0]["author-id"]);
733
734         $r = q(item_query()." AND `item`.`author-id` = %d AND ".$sql.
735                 " ORDER BY `item`.`created` DESC LIMIT %d, %d",
736                 intval($author_id),
737                 intval(local_user()),
738                 intval($a->pager['start']),
739                 intval($a->pager['itemspage'])
740         );
741
742         $o = conversation($a, $r, 'community', false);
743
744         $o .= alt_pager($a, count($r));
745
746         return $o;
747 }
748
749 /**
750  * @brief Returns a formatted location string from the given profile array
751  *
752  * @param array $profile Profile array (Generated from the "profile" table)
753  *
754  * @return string Location string
755  */
756 function formatted_location($profile) {
757         $location = '';
758
759         if($profile['locality'])
760                 $location .= $profile['locality'];
761
762         if($profile['region'] && ($profile['locality'] != $profile['region'])) {
763                 if($location)
764                         $location .= ', ';
765
766                 $location .= $profile['region'];
767         }
768
769         if($profile['country-name']) {
770                 if($location)
771                         $location .= ', ';
772
773                 $location .= $profile['country-name'];
774         }
775
776         return $location;
777 }
778
779 /**
780  * @brief Returns the account type name
781  *
782  * The function can be called with either the user or the contact array
783  *
784  * @param array $contact contact or user array
785  */
786 function account_type($contact) {
787
788         // There are several fields that indicate that the contact or user is a forum
789         // "page-flags" is a field in the user table,
790         // "forum" and "prv" are used in the contact table. They stand for PAGE_COMMUNITY and PAGE_PRVGROUP.
791         // "community" is used in the gcontact table and is true if the contact is PAGE_COMMUNITY or PAGE_PRVGROUP.
792         if((isset($contact['page-flags']) && (intval($contact['page-flags']) == PAGE_COMMUNITY))
793                 || (isset($contact['page-flags']) && (intval($contact['page-flags']) == PAGE_PRVGROUP))
794                 || (isset($contact['forum']) && intval($contact['forum']))
795                 || (isset($contact['prv']) && intval($contact['prv']))
796                 || (isset($contact['community']) && intval($contact['community'])))
797                 $type = ACCOUNT_TYPE_COMMUNITY;
798         else
799                 $type = ACCOUNT_TYPE_PERSON;
800
801         // The "contact-type" (contact table) and "account-type" (user table) are more general then the chaos from above.
802         if (isset($contact["contact-type"]))
803                 $type = $contact["contact-type"];
804         if (isset($contact["account-type"]))
805                 $type = $contact["account-type"];
806
807         switch($type) {
808                 case ACCOUNT_TYPE_ORGANISATION:
809                         $account_type = t("Organisation");
810                         break;
811                 case ACCOUNT_TYPE_NEWS:
812                         $account_type = t('News');
813                         break;
814                 case ACCOUNT_TYPE_COMMUNITY:
815                         $account_type = t("Forum");
816                         break;
817                 default:
818                         $account_type = "";
819                         break;
820         }
821
822         return $account_type;
823 }