]> git.mxchange.org Git - friendica.git/blob - include/Contact.php
f69454e39e782b75ddb88f1fda7e313a2ad57173
[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         dba::delete('contact', array('id' => $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         $r = dba::inArray($s);
214
215         // Fetch the data from the contact table with "uid=0" (which is filled automatically)
216         if (!dbm::is_result($r)) {
217                 $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`,
218                         `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`
219                         FROM `contact` WHERE `nurl` = ? AND `uid` = 0",
220                                 normalise_link($url));
221                 $r = dba::inArray($s);
222         }
223
224         // Fetch the data from the gcontact table
225         if (!dbm::is_result($r)) {
226                 $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`,
227                         `keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, `community` AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self`
228                         FROM `gcontact` WHERE `nurl` = ?",
229                                 normalise_link($url));
230                 $r = dba::inArray($s);
231         }
232
233         if (dbm::is_result($r)) {
234                 // If there is more than one entry we filter out the connector networks
235                 if (count($r) > 1) {
236                         foreach ($r AS $id => $result) {
237                                 if ($result["network"] == NETWORK_STATUSNET) {
238                                         unset($r[$id]);
239                                 }
240                         }
241                 }
242
243                 $profile = array_shift($r);
244
245                 // "bd" always contains the upcoming birthday of a contact.
246                 // "birthday" might contain the birthday including the year of birth.
247                 if ($profile["birthday"] > '0001-01-01') {
248                         $bd_timestamp = strtotime($profile["birthday"]);
249                         $month = date("m", $bd_timestamp);
250                         $day = date("d", $bd_timestamp);
251
252                         $current_timestamp = time();
253                         $current_year = date("Y", $current_timestamp);
254                         $current_month = date("m", $current_timestamp);
255                         $current_day = date("d", $current_timestamp);
256
257                         $profile["bd"] = $current_year."-".$month."-".$day;
258                         $current = $current_year."-".$current_month."-".$current_day;
259
260                         if ($profile["bd"] < $current) {
261                                 $profile["bd"] = (++$current_year)."-".$month."-".$day;
262                         }
263                 } else {
264                         $profile["bd"] = '0001-01-01';
265                 }
266         } else {
267                 $profile = $default;
268         }
269
270         if (($profile["photo"] == "") && isset($default["photo"])) {
271                 $profile["photo"] = $default["photo"];
272         }
273
274         if (($profile["name"] == "") && isset($default["name"])) {
275                 $profile["name"] = $default["name"];
276         }
277
278         if (($profile["network"] == "") && isset($default["network"])) {
279                 $profile["network"] = $default["network"];
280         }
281
282         if (($profile["thumb"] == "") && isset($profile["photo"])) {
283                 $profile["thumb"] = $profile["photo"];
284         }
285
286         if (($profile["micro"] == "") && isset($profile["thumb"])) {
287                 $profile["micro"] = $profile["thumb"];
288         }
289
290         if ((($profile["addr"] == "") || ($profile["name"] == "")) && ($profile["gid"] != 0) &&
291                 in_array($profile["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS))) {
292                 proc_run(PRIORITY_LOW, "include/update_gcontact.php", $profile["gid"]);
293         }
294
295         // Show contact details of Diaspora contacts only if connected
296         if (($profile["cid"] == 0) && ($profile["network"] == NETWORK_DIASPORA)) {
297                 $profile["location"] = "";
298                 $profile["about"] = "";
299                 $profile["gender"] = "";
300                 $profile["birthday"] = '0001-01-01';
301         }
302
303         $cache[$url][$uid] = $profile;
304
305         return $profile;
306 }
307
308 /**
309  * @brief Get contact data for a given address
310  *
311  * The function looks at several places (contact table and gcontact table) for the contact
312  *
313  * @param string $addr The profile link
314  * @param int $uid User id
315  *
316  * @return array Contact data
317  */
318 function get_contact_details_by_addr($addr, $uid = -1) {
319         static $cache = array();
320
321         if ($addr == '') {
322                 return array();
323         }
324
325         if ($uid == -1) {
326                 $uid = local_user();
327         }
328
329         // Fetch contact data from the contact table for the given user
330         $r = q("SELECT `id`, `id` AS `cid`, 0 AS `gid`, 0 AS `zid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
331                         `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`
332                 FROM `contact` WHERE `addr` = '%s' AND `uid` = %d",
333                         dbesc($addr), intval($uid));
334
335         // Fetch the data from the contact table with "uid=0" (which is filled automatically)
336         if (!dbm::is_result($r))
337                 $r = q("SELECT `id`, 0 AS `cid`, `id` AS `zid`, 0 AS `gid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
338                         `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`
339                         FROM `contact` WHERE `addr` = '%s' AND `uid` = 0",
340                                 dbesc($addr));
341
342         // Fetch the data from the gcontact table
343         if (!dbm::is_result($r))
344                 $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`,
345                         `keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, `community` AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self`
346                         FROM `gcontact` WHERE `addr` = '%s'",
347                                 dbesc($addr));
348
349         if (!dbm::is_result($r)) {
350                 $data = Probe::uri($addr);
351
352                 $profile = get_contact_details_by_url($data['url'], $uid);
353         } else {
354                 $profile = $r[0];
355         }
356
357         return $profile;
358 }
359
360 if (! function_exists('contact_photo_menu')) {
361 function contact_photo_menu($contact, $uid = 0)
362 {
363         $a = get_app();
364
365         $contact_url = '';
366         $pm_url = '';
367         $status_link = '';
368         $photos_link = '';
369         $posts_link = '';
370         $contact_drop_link = '';
371         $poke_link = '';
372
373         if ($uid == 0) {
374                 $uid = local_user();
375         }
376
377         if ($contact['uid'] != $uid) {
378                 if ($uid == 0) {
379                         $profile_link = zrl($contact['url']);
380                         $menu = Array('profile' => array(t('View Profile'), $profile_link, true));
381
382                         return $menu;
383                 }
384
385                 $r = q("SELECT * FROM `contact` WHERE `nurl` = '%s' AND `network` = '%s' AND `uid` = %d",
386                         dbesc($contact['nurl']), dbesc($contact['network']), intval($uid));
387                 if ($r) {
388                         return contact_photo_menu($r[0], $uid);
389                 } else {
390                         $profile_link = zrl($contact['url']);
391                         $connlnk = 'follow/?url='.$contact['url'];
392                         $menu = array(
393                                 'profile' => array(t('View Profile'), $profile_link, true),
394                                 'follow' => array(t('Connect/Follow'), $connlnk, true)
395                         );
396
397                         return $menu;
398                 }
399         }
400
401         $sparkle = false;
402         if ($contact['network'] === NETWORK_DFRN) {
403                 $sparkle = true;
404                 $profile_link = App::get_baseurl() . '/redir/' . $contact['id'];
405         } else {
406                 $profile_link = $contact['url'];
407         }
408
409         if ($profile_link === 'mailbox') {
410                 $profile_link = '';
411         }
412
413         if ($sparkle) {
414                 $status_link = $profile_link . '?url=status';
415                 $photos_link = $profile_link . '?url=photos';
416                 $profile_link = $profile_link . '?url=profile';
417         }
418
419         if (in_array($contact['network'], array(NETWORK_DFRN, NETWORK_DIASPORA))) {
420                 $pm_url = App::get_baseurl() . '/message/new/' . $contact['id'];
421         }
422
423         if ($contact['network'] == NETWORK_DFRN) {
424                 $poke_link = App::get_baseurl() . '/poke/?f=&c=' . $contact['id'];
425         }
426
427         $contact_url = App::get_baseurl() . '/contacts/' . $contact['id'];
428
429         $posts_link = App::get_baseurl() . '/contacts/' . $contact['id'] . '/posts';
430         $contact_drop_link = App::get_baseurl() . '/contacts/' . $contact['id'] . '/drop?confirm=1';
431
432         /**
433          * menu array:
434          * "name" => [ "Label", "link", (bool)Should the link opened in a new tab? ]
435          */
436         $menu = array(
437                 'status' => array(t("View Status"), $status_link, true),
438                 'profile' => array(t("View Profile"), $profile_link, true),
439                 'photos' => array(t("View Photos"), $photos_link, true),
440                 'network' => array(t("Network Posts"), $posts_link, false),
441                 'edit' => array(t("View Contact"), $contact_url, false),
442                 'drop' => array(t("Drop Contact"), $contact_drop_link, false),
443                 'pm' => array(t("Send PM"), $pm_url, false),
444                 'poke' => array(t("Poke"), $poke_link, false),
445         );
446
447
448         $args = array('contact' => $contact, 'menu' => &$menu);
449
450         call_hooks('contact_photo_menu', $args);
451
452         $menucondensed = array();
453
454         foreach ($menu AS $menuname => $menuitem) {
455                 if ($menuitem[1] != '') {
456                         $menucondensed[$menuname] = $menuitem;
457                 }
458         }
459
460         return $menucondensed;
461 }}
462
463
464 function random_profile() {
465         $r = q("SELECT `url` FROM `gcontact` WHERE `network` = '%s'
466                                 AND `last_contact` >= `last_failure`
467                                 AND `updated` > UTC_TIMESTAMP - INTERVAL 1 MONTH
468                         ORDER BY rand() LIMIT 1",
469                 dbesc(NETWORK_DFRN));
470
471         if (dbm::is_result($r))
472                 return dirname($r[0]['url']);
473         return '';
474 }
475
476
477 function contacts_not_grouped($uid,$start = 0,$count = 0) {
478
479         if(! $count) {
480                 $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) ",
481                         intval($uid),
482                         intval($uid)
483                 );
484
485                 return $r;
486
487
488         }
489
490         $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",
491                 intval($uid),
492                 intval($uid),
493                 intval($start),
494                 intval($count)
495         );
496
497         return $r;
498 }
499
500 /**
501  * @brief Fetch the contact id for a given url and user
502  *
503  * First lookup in the contact table to find a record matching either `url`, `nurl`,
504  * `addr` or `alias`.
505  *
506  * If there's no record and we aren't looking for a public contact, we quit.
507  * If there's one, we check that it isn't time to update the picture else we
508  * directly return the found contact id.
509  *
510  * Second, we probe the provided $url wether it's http://server.tld/profile or
511  * nick@server.tld. We quit if we can't get any info back.
512  *
513  * Third, we create the contact record if it doesn't exist
514  *
515  * Fourth, we update the existing record with the new data (avatar, alias, nick)
516  * if there's any updates
517  *
518  * @param string $url Contact URL
519  * @param integer $uid The user id for the contact (0 = public contact)
520  * @param boolean $no_update Don't update the contact
521  *
522  * @return integer Contact ID
523  */
524 function get_contact($url, $uid = 0, $no_update = false) {
525         logger("Get contact data for url ".$url." and user ".$uid." - ".App::callstack(), LOGGER_DEBUG);
526
527         $data = array();
528         $contact_id = 0;
529
530         if ($url == '') {
531                 return 0;
532         }
533
534         // We first try the nurl (http://server.tld/nick), most common case
535         $contact = dba::select('contact', array('id', 'avatar-date'), array('nurl' => normalise_link($url), 'uid' => $uid), array('limit' => 1));
536
537         // Then the addr (nick@server.tld)
538         if (!dbm::is_result($contact)) {
539                 $contact = dba::select('contact', array('id', 'avatar-date'), array('addr' => $url, 'uid' => $uid), array('limit' => 1));
540         }
541
542         // Then the alias (which could be anything)
543         if (!dbm::is_result($contact)) {
544                 $r = dba::p("SELECT `id`, `avatar-date` FROM `contact` WHERE `alias` IN (?, ?) AND `uid` = ? LIMIT 1",
545                                 $url, normalise_link($url), $uid);
546                 $contact = dba::fetch($r);
547                 dba::close($r);
548         }
549
550         if (dbm::is_result($contact)) {
551                 $contact_id = $contact["id"];
552
553                 // Update the contact every 7 days
554                 $update_contact = ($contact['avatar-date'] < datetime_convert('','','now -7 days'));
555
556                 if (!$update_contact || $no_update) {
557                         return $contact_id;
558                 }
559         } elseif ($uid != 0) {
560                 // Non-existing user-specific contact, exiting
561                 return 0;
562         }
563
564         $data = Probe::uri($url);
565
566         // Last try in gcontact for unsupported networks
567         if (!in_array($data["network"], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_DIASPORA, NETWORK_PUMPIO))) {
568                 if ($uid != 0) {
569                         return 0;
570                 }
571
572                 // Get data from the gcontact table
573                 $gcontacts = dba::select('gcontact', array('name', 'nick', 'url', 'photo', 'addr', 'alias', 'network'),
574                                                 array('nurl' => normalise_link($url)), array('limit' => 1));
575                 if (!dbm::is_result($gcontacts)) {
576                         return 0;
577                 }
578
579                 $data = array_merge($data, $gcontacts);
580         }
581
582         $url = $data["url"];
583         if (!$contact_id) {
584                 dba::insert('contact', array('uid' => $uid, 'created' => datetime_convert(), 'url' => $data["url"],
585                                         'nurl' => normalise_link($data["url"]), 'addr' => $data["addr"],
586                                         'alias' => $data["alias"], 'notify' => $data["notify"], 'poll' => $data["poll"],
587                                         'name' => $data["name"], 'nick' => $data["nick"], 'photo' => $data["photo"],
588                                         'keywords' => $data["keywords"], 'location' => $data["location"], 'about' => $data["about"],
589                                         'network' => $data["network"], 'pubkey' => $data["pubkey"],
590                                         'rel' => CONTACT_IS_SHARING, 'priority' => $data["priority"],
591                                         'batch' => $data["batch"], 'request' => $data["request"],
592                                         'confirm' => $data["confirm"], 'poco' => $data["poco"],
593                                         'name-date' => datetime_convert(), 'uri-date' => datetime_convert(),
594                                         'avatar-date' => datetime_convert(), 'writable' => 1, 'blocked' => 0,
595                                         'readonly' => 0, 'pending' => 0));
596
597                 $contacts = q("SELECT `id` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d ORDER BY `id` LIMIT 2",
598                                 dbesc(normalise_link($data["url"])),
599                                 intval($uid));
600                 if (!dbm::is_result($contacts)) {
601                         return 0;
602                 }
603
604                 $contact_id = $contacts[0]["id"];
605
606                 // Update the newly created contact from data in the gcontact table
607                 $gcontact = dba::select('gcontact', array('location', 'about', 'keywords', 'gender'),
608                                         array('nurl' => normalise_link($data["url"])), array('limit' => 1));
609                 if (dbm::is_result($gcontact)) {
610                         // Only use the information when the probing hadn't fetched these values
611                         if ($data['keywords'] != '') {
612                                 unset($gcontact['keywords']);
613                         }
614                         if ($data['location'] != '') {
615                                 unset($gcontact['location']);
616                         }
617                         if ($data['about'] != '') {
618                                 unset($gcontact['about']);
619                         }
620                         dba::update('contact', $gcontact, array('id' => $contact_id));
621                 }
622
623                 if (count($contacts) > 1 && $uid == 0 && $contact_id != 0 && $data["url"] != "") {
624                         dba::delete('contact', array("`nurl` = ? AND `uid` = 0 AND `id` != ? AND NOT `self`",
625                                 normalise_link($data["url"]), $contact_id));
626                 }
627         }
628
629         require_once "Photo.php";
630
631         update_contact_avatar($data["photo"], $uid, $contact_id);
632
633         $contact = dba::select('contact', array('addr', 'alias', 'name', 'nick', 'keywords', 'location', 'about', 'avatar-date'),
634                                 array('id' => $contact_id), array('limit' => 1));
635
636         // This condition should always be true
637         if (!dbm::is_result($contact)) {
638                 return $contact_id;
639         }
640
641         $updated = array('addr' => $data['addr'],
642                         'alias' => $data['alias'],
643                         'name' => $data['name'],
644                         'nick' => $data['nick']);
645
646         if ($data['keywords'] != '') {
647                 $updated['keywords'] = $data['keywords'];
648         }
649         if ($data['location'] != '') {
650                 $updated['location'] = $data['location'];
651         }
652         if ($data['about'] != '') {
653                 $updated['about'] = $data['about'];
654         }
655
656         if (($data["addr"] != $contact["addr"]) || ($data["alias"] != $contact["alias"])) {
657                 $updated['uri-date'] = datetime_convert();
658         }
659         if (($data["name"] != $contact["name"]) || ($data["nick"] != $contact["nick"])) {
660                 $updated['name-date'] = datetime_convert();
661         }
662
663         $updated['avatar-date'] = datetime_convert();
664
665         dba::update('contact', $updated, array('id' => $contact_id), $contact);
666
667         return $contact_id;
668 }
669
670 /**
671  * @brief Returns posts from a given gcontact
672  *
673  * @param App $a argv application class
674  * @param int $gcontact_id Global contact
675  *
676  * @return string posts in HTML
677  */
678 function posts_from_gcontact(App $a, $gcontact_id) {
679
680         require_once 'include/conversation.php';
681
682         // There are no posts with "uid = 0" with connector networks
683         // This speeds up the query a lot
684         $r = q("SELECT `network` FROM `gcontact` WHERE `id` = %d", dbesc($gcontact_id));
685         if (in_array($r[0]["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, "")))
686                 $sql = "(`item`.`uid` = 0 OR  (`item`.`uid` = %d AND `item`.`private`))";
687         else
688                 $sql = "`item`.`uid` = %d";
689
690         $r = q("SELECT `item`.`uri`, `item`.*, `item`.`id` AS `item_id`,
691                         `author-name` AS `name`, `owner-avatar` AS `photo`,
692                         `owner-link` AS `url`, `owner-avatar` AS `thumb`
693                 FROM `item`
694                 WHERE `gcontact-id` = %d AND $sql AND
695                         NOT `deleted` AND NOT `moderated` AND `visible`
696                 ORDER BY `item`.`created` DESC LIMIT %d, %d",
697                 intval($gcontact_id),
698                 intval(local_user()),
699                 intval($a->pager['start']),
700                 intval($a->pager['itemspage'])
701         );
702
703         $o = conversation($a, $r, 'community', false);
704
705         $o .= alt_pager($a, count($r));
706
707         return $o;
708 }
709 /**
710  * @brief Returns posts from a given contact url
711  *
712  * @param App $a argv application class
713  * @param string $contact_url Contact URL
714  *
715  * @return string posts in HTML
716  */
717 function posts_from_contact_url(App $a, $contact_url) {
718
719         require_once 'include/conversation.php';
720
721         // There are no posts with "uid = 0" with connector networks
722         // This speeds up the query a lot
723         $r = q("SELECT `network`, `id` AS `author-id` FROM `contact`
724                 WHERE `contact`.`nurl` = '%s' AND `contact`.`uid` = 0",
725                 dbesc(normalise_link($contact_url)));
726         if (in_array($r[0]["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, ""))) {
727                 $sql = "(`item`.`uid` = 0 OR (`item`.`uid` = %d AND `item`.`private`))";
728         } else {
729                 $sql = "`item`.`uid` = %d";
730         }
731
732         if (!dbm::is_result($r)) {
733                 return '';
734         }
735
736         $author_id = intval($r[0]["author-id"]);
737
738         $r = q(item_query()." AND `item`.`author-id` = %d AND ".$sql.
739                 " ORDER BY `item`.`created` DESC LIMIT %d, %d",
740                 intval($author_id),
741                 intval(local_user()),
742                 intval($a->pager['start']),
743                 intval($a->pager['itemspage'])
744         );
745
746         $o = conversation($a, $r, 'community', false);
747
748         $o .= alt_pager($a, count($r));
749
750         return $o;
751 }
752
753 /**
754  * @brief Returns a formatted location string from the given profile array
755  *
756  * @param array $profile Profile array (Generated from the "profile" table)
757  *
758  * @return string Location string
759  */
760 function formatted_location($profile) {
761         $location = '';
762
763         if($profile['locality'])
764                 $location .= $profile['locality'];
765
766         if($profile['region'] && ($profile['locality'] != $profile['region'])) {
767                 if($location)
768                         $location .= ', ';
769
770                 $location .= $profile['region'];
771         }
772
773         if($profile['country-name']) {
774                 if($location)
775                         $location .= ', ';
776
777                 $location .= $profile['country-name'];
778         }
779
780         return $location;
781 }
782
783 /**
784  * @brief Returns the account type name
785  *
786  * The function can be called with either the user or the contact array
787  *
788  * @param array $contact contact or user array
789  */
790 function account_type($contact) {
791
792         // There are several fields that indicate that the contact or user is a forum
793         // "page-flags" is a field in the user table,
794         // "forum" and "prv" are used in the contact table. They stand for PAGE_COMMUNITY and PAGE_PRVGROUP.
795         // "community" is used in the gcontact table and is true if the contact is PAGE_COMMUNITY or PAGE_PRVGROUP.
796         if((isset($contact['page-flags']) && (intval($contact['page-flags']) == PAGE_COMMUNITY))
797                 || (isset($contact['page-flags']) && (intval($contact['page-flags']) == PAGE_PRVGROUP))
798                 || (isset($contact['forum']) && intval($contact['forum']))
799                 || (isset($contact['prv']) && intval($contact['prv']))
800                 || (isset($contact['community']) && intval($contact['community'])))
801                 $type = ACCOUNT_TYPE_COMMUNITY;
802         else
803                 $type = ACCOUNT_TYPE_PERSON;
804
805         // The "contact-type" (contact table) and "account-type" (user table) are more general then the chaos from above.
806         if (isset($contact["contact-type"]))
807                 $type = $contact["contact-type"];
808         if (isset($contact["account-type"]))
809                 $type = $contact["account-type"];
810
811         switch($type) {
812                 case ACCOUNT_TYPE_ORGANISATION:
813                         $account_type = t("Organisation");
814                         break;
815                 case ACCOUNT_TYPE_NEWS:
816                         $account_type = t('News');
817                         break;
818                 case ACCOUNT_TYPE_COMMUNITY:
819                         $account_type = t("Forum");
820                         break;
821                 default:
822                         $account_type = "";
823                         break;
824         }
825
826         return $account_type;
827 }