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