]> git.mxchange.org Git - friendica.git/blob - mod/contacts.php
Remove unused global cache constants
[friendica.git] / mod / contacts.php
1 <?php
2 /**
3  * @file mod/contacts.php
4  */
5
6 use Friendica\App;
7 use Friendica\Content\ContactSelector;
8 use Friendica\Content\Nav;
9 use Friendica\Content\Text\BBCode;
10 use Friendica\Content\Widget;
11 use Friendica\Core\Addon;
12 use Friendica\Core\L10n;
13 use Friendica\Core\System;
14 use Friendica\Core\Worker;
15 use Friendica\Database\DBM;
16 use Friendica\Model\Contact;
17 use Friendica\Model\GContact;
18 use Friendica\Model\Group;
19 use Friendica\Model\Profile;
20 use Friendica\Network\Probe;
21 use Friendica\Util\DateTimeFormat;
22
23 require_once 'mod/proxy.php';
24
25 function contacts_init(App $a)
26 {
27         if (!local_user()) {
28                 return;
29         }
30
31         $nets = defaults($_GET, 'nets', '');
32         if ($nets == "all") {
33                 $nets = "";
34         }
35
36         if (!x($a->page, 'aside')) {
37                 $a->page['aside'] = '';
38         }
39
40         $contact_id = null;
41         $contact = null;
42         if ((($a->argc == 2) && intval($a->argv[1])) || (($a->argc == 3) && intval($a->argv[1]) && ($a->argv[2] == "posts"))) {
43                 $contact_id = intval($a->argv[1]);
44                 $contact = dba::selectFirst('contact', [], ['id' => $contact_id, 'uid' => local_user()]);
45         }
46
47         if (DBM::is_result($contact)) {
48                 $a->data['contact'] = $contact;
49
50                 if (($a->data['contact']['network'] != "") && ($a->data['contact']['network'] != NETWORK_DFRN)) {
51                         $networkname = format_network_name($a->data['contact']['network'], $a->data['contact']['url']);
52                 } else {
53                         $networkname = '';
54                 }
55
56                 /// @TODO Add nice spaces
57                 $vcard_widget = replace_macros(get_markup_template("vcard-widget.tpl"), [
58                         '$name' => htmlentities($a->data['contact']['name']),
59                         '$photo' => $a->data['contact']['photo'],
60                         '$url' => ($a->data['contact']['network'] == NETWORK_DFRN) ? "redir/" . $a->data['contact']['id'] : $a->data['contact']['url'],
61                         '$addr' => (($a->data['contact']['addr'] != "") ? ($a->data['contact']['addr']) : ""),
62                         '$network_name' => $networkname,
63                         '$network' => L10n::t('Network:'),
64                         '$account_type' => Contact::getAccountType($a->data['contact'])
65                 ]);
66
67                 $findpeople_widget = '';
68                 $follow_widget = '';
69                 $networks_widget = '';
70         } else {
71                 $vcard_widget = '';
72                 $networks_widget = Widget::networks('contacts', $nets);
73                 if (isset($_GET['add'])) {
74                         $follow_widget = Widget::follow($_GET['add']);
75                 } else {
76                         $follow_widget = Widget::follow();
77                 }
78
79                 $findpeople_widget = Widget::findPeople();
80         }
81
82         $groups_widget = Group::sidebarWidget('contacts', 'group', 'full', 0, $contact_id);
83
84         $a->page['aside'] .= replace_macros(get_markup_template("contacts-widget-sidebar.tpl"), [
85                 '$vcard_widget' => $vcard_widget,
86                 '$findpeople_widget' => $findpeople_widget,
87                 '$follow_widget' => $follow_widget,
88                 '$groups_widget' => $groups_widget,
89                 '$networks_widget' => $networks_widget
90         ]);
91
92         $base = System::baseUrl();
93         $tpl = get_markup_template("contacts-head.tpl");
94         $a->page['htmlhead'] .= replace_macros($tpl, [
95                 '$baseurl' => System::baseUrl(true),
96                 '$base' => $base
97         ]);
98
99         $tpl = get_markup_template("contacts-end.tpl");
100         $a->page['end'] .= replace_macros($tpl, [
101                 '$baseurl' => System::baseUrl(true),
102                 '$base' => $base
103         ]);
104 }
105
106 function contacts_batch_actions(App $a)
107 {
108         $contacts_id = $_POST['contact_batch'];
109         if (!is_array($contacts_id)) {
110                 return;
111         }
112
113         $orig_records = q("SELECT * FROM `contact` WHERE `id` IN (%s) AND `uid` = %d AND `self` = 0",
114                 implode(",", $contacts_id),
115                 intval(local_user())
116         );
117
118         $count_actions = 0;
119         foreach ($orig_records as $orig_record) {
120                 $contact_id = $orig_record['id'];
121                 if (x($_POST, 'contacts_batch_update')) {
122                         _contact_update($contact_id);
123                         $count_actions++;
124                 }
125                 if (x($_POST, 'contacts_batch_block')) {
126                         $r = _contact_block($contact_id, $orig_record);
127                         if ($r) {
128                                 $count_actions++;
129                         }
130                 }
131                 if (x($_POST, 'contacts_batch_ignore')) {
132                         $r = _contact_ignore($contact_id, $orig_record);
133                         if ($r) {
134                                 $count_actions++;
135                         }
136                 }
137                 if (x($_POST, 'contacts_batch_archive')) {
138                         $r = _contact_archive($contact_id, $orig_record);
139                         if ($r) {
140                                 $count_actions++;
141                         }
142                 }
143                 if (x($_POST, 'contacts_batch_drop')) {
144                         _contact_drop($orig_record);
145                         $count_actions++;
146                 }
147         }
148         if ($count_actions > 0) {
149                 info(L10n::tt("%d contact edited.", "%d contacts edited.", $count_actions));
150         }
151
152         if (x($_SESSION, 'return_url')) {
153                 goaway('' . $_SESSION['return_url']);
154         } else {
155                 goaway('contacts');
156         }
157 }
158
159 function contacts_post(App $a)
160 {
161         if (!local_user()) {
162                 return;
163         }
164
165         if ($a->argv[1] === "batch") {
166                 contacts_batch_actions($a);
167                 return;
168         }
169
170         $contact_id = intval($a->argv[1]);
171         if (!$contact_id) {
172                 return;
173         }
174
175         if (!dba::exists('contact', ['id' => $contact_id, 'uid' => local_user()])) {
176                 notice(L10n::t('Could not access contact record.') . EOL);
177                 goaway('contacts');
178                 return; // NOTREACHED
179         }
180
181         Addon::callHooks('contact_edit_post', $_POST);
182
183         $profile_id = intval($_POST['profile-assign']);
184         if ($profile_id) {
185                 if (!dba::exists('profile', ['id' => $profile_id, 'uid' => local_user()])) {
186                         notice(L10n::t('Could not locate selected profile.') . EOL);
187                         return;
188                 }
189         }
190
191         $hidden = intval($_POST['hidden']);
192
193         $notify = intval($_POST['notify']);
194
195         $fetch_further_information = intval($_POST['fetch_further_information']);
196
197         $ffi_keyword_blacklist = escape_tags(trim($_POST['ffi_keyword_blacklist']));
198
199         $priority = intval($_POST['poll']);
200         if ($priority > 5 || $priority < 0) {
201                 $priority = 0;
202         }
203
204         $info = escape_tags(trim($_POST['info']));
205
206         $r = q("UPDATE `contact` SET `profile-id` = %d, `priority` = %d , `info` = '%s',
207                 `hidden` = %d, `notify_new_posts` = %d, `fetch_further_information` = %d,
208                 `ffi_keyword_blacklist` = '%s' WHERE `id` = %d AND `uid` = %d",
209                 intval($profile_id),
210                 intval($priority),
211                 dbesc($info),
212                 intval($hidden),
213                 intval($notify),
214                 intval($fetch_further_information),
215                 dbesc($ffi_keyword_blacklist),
216                 intval($contact_id),
217                 intval(local_user())
218         );
219         if (DBM::is_result($r)) {
220                 info(L10n::t('Contact updated.') . EOL);
221         } else {
222                 notice(L10n::t('Failed to update contact record.') . EOL);
223         }
224
225         $contact = dba::selectFirst('contact', [], ['id' => $contact_id, 'uid' => local_user()]);
226         if (DBM::is_result($contact)) {
227                 $a->data['contact'] = $contact;
228         }
229
230         return;
231 }
232
233 /* contact actions */
234
235 function _contact_update($contact_id)
236 {
237         $contact = dba::selectFirst('contact', ['uid', 'url', 'network'], ['id' => $contact_id, 'uid' => local_user()]);
238         if (!DBM::is_result($contact)) {
239                 return;
240         }
241
242         $uid = $contact["uid"];
243
244         if ($contact["network"] == NETWORK_OSTATUS) {
245                 $result = Contact::createFromProbe($uid, $contact["url"], false, $contact["network"]);
246
247                 if ($result['success']) {
248                         q("UPDATE `contact` SET `subhub` = 1 WHERE `id` = %d", intval($contact_id));
249                 }
250         } else {
251                 // pull feed and consume it, which should subscribe to the hub.
252                 Worker::add(PRIORITY_HIGH, "OnePoll", $contact_id, "force");
253         }
254 }
255
256 function _contact_update_profile($contact_id)
257 {
258         $contact = dba::selectFirst('contact', ['uid', 'url', 'network'], ['id' => $contact_id, 'uid' => local_user()]);
259         if (!DBM::is_result($contact)) {
260                 return;
261         }
262
263         $uid = $contact["uid"];
264
265         $data = Probe::uri($contact["url"], "", 0, false);
266
267         // "Feed" or "Unknown" is mostly a sign of communication problems
268         if ((in_array($data["network"], [NETWORK_FEED, NETWORK_PHANTOM])) && ($data["network"] != $contact["network"])) {
269                 return;
270         }
271
272         $updatefields = ["name", "nick", "url", "addr", "batch", "notify", "poll", "request", "confirm",
273                 "poco", "network", "alias"];
274         $update = [];
275
276         if ($data["network"] == NETWORK_OSTATUS) {
277                 $result = Contact::createFromProbe($uid, $data["url"], false);
278
279                 if ($result['success']) {
280                         $update["subhub"] = true;
281                 }
282         }
283
284         foreach ($updatefields AS $field) {
285                 if (isset($data[$field]) && ($data[$field] != "")) {
286                         $update[$field] = $data[$field];
287                 }
288         }
289
290         $update["nurl"] = normalise_link($data["url"]);
291
292         $query = "";
293
294         if (isset($data["priority"]) && ($data["priority"] != 0)) {
295                 $query = "`priority` = " . intval($data["priority"]);
296         }
297
298         foreach ($update AS $key => $value) {
299                 if ($query != "") {
300                         $query .= ", ";
301                 }
302
303                 $query .= "`" . $key . "` = '" . dbesc($value) . "'";
304         }
305
306         if ($query == "") {
307                 return;
308         }
309
310         $r = q("UPDATE `contact` SET $query WHERE `id` = %d AND `uid` = %d",
311                 intval($contact_id),
312                 intval(local_user())
313         );
314
315         // Update the entry in the contact table
316         Contact::updateAvatar($data['photo'], local_user(), $contact_id, true);
317
318         // Update the entry in the gcontact table
319         GContact::updateFromProbe($data["url"]);
320 }
321
322 function _contact_block($contact_id, $orig_record)
323 {
324         $blocked = (($orig_record['blocked']) ? 0 : 1);
325         $r = q("UPDATE `contact` SET `blocked` = %d WHERE `id` = %d AND `uid` = %d",
326                 intval($blocked),
327                 intval($contact_id),
328                 intval(local_user())
329         );
330         return DBM::is_result($r);
331 }
332
333 function _contact_ignore($contact_id, $orig_record)
334 {
335         $readonly = (($orig_record['readonly']) ? 0 : 1);
336         $r = q("UPDATE `contact` SET `readonly` = %d WHERE `id` = %d AND `uid` = %d",
337                 intval($readonly),
338                 intval($contact_id),
339                 intval(local_user())
340         );
341         return DBM::is_result($r);
342 }
343
344 function _contact_archive($contact_id, $orig_record)
345 {
346         $archived = (($orig_record['archive']) ? 0 : 1);
347         $r = q("UPDATE `contact` SET `archive` = %d WHERE `id` = %d AND `uid` = %d",
348                 intval($archived),
349                 intval($contact_id),
350                 intval(local_user())
351         );
352         return DBM::is_result($r);
353 }
354
355 function _contact_drop($orig_record)
356 {
357         $a = get_app();
358
359         $r = q("SELECT `contact`.*, `user`.* FROM `contact` INNER JOIN `user` ON `contact`.`uid` = `user`.`uid`
360                 WHERE `user`.`uid` = %d AND `contact`.`self` LIMIT 1",
361                 intval($a->user['uid'])
362         );
363         if (!DBM::is_result($r)) {
364                 return;
365         }
366
367         Contact::terminateFriendship($r[0], $orig_record);
368         Contact::remove($orig_record['id']);
369 }
370
371 function contacts_content(App $a)
372 {
373         $sort_type = 0;
374         $o = '';
375         Nav::setSelected('contacts');
376
377         if (!local_user()) {
378                 notice(L10n::t('Permission denied.') . EOL);
379                 return;
380         }
381
382         if ($a->argc == 3) {
383                 $contact_id = intval($a->argv[1]);
384                 if (!$contact_id) {
385                         return;
386                 }
387
388                 $cmd = $a->argv[2];
389
390                 $orig_record = dba::selectFirst('contact', [], ['id' => $contact_id, 'uid' => local_user(), 'self' => false]);
391                 if (!DBM::is_result($orig_record)) {
392                         notice(L10n::t('Could not access contact record.') . EOL);
393                         goaway('contacts');
394                         return; // NOTREACHED
395                 }
396
397                 if ($cmd === 'update') {
398                         _contact_update($contact_id);
399                         goaway('contacts/' . $contact_id);
400                         // NOTREACHED
401                 }
402
403                 if ($cmd === 'updateprofile') {
404                         _contact_update_profile($contact_id);
405                         goaway('crepair/' . $contact_id);
406                         // NOTREACHED
407                 }
408
409                 if ($cmd === 'block') {
410                         $r = _contact_block($contact_id, $orig_record);
411                         if ($r) {
412                                 $blocked = (($orig_record['blocked']) ? 0 : 1);
413                                 info((($blocked) ? L10n::t('Contact has been blocked') : L10n::t('Contact has been unblocked')) . EOL);
414                         }
415
416                         goaway('contacts/' . $contact_id);
417                         return; // NOTREACHED
418                 }
419
420                 if ($cmd === 'ignore') {
421                         $r = _contact_ignore($contact_id, $orig_record);
422                         if ($r) {
423                                 $readonly = (($orig_record['readonly']) ? 0 : 1);
424                                 info((($readonly) ? L10n::t('Contact has been ignored') : L10n::t('Contact has been unignored')) . EOL);
425                         }
426
427                         goaway('contacts/' . $contact_id);
428                         return; // NOTREACHED
429                 }
430
431                 if ($cmd === 'archive') {
432                         $r = _contact_archive($contact_id, $orig_record);
433                         if ($r) {
434                                 $archived = (($orig_record['archive']) ? 0 : 1);
435                                 info((($archived) ? L10n::t('Contact has been archived') : L10n::t('Contact has been unarchived')) . EOL);
436                         }
437
438                         goaway('contacts/' . $contact_id);
439                         return; // NOTREACHED
440                 }
441
442                 if ($cmd === 'drop') {
443                         // Check if we should do HTML-based delete confirmation
444                         if (x($_REQUEST, 'confirm')) {
445                                 // <form> can't take arguments in its "action" parameter
446                                 // so add any arguments as hidden inputs
447                                 $query = explode_querystring($a->query_string);
448                                 $inputs = [];
449                                 foreach ($query['args'] as $arg) {
450                                         if (strpos($arg, 'confirm=') === false) {
451                                                 $arg_parts = explode('=', $arg);
452                                                 $inputs[] = ['name' => $arg_parts[0], 'value' => $arg_parts[1]];
453                                         }
454                                 }
455
456                                 $a->page['aside'] = '';
457
458                                 return replace_macros(get_markup_template('contact_drop_confirm.tpl'), [
459                                         '$header' => L10n::t('Drop contact'),
460                                         '$contact' => _contact_detail_for_template($orig_record),
461                                         '$method' => 'get',
462                                         '$message' => L10n::t('Do you really want to delete this contact?'),
463                                         '$extra_inputs' => $inputs,
464                                         '$confirm' => L10n::t('Yes'),
465                                         '$confirm_url' => $query['base'],
466                                         '$confirm_name' => 'confirmed',
467                                         '$cancel' => L10n::t('Cancel'),
468                                 ]);
469                         }
470                         // Now check how the user responded to the confirmation query
471                         if (x($_REQUEST, 'canceled')) {
472                                 if (x($_SESSION, 'return_url')) {
473                                         goaway('' . $_SESSION['return_url']);
474                                 } else {
475                                         goaway('contacts');
476                                 }
477                         }
478
479                         _contact_drop($orig_record);
480                         info(L10n::t('Contact has been removed.') . EOL);
481                         if (x($_SESSION, 'return_url')) {
482                                 goaway('' . $_SESSION['return_url']);
483                         } else {
484                                 goaway('contacts');
485                         }
486                         return; // NOTREACHED
487                 }
488                 if ($cmd === 'posts') {
489                         return contact_posts($a, $contact_id);
490                 }
491         }
492
493         $_SESSION['return_url'] = $a->query_string;
494
495         if ((x($a->data, 'contact')) && (is_array($a->data['contact']))) {
496                 $contact_id = $a->data['contact']['id'];
497                 $contact = $a->data['contact'];
498
499                 $a->page['htmlhead'] .= replace_macros(get_markup_template('contact_head.tpl'), [
500                         '$baseurl' => System::baseUrl(true),
501                 ]);
502                 $a->page['end'] .= replace_macros(get_markup_template('contact_end.tpl'), [
503                         '$baseurl' => System::baseUrl(true),
504                 ]);
505
506                 $dir_icon = '';
507                 $relation_text = '';
508                 switch ($contact['rel']) {
509                         case CONTACT_IS_FRIEND:
510                                 $dir_icon = 'images/lrarrow.gif';
511                                 $relation_text = L10n::t('You are mutual friends with %s');
512                                 break;
513                         case CONTACT_IS_FOLLOWER;
514                                 $dir_icon = 'images/larrow.gif';
515                                 $relation_text = L10n::t('You are sharing with %s');
516                                 break;
517                         case CONTACT_IS_SHARING;
518                                 $dir_icon = 'images/rarrow.gif';
519                                 $relation_text = L10n::t('%s is sharing with you');
520                                 break;
521                         default:
522                                 break;
523                 }
524
525                 if (!in_array($contact['network'], [NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_DIASPORA])) {
526                         $relation_text = "";
527                 }
528
529                 $relation_text = sprintf($relation_text, htmlentities($contact['name']));
530
531                 if (($contact['network'] === NETWORK_DFRN) && ($contact['rel'])) {
532                         $url = "redir/{$contact['id']}";
533                         $sparkle = ' class="sparkle" ';
534                 } else {
535                         $url = $contact['url'];
536                         $sparkle = '';
537                 }
538
539                 $insecure = L10n::t('Private communications are not available for this contact.');
540
541                 $last_update = (($contact['last-update'] <= NULL_DATE) ? L10n::t('Never') : DateTimeFormat::local($contact['last-update'], 'D, j M Y, g:i A'));
542
543                 if ($contact['last-update'] > NULL_DATE) {
544                         $last_update .= ' ' . (($contact['last-update'] <= $contact['success_update']) ? L10n::t("\x28Update was successful\x29") : L10n::t("\x28Update was not successful\x29"));
545                 }
546                 $lblsuggest = (($contact['network'] === NETWORK_DFRN) ? L10n::t('Suggest friends') : '');
547
548                 $poll_enabled = in_array($contact['network'], [NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_FEED, NETWORK_MAIL]);
549
550                 $nettype = L10n::t('Network type: %s', ContactSelector::networkToName($contact['network'], $contact["url"]));
551
552                 // tabs
553                 $tab_str = contacts_tab($a, $contact_id, 2);
554
555                 $lost_contact = (($contact['archive'] && $contact['term-date'] > NULL_DATE && $contact['term-date'] < DateTimeFormat::utcNow()) ? L10n::t('Communications lost with this contact!') : '');
556
557                 $fetch_further_information = null;
558                 if ($contact['network'] == NETWORK_FEED) {
559                         $fetch_further_information = [
560                                 'fetch_further_information',
561                                 L10n::t('Fetch further information for feeds'),
562                                 $contact['fetch_further_information'],
563                                 L10n::t("Fetch information like preview pictures, title and teaser from the feed item. You can activate this if the feed doesn't contain much text. Keywords are taken from the meta header in the feed item and are posted as hash tags."),
564                                 ['0' => L10n::t('Disabled'),
565                                         '1' => L10n::t('Fetch information'),
566                                         '3' => L10n::t('Fetch keywords'),
567                                         '2' => L10n::t('Fetch information and keywords')
568                                 ]
569                         ];
570                 }
571
572                 $poll_interval = null;
573                 if (in_array($contact['network'], [NETWORK_FEED, NETWORK_MAIL])) {
574                         $poll_interval = ContactSelector::pollInterval($contact['priority'], (!$poll_enabled));
575                 }
576
577                 $profile_select = null;
578                 if ($contact['network'] == NETWORK_DFRN) {
579                         $profile_select = ContactSelector::profileAssign($contact['profile-id'], (($contact['network'] !== NETWORK_DFRN) ? true : false));
580                 }
581
582                 $follow = '';
583                 $follow_text = '';
584                 if (in_array($contact['network'], [NETWORK_DIASPORA, NETWORK_OSTATUS])) {
585                         if ($contact['rel'] == CONTACT_IS_FOLLOWER) {
586                                 $follow = System::baseUrl(true) . "/follow?url=" . urlencode($contact["url"]);
587                                 $follow_text = L10n::t("Connect/Follow");
588                         } elseif ($contact['rel'] == CONTACT_IS_FRIEND) {
589                                 $follow = System::baseUrl(true) . "/unfollow?url=" . urlencode($contact["url"]);
590                                 $follow_text = L10n::t("Disconnect/Unfollow");
591                         }
592                 }
593
594                 // Load contactact related actions like hide, suggest, delete and others
595                 $contact_actions = contact_actions($contact);
596
597                 $tpl = get_markup_template("contact_edit.tpl");
598                 $o .= replace_macros($tpl, [
599                         '$header' => L10n::t("Contact"),
600                         '$tab_str' => $tab_str,
601                         '$submit' => L10n::t('Submit'),
602                         '$lbl_vis1' => L10n::t('Profile Visibility'),
603                         '$lbl_vis2' => L10n::t('Please choose the profile you would like to display to %s when viewing your profile securely.', $contact['name']),
604                         '$lbl_info1' => L10n::t('Contact Information / Notes'),
605                         '$lbl_info2' => L10n::t('Their personal note'),
606                         '$reason' => trim(notags($contact['reason'])),
607                         '$infedit' => L10n::t('Edit contact notes'),
608                         '$common_link' => 'common/loc/' . local_user() . '/' . $contact['id'],
609                         '$relation_text' => $relation_text,
610                         '$visit' => L10n::t('Visit %s\'s profile [%s]', $contact['name'], $contact['url']),
611                         '$blockunblock' => L10n::t('Block/Unblock contact'),
612                         '$ignorecont' => L10n::t('Ignore contact'),
613                         '$lblcrepair' => L10n::t("Repair URL settings"),
614                         '$lblrecent' => L10n::t('View conversations'),
615                         '$lblsuggest' => $lblsuggest,
616                         '$nettype' => $nettype,
617                         '$poll_interval' => $poll_interval,
618                         '$poll_enabled' => $poll_enabled,
619                         '$lastupdtext' => L10n::t('Last update:'),
620                         '$lost_contact' => $lost_contact,
621                         '$updpub' => L10n::t('Update public posts'),
622                         '$last_update' => $last_update,
623                         '$udnow' => L10n::t('Update now'),
624                         '$follow' => $follow,
625                         '$follow_text' => $follow_text,
626                         '$profile_select' => $profile_select,
627                         '$contact_id' => $contact['id'],
628                         '$block_text' => (($contact['blocked']) ? L10n::t('Unblock') : L10n::t('Block') ),
629                         '$ignore_text' => (($contact['readonly']) ? L10n::t('Unignore') : L10n::t('Ignore') ),
630                         '$insecure' => (($contact['network'] !== NETWORK_DFRN && $contact['network'] !== NETWORK_MAIL && $contact['network'] !== NETWORK_FACEBOOK && $contact['network'] !== NETWORK_DIASPORA) ? $insecure : ''),
631                         '$info' => $contact['info'],
632                         '$cinfo' => ['info', '', $contact['info'], ''],
633                         '$blocked' => (($contact['blocked']) ? L10n::t('Currently blocked') : ''),
634                         '$ignored' => (($contact['readonly']) ? L10n::t('Currently ignored') : ''),
635                         '$archived' => (($contact['archive']) ? L10n::t('Currently archived') : ''),
636                         '$pending' => (($contact['pending']) ? L10n::t('Awaiting connection acknowledge') : ''),
637                         '$hidden' => ['hidden', L10n::t('Hide this contact from others'), ($contact['hidden'] == 1), L10n::t('Replies/likes to your public posts <strong>may</strong> still be visible')],
638                         '$notify' => ['notify', L10n::t('Notification for new posts'), ($contact['notify_new_posts'] == 1), L10n::t('Send a notification of every new post of this contact')],
639                         '$fetch_further_information' => $fetch_further_information,
640                         '$ffi_keyword_blacklist' => $contact['ffi_keyword_blacklist'],
641                         '$ffi_keyword_blacklist' => ['ffi_keyword_blacklist', L10n::t('Blacklisted keywords'), $contact['ffi_keyword_blacklist'], L10n::t('Comma separated list of keywords that should not be converted to hashtags, when "Fetch information and keywords" is selected')],
642                         '$photo' => $contact['photo'],
643                         '$name' => htmlentities($contact['name']),
644                         '$dir_icon' => $dir_icon,
645                         '$sparkle' => $sparkle,
646                         '$url' => $url,
647                         '$profileurllabel' => L10n::t('Profile URL'),
648                         '$profileurl' => $contact['url'],
649                         '$account_type' => Contact::getAccountType($contact),
650                         '$location' => BBCode::convert($contact["location"]),
651                         '$location_label' => L10n::t("Location:"),
652                         '$xmpp' => BBCode::convert($contact["xmpp"]),
653                         '$xmpp_label' => L10n::t("XMPP:"),
654                         '$about' => BBCode::convert($contact["about"], false),
655                         '$about_label' => L10n::t("About:"),
656                         '$keywords' => $contact["keywords"],
657                         '$keywords_label' => L10n::t("Tags:"),
658                         '$contact_action_button' => L10n::t("Actions"),
659                         '$contact_actions' => $contact_actions,
660                         '$contact_status' => L10n::t("Status"),
661                         '$contact_settings_label' => L10n::t('Contact Settings'),
662                         '$contact_profile_label' => L10n::t("Profile"),
663                 ]);
664
665                 $arr = ['contact' => $contact, 'output' => $o];
666
667                 Addon::callHooks('contact_edit', $arr);
668
669                 return $arr['output'];
670         }
671
672         $blocked = false;
673         $hidden = false;
674         $ignored = false;
675         $archived = false;
676         $all = false;
677
678         if (($a->argc == 2) && ($a->argv[1] === 'all')) {
679                 $sql_extra = '';
680                 $all = true;
681         } elseif (($a->argc == 2) && ($a->argv[1] === 'blocked')) {
682                 $sql_extra = " AND `blocked` = 1 ";
683                 $blocked = true;
684         } elseif (($a->argc == 2) && ($a->argv[1] === 'hidden')) {
685                 $sql_extra = " AND `hidden` = 1 ";
686                 $hidden = true;
687         } elseif (($a->argc == 2) && ($a->argv[1] === 'ignored')) {
688                 $sql_extra = " AND `readonly` = 1 ";
689                 $ignored = true;
690         } elseif (($a->argc == 2) && ($a->argv[1] === 'archived')) {
691                 $sql_extra = " AND `archive` = 1 ";
692                 $archived = true;
693         } else {
694                 $sql_extra = " AND `blocked` = 0 ";
695         }
696
697         $search = x($_GET, 'search') ? notags(trim($_GET['search'])) : '';
698         $nets   = x($_GET, 'nets'  ) ? notags(trim($_GET['nets']))   : '';
699
700         $tabs = [
701                 [
702                         'label' => L10n::t('Suggestions'),
703                         'url'   => 'suggest',
704                         'sel'   => '',
705                         'title' => L10n::t('Suggest potential friends'),
706                         'id'    => 'suggestions-tab',
707                         'accesskey' => 'g',
708                 ],
709                 [
710                         'label' => L10n::t('All Contacts'),
711                         'url'   => 'contacts/all',
712                         'sel'   => ($all) ? 'active' : '',
713                         'title' => L10n::t('Show all contacts'),
714                         'id'    => 'showall-tab',
715                         'accesskey' => 'l',
716                 ],
717                 [
718                         'label' => L10n::t('Unblocked'),
719                         'url'   => 'contacts',
720                         'sel'   => ((!$all) && (!$blocked) && (!$hidden) && (!$search) && (!$nets) && (!$ignored) && (!$archived)) ? 'active' : '',
721                         'title' => L10n::t('Only show unblocked contacts'),
722                         'id'    => 'showunblocked-tab',
723                         'accesskey' => 'o',
724                 ],
725                 [
726                         'label' => L10n::t('Blocked'),
727                         'url'   => 'contacts/blocked',
728                         'sel'   => ($blocked) ? 'active' : '',
729                         'title' => L10n::t('Only show blocked contacts'),
730                         'id'    => 'showblocked-tab',
731                         'accesskey' => 'b',
732                 ],
733                 [
734                         'label' => L10n::t('Ignored'),
735                         'url'   => 'contacts/ignored',
736                         'sel'   => ($ignored) ? 'active' : '',
737                         'title' => L10n::t('Only show ignored contacts'),
738                         'id'    => 'showignored-tab',
739                         'accesskey' => 'i',
740                 ],
741                 [
742                         'label' => L10n::t('Archived'),
743                         'url'   => 'contacts/archived',
744                         'sel'   => ($archived) ? 'active' : '',
745                         'title' => L10n::t('Only show archived contacts'),
746                         'id'    => 'showarchived-tab',
747                         'accesskey' => 'y',
748                 ],
749                 [
750                         'label' => L10n::t('Hidden'),
751                         'url'   => 'contacts/hidden',
752                         'sel'   => ($hidden) ? 'active' : '',
753                         'title' => L10n::t('Only show hidden contacts'),
754                         'id'    => 'showhidden-tab',
755                         'accesskey' => 'h',
756                 ],
757         ];
758
759         $tab_tpl = get_markup_template('common_tabs.tpl');
760         $t = replace_macros($tab_tpl, ['$tabs' => $tabs]);
761
762         $total = 0;
763         $searching = false;
764         $search_hdr = null;
765         if ($search) {
766                 $searching = true;
767                 $search_hdr = $search;
768                 $search_txt = dbesc(protect_sprintf(preg_quote($search)));
769                 $sql_extra .= " AND (name REGEXP '$search_txt' OR url REGEXP '$search_txt'  OR nick REGEXP '$search_txt') ";
770         }
771
772         if ($nets) {
773                 $sql_extra .= sprintf(" AND network = '%s' ", dbesc($nets));
774         }
775
776         $sql_extra2 = ((($sort_type > 0) && ($sort_type <= CONTACT_IS_FRIEND)) ? sprintf(" AND `rel` = %d ", intval($sort_type)) : '');
777
778         $r = q("SELECT COUNT(*) AS `total` FROM `contact`
779                 WHERE `uid` = %d AND `self` = 0 AND `pending` = 0 $sql_extra $sql_extra2 ",
780                 intval($_SESSION['uid'])
781         );
782         if (DBM::is_result($r)) {
783                 $a->set_pager_total($r[0]['total']);
784                 $total = $r[0]['total'];
785         }
786
787         $sql_extra3 = Widget::unavailableNetworks();
788
789         $contacts = [];
790
791         $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 0 AND `pending` = 0 $sql_extra $sql_extra2 $sql_extra3 ORDER BY `name` ASC LIMIT %d , %d ",
792                 intval($_SESSION['uid']),
793                 intval($a->pager['start']),
794                 intval($a->pager['itemspage'])
795         );
796         if (DBM::is_result($r)) {
797                 foreach ($r as $rr) {
798                         $contacts[] = _contact_detail_for_template($rr);
799                 }
800         }
801
802         $tpl = get_markup_template("contacts-template.tpl");
803         $o .= replace_macros($tpl, [
804                 '$baseurl' => System::baseUrl(),
805                 '$header' => L10n::t('Contacts') . (($nets) ? ' - ' . ContactSelector::networkToName($nets) : ''),
806                 '$tabs' => $t,
807                 '$total' => $total,
808                 '$search' => $search_hdr,
809                 '$desc' => L10n::t('Search your contacts'),
810                 '$finding' => $searching ? L10n::t('Results for: %s', $search) : "",
811                 '$submit' => L10n::t('Find'),
812                 '$cmd' => $a->cmd,
813                 '$contacts' => $contacts,
814                 '$contact_drop_confirm' => L10n::t('Do you really want to delete this contact?'),
815                 'multiselect' => 1,
816                 '$batch_actions' => [
817                         'contacts_batch_update'  => L10n::t('Update'),
818                         'contacts_batch_block'   => L10n::t('Block') . "/" . L10n::t("Unblock"),
819                         "contacts_batch_ignore"  => L10n::t('Ignore') . "/" . L10n::t("Unignore"),
820                         "contacts_batch_archive" => L10n::t('Archive') . "/" . L10n::t("Unarchive"),
821                         "contacts_batch_drop"    => L10n::t('Delete'),
822                 ],
823                 '$h_batch_actions' => L10n::t('Batch Actions'),
824                 '$paginate' => paginate($a),
825         ]);
826
827         return $o;
828 }
829
830 /**
831  * @brief List of pages for the Contact TabBar
832  *
833  * Available Pages are 'Status', 'Profile', 'Contacts' and 'Common Friends'
834  *
835  * @param App $a
836  * @param int $contact_id The ID of the contact
837  * @param int $active_tab 1 if tab should be marked as active
838  *
839  * @return string
840  */
841 function contacts_tab($a, $contact_id, $active_tab)
842 {
843         // tabs
844         $tabs = [
845                 [
846                         'label' => L10n::t('Status'),
847                         'url'   => "contacts/" . $contact_id . "/posts",
848                         'sel'   => (($active_tab == 1) ? 'active' : ''),
849                         'title' => L10n::t('Status Messages and Posts'),
850                         'id'    => 'status-tab',
851                         'accesskey' => 'm',
852                 ],
853                 [
854                         'label' => L10n::t('Profile'),
855                         'url'   => "contacts/" . $contact_id,
856                         'sel'   => (($active_tab == 2) ? 'active' : ''),
857                         'title' => L10n::t('Profile Details'),
858                         'id'    => 'profile-tab',
859                         'accesskey' => 'o',
860                 ]
861         ];
862
863         // Show this tab only if there is visible friend list
864         $x = GContact::countAllFriends(local_user(), $contact_id);
865         if ($x) {
866                 $tabs[] = ['label' => L10n::t('Contacts'),
867                         'url'   => "allfriends/" . $contact_id,
868                         'sel'   => (($active_tab == 3) ? 'active' : ''),
869                         'title' => L10n::t('View all contacts'),
870                         'id'    => 'allfriends-tab',
871                         'accesskey' => 't'];
872         }
873
874         // Show this tab only if there is visible common friend list
875         $common = GContact::countCommonFriends(local_user(), $contact_id);
876         if ($common) {
877                 $tabs[] = ['label' => L10n::t('Common Friends'),
878                         'url'   => "common/loc/" . local_user() . "/" . $contact_id,
879                         'sel'   => (($active_tab == 4) ? 'active' : ''),
880                         'title' => L10n::t('View all common friends'),
881                         'id'    => 'common-loc-tab',
882                         'accesskey' => 'd'
883                 ];
884         }
885
886         $tabs[] = ['label' => L10n::t('Advanced'),
887                 'url'   => 'crepair/' . $contact_id,
888                 'sel'   => (($active_tab == 5) ? 'active' : ''),
889                 'title' => L10n::t('Advanced Contact Settings'),
890                 'id'    => 'advanced-tab',
891                 'accesskey' => 'r'
892         ];
893
894         $tab_tpl = get_markup_template('common_tabs.tpl');
895         $tab_str = replace_macros($tab_tpl, ['$tabs' => $tabs]);
896
897         return $tab_str;
898 }
899
900 function contact_posts($a, $contact_id)
901 {
902         $o = contacts_tab($a, $contact_id, 1);
903
904         $contact = dba::selectFirst('contact', ['url'], ['id' => $contact_id]);
905         if (DBM::is_result($contact)) {
906                 $a->page['aside'] = "";
907                 Profile::load($a, "", 0, Contact::getDetailsByURL($contact["url"]));
908                 $o .= Contact::getPostsFromUrl($contact["url"]);
909         }
910
911         return $o;
912 }
913
914 function _contact_detail_for_template($rr)
915 {
916         $dir_icon = '';
917         $alt_text = '';
918         switch ($rr['rel']) {
919                 case CONTACT_IS_FRIEND:
920                         $dir_icon = 'images/lrarrow.gif';
921                         $alt_text = L10n::t('Mutual Friendship');
922                         break;
923                 case CONTACT_IS_FOLLOWER;
924                         $dir_icon = 'images/larrow.gif';
925                         $alt_text = L10n::t('is a fan of yours');
926                         break;
927                 case CONTACT_IS_SHARING;
928                         $dir_icon = 'images/rarrow.gif';
929                         $alt_text = L10n::t('you are a fan of');
930                         break;
931                 default:
932                         break;
933         }
934         if (($rr['network'] === NETWORK_DFRN) && ($rr['rel'])) {
935                 $url = "redir/{$rr['id']}";
936                 $sparkle = ' class="sparkle" ';
937         } else {
938                 $url = $rr['url'];
939                 $sparkle = '';
940         }
941
942         return [
943                 'img_hover' => L10n::t('Visit %s\'s profile [%s]', $rr['name'], $rr['url']),
944                 'edit_hover' => L10n::t('Edit contact'),
945                 'photo_menu' => Contact::photoMenu($rr),
946                 'id' => $rr['id'],
947                 'alt_text' => $alt_text,
948                 'dir_icon' => $dir_icon,
949                 'thumb' => proxy_url($rr['thumb'], false, PROXY_SIZE_THUMB),
950                 'name' => htmlentities($rr['name']),
951                 'username' => htmlentities($rr['name']),
952                 'account_type' => Contact::getAccountType($rr),
953                 'sparkle' => $sparkle,
954                 'itemurl' => (($rr['addr'] != "") ? $rr['addr'] : $rr['url']),
955                 'url' => $url,
956                 'network' => ContactSelector::networkToName($rr['network'], $rr['url']),
957         ];
958 }
959
960 /**
961  * @brief Gives a array with actions which can performed to a given contact
962  *
963  * This includes actions like e.g. 'block', 'hide', 'archive', 'delete' and others
964  *
965  * @param array $contact Data about the Contact
966  * @return array with contact related actions
967  */
968 function contact_actions($contact)
969 {
970         $poll_enabled = in_array($contact['network'], [NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_FEED, NETWORK_MAIL]);
971         $contact_actions = [];
972
973         // Provide friend suggestion only for Friendica contacts
974         if ($contact['network'] === NETWORK_DFRN) {
975                 $contact_actions['suggest'] = [
976                         'label' => L10n::t('Suggest friends'),
977                         'url'   => 'fsuggest/' . $contact['id'],
978                         'title' => '',
979                         'sel'   => '',
980                         'id'    => 'suggest',
981                 ];
982         }
983
984         if ($poll_enabled) {
985                 $contact_actions['update'] = [
986                         'label' => L10n::t('Update now'),
987                         'url'   => 'contacts/' . $contact['id'] . '/update',
988                         'title' => '',
989                         'sel'   => '',
990                         'id'    => 'update',
991                 ];
992         }
993
994         $contact_actions['block'] = [
995                 'label' => (intval($contact['blocked']) ? L10n::t('Unblock') : L10n::t('Block') ),
996                 'url'   => 'contacts/' . $contact['id'] . '/block',
997                 'title' => L10n::t('Toggle Blocked status'),
998                 'sel'   => (intval($contact['blocked']) ? 'active' : ''),
999                 'id'    => 'toggle-block',
1000         ];
1001
1002         $contact_actions['ignore'] = [
1003                 'label' => (intval($contact['readonly']) ? L10n::t('Unignore') : L10n::t('Ignore') ),
1004                 'url'   => 'contacts/' . $contact['id'] . '/ignore',
1005                 'title' => L10n::t('Toggle Ignored status'),
1006                 'sel'   => (intval($contact['readonly']) ? 'active' : ''),
1007                 'id'    => 'toggle-ignore',
1008         ];
1009
1010         $contact_actions['archive'] = [
1011                 'label' => (intval($contact['archive']) ? L10n::t('Unarchive') : L10n::t('Archive') ),
1012                 'url'   => 'contacts/' . $contact['id'] . '/archive',
1013                 'title' => L10n::t('Toggle Archive status'),
1014                 'sel'   => (intval($contact['archive']) ? 'active' : ''),
1015                 'id'    => 'toggle-archive',
1016         ];
1017
1018         $contact_actions['delete'] = [
1019                 'label' => L10n::t('Delete'),
1020                 'url'   => 'contacts/' . $contact['id'] . '/drop',
1021                 'title' => L10n::t('Delete contact'),
1022                 'sel'   => '',
1023                 'id'    => 'delete',
1024         ];
1025
1026         return $contact_actions;
1027 }