]> git.mxchange.org Git - friendica.git/blob - mod/contacts.php
Merge pull request #4312 from zeroadam/feature/L10n
[friendica.git] / mod / contacts.php
1 <?php
2 /**
3  * @file mod/contacts.php
4  */
5 use Friendica\App;
6 use Friendica\Content\ContactSelector;
7 use Friendica\Content\Nav;
8 use Friendica\Content\Widget;
9 use Friendica\Core\Addon;
10 use Friendica\Core\L10n;
11 use Friendica\Core\System;
12 use Friendica\Core\Worker;
13 use Friendica\Database\DBM;
14 use Friendica\Model\Contact;
15 use Friendica\Model\GContact;
16 use Friendica\Model\Group;
17 use Friendica\Model\Profile;
18 use Friendica\Network\Probe;
19
20 require_once 'mod/proxy.php';
21
22 function contacts_init(App $a)
23 {
24         if (!local_user()) {
25                 return;
26         }
27
28         $nets = defaults($_GET, 'nets', '');
29         if ($nets == "all") {
30                 $nets = "";
31         }
32
33         if (!x($a->page, 'aside')) {
34                 $a->page['aside'] = '';
35         }
36
37         $contact_id = null;
38         $contact = null;
39         if ((($a->argc == 2) && intval($a->argv[1])) || (($a->argc == 3) && intval($a->argv[1]) && ($a->argv[2] == "posts"))) {
40                 $contact_id = intval($a->argv[1]);
41                 $contact = dba::selectFirst('contact', [], ['id' => $contact_id, 'uid' => local_user()]);
42         }
43
44         if (DBM::is_result($contact)) {
45                 $a->data['contact'] = $contact;
46
47                 if (($a->data['contact']['network'] != "") && ($a->data['contact']['network'] != NETWORK_DFRN)) {
48                         $networkname = format_network_name($a->data['contact']['network'], $a->data['contact']['url']);
49                 } else {
50                         $networkname = '';
51                 }
52
53                 /// @TODO Add nice spaces
54                 $vcard_widget = replace_macros(get_markup_template("vcard-widget.tpl"), [
55                         '$name' => htmlentities($a->data['contact']['name']),
56                         '$photo' => $a->data['contact']['photo'],
57                         '$url' => ($a->data['contact']['network'] == NETWORK_DFRN) ? "redir/" . $a->data['contact']['id'] : $a->data['contact']['url'],
58                         '$addr' => (($a->data['contact']['addr'] != "") ? ($a->data['contact']['addr']) : ""),
59                         '$network_name' => $networkname,
60                         '$network' => L10n::t('Network:'),
61                         '$account_type' => Contact::getAccountType($a->data['contact'])
62                 ]);
63
64                 $findpeople_widget = '';
65                 $follow_widget = '';
66                 $networks_widget = '';
67         } else {
68                 $vcard_widget = '';
69                 $networks_widget = Widget::networks('contacts', $nets);
70                 if (isset($_GET['add'])) {
71                         $follow_widget = Widget::follow($_GET['add']);
72                 } else {
73                         $follow_widget = Widget::follow();
74                 }
75
76                 $findpeople_widget = Widget::findPeople();
77         }
78
79         $groups_widget = Group::sidebarWidget('contacts', 'group', 'full', 0, $contact_id);
80
81         $a->page['aside'] .= replace_macros(get_markup_template("contacts-widget-sidebar.tpl"), [
82                 '$vcard_widget' => $vcard_widget,
83                 '$findpeople_widget' => $findpeople_widget,
84                 '$follow_widget' => $follow_widget,
85                 '$groups_widget' => $groups_widget,
86                 '$networks_widget' => $networks_widget
87         ]);
88
89         $base = System::baseUrl();
90         $tpl = get_markup_template("contacts-head.tpl");
91         $a->page['htmlhead'] .= replace_macros($tpl, [
92                 '$baseurl' => System::baseUrl(true),
93                 '$base' => $base
94         ]);
95
96         $tpl = get_markup_template("contacts-end.tpl");
97         $a->page['end'] .= replace_macros($tpl, [
98                 '$baseurl' => System::baseUrl(true),
99                 '$base' => $base
100         ]);
101 }
102
103 function contacts_batch_actions(App $a)
104 {
105         $contacts_id = $_POST['contact_batch'];
106         if (!is_array($contacts_id)) {
107                 return;
108         }
109
110         $orig_records = q("SELECT * FROM `contact` WHERE `id` IN (%s) AND `uid` = %d AND `self` = 0",
111                 implode(",", $contacts_id),
112                 intval(local_user())
113         );
114
115         $count_actions = 0;
116         foreach ($orig_records as $orig_record) {
117                 $contact_id = $orig_record['id'];
118                 if (x($_POST, 'contacts_batch_update')) {
119                         _contact_update($contact_id);
120                         $count_actions++;
121                 }
122                 if (x($_POST, 'contacts_batch_block')) {
123                         $r = _contact_block($contact_id, $orig_record);
124                         if ($r) {
125                                 $count_actions++;
126                         }
127                 }
128                 if (x($_POST, 'contacts_batch_ignore')) {
129                         $r = _contact_ignore($contact_id, $orig_record);
130                         if ($r) {
131                                 $count_actions++;
132                         }
133                 }
134                 if (x($_POST, 'contacts_batch_archive')) {
135                         $r = _contact_archive($contact_id, $orig_record);
136                         if ($r) {
137                                 $count_actions++;
138                         }
139                 }
140                 if (x($_POST, 'contacts_batch_drop')) {
141                         _contact_drop($orig_record);
142                         $count_actions++;
143                 }
144         }
145         if ($count_actions > 0) {
146                 info(L10n::tt("%d contact edited.", "%d contacts edited.", $count_actions));
147         }
148
149         if (x($_SESSION, 'return_url')) {
150                 goaway('' . $_SESSION['return_url']);
151         } else {
152                 goaway('contacts');
153         }
154 }
155
156 function contacts_post(App $a)
157 {
158         if (!local_user()) {
159                 return;
160         }
161
162         if ($a->argv[1] === "batch") {
163                 contacts_batch_actions($a);
164                 return;
165         }
166
167         $contact_id = intval($a->argv[1]);
168         if (!$contact_id) {
169                 return;
170         }
171
172         if (!dba::exists('contact', ['id' => $contact_id, 'uid' => local_user()])) {
173                 notice(L10n::t('Could not access contact record.') . EOL);
174                 goaway('contacts');
175                 return; // NOTREACHED
176         }
177
178         Addon::callHooks('contact_edit_post', $_POST);
179
180         $profile_id = intval($_POST['profile-assign']);
181         if ($profile_id) {
182                 if (!dba::exists('profile', ['id' => $profile_id, 'uid' => local_user()])) {
183                         notice(L10n::t('Could not locate selected profile.') . EOL);
184                         return;
185                 }
186         }
187
188         $hidden = intval($_POST['hidden']);
189
190         $notify = intval($_POST['notify']);
191
192         $fetch_further_information = intval($_POST['fetch_further_information']);
193
194         $ffi_keyword_blacklist = escape_tags(trim($_POST['ffi_keyword_blacklist']));
195
196         $priority = intval($_POST['poll']);
197         if ($priority > 5 || $priority < 0) {
198                 $priority = 0;
199         }
200
201         $info = escape_tags(trim($_POST['info']));
202
203         $r = q("UPDATE `contact` SET `profile-id` = %d, `priority` = %d , `info` = '%s',
204                 `hidden` = %d, `notify_new_posts` = %d, `fetch_further_information` = %d,
205                 `ffi_keyword_blacklist` = '%s' WHERE `id` = %d AND `uid` = %d",
206                 intval($profile_id),
207                 intval($priority),
208                 dbesc($info),
209                 intval($hidden),
210                 intval($notify),
211                 intval($fetch_further_information),
212                 dbesc($ffi_keyword_blacklist),
213                 intval($contact_id),
214                 intval(local_user())
215         );
216         if (DBM::is_result($r)) {
217                 info(L10n::t('Contact updated.') . EOL);
218         } else {
219                 notice(L10n::t('Failed to update contact record.') . EOL);
220         }
221
222         $contact = dba::selectFirst('contact', [], ['id' => $contact_id, 'uid' => local_user()]);
223         if (DBM::is_result($contact)) {
224                 $a->data['contact'] = $contact;
225         }
226
227         return;
228 }
229
230 /* contact actions */
231
232 function _contact_update($contact_id)
233 {
234         $contact = dba::selectFirst('contact', ['uid', 'url', 'network'], ['id' => $contact_id, 'uid' => local_user()]);
235         if (!DBM::is_result($contact)) {
236                 return;
237         }
238
239         $uid = $contact["uid"];
240
241         if ($contact["network"] == NETWORK_OSTATUS) {
242                 $result = Contact::createFromProbe($uid, $contact["url"], false, $contact["network"]);
243
244                 if ($result['success']) {
245                         q("UPDATE `contact` SET `subhub` = 1 WHERE `id` = %d", intval($contact_id));
246                 }
247         } else {
248                 // pull feed and consume it, which should subscribe to the hub.
249                 Worker::add(PRIORITY_HIGH, "OnePoll", $contact_id, "force");
250         }
251 }
252
253 function _contact_update_profile($contact_id)
254 {
255         $contact = dba::selectFirst('contact', ['uid', 'url', 'network'], ['id' => $contact_id, 'uid' => local_user()]);
256         if (!DBM::is_result($contact)) {
257                 return;
258         }
259
260         $uid = $contact["uid"];
261
262         $data = Probe::uri($contact["url"], "", 0, false);
263
264         // "Feed" or "Unknown" is mostly a sign of communication problems
265         if ((in_array($data["network"], [NETWORK_FEED, NETWORK_PHANTOM])) && ($data["network"] != $contact["network"])) {
266                 return;
267         }
268
269         $updatefields = ["name", "nick", "url", "addr", "batch", "notify", "poll", "request", "confirm",
270                 "poco", "network", "alias"];
271         $update = [];
272
273         if ($data["network"] == NETWORK_OSTATUS) {
274                 $result = Contact::createFromProbe($uid, $data["url"], false);
275
276                 if ($result['success']) {
277                         $update["subhub"] = true;
278                 }
279         }
280
281         foreach ($updatefields AS $field) {
282                 if (isset($data[$field]) && ($data[$field] != "")) {
283                         $update[$field] = $data[$field];
284                 }
285         }
286
287         $update["nurl"] = normalise_link($data["url"]);
288
289         $query = "";
290
291         if (isset($data["priority"]) && ($data["priority"] != 0)) {
292                 $query = "`priority` = " . intval($data["priority"]);
293         }
294
295         foreach ($update AS $key => $value) {
296                 if ($query != "") {
297                         $query .= ", ";
298                 }
299
300                 $query .= "`" . $key . "` = '" . dbesc($value) . "'";
301         }
302
303         if ($query == "") {
304                 return;
305         }
306
307         $r = q("UPDATE `contact` SET $query WHERE `id` = %d AND `uid` = %d",
308                 intval($contact_id),
309                 intval(local_user())
310         );
311
312         // Update the entry in the contact table
313         Contact::updateAvatar($data['photo'], local_user(), $contact_id, true);
314
315         // Update the entry in the gcontact table
316         GContact::updateFromProbe($data["url"]);
317 }
318
319 function _contact_block($contact_id, $orig_record)
320 {
321         $blocked = (($orig_record['blocked']) ? 0 : 1);
322         $r = q("UPDATE `contact` SET `blocked` = %d WHERE `id` = %d AND `uid` = %d",
323                 intval($blocked),
324                 intval($contact_id),
325                 intval(local_user())
326         );
327         return DBM::is_result($r);
328 }
329
330 function _contact_ignore($contact_id, $orig_record)
331 {
332         $readonly = (($orig_record['readonly']) ? 0 : 1);
333         $r = q("UPDATE `contact` SET `readonly` = %d WHERE `id` = %d AND `uid` = %d",
334                 intval($readonly),
335                 intval($contact_id),
336                 intval(local_user())
337         );
338         return DBM::is_result($r);
339 }
340
341 function _contact_archive($contact_id, $orig_record)
342 {
343         $archived = (($orig_record['archive']) ? 0 : 1);
344         $r = q("UPDATE `contact` SET `archive` = %d WHERE `id` = %d AND `uid` = %d",
345                 intval($archived),
346                 intval($contact_id),
347                 intval(local_user())
348         );
349         if ($archived) {
350                 q("UPDATE `item` SET `private` = 2 WHERE `contact-id` = %d AND `uid` = %d", intval($contact_id), 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') : datetime_convert('UTC', date_default_timezone_get(), $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'] < datetime_converL10n::t('', '', 'now')) ? 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($contact["location"]),
651                         '$location_label' => L10n::t("Location:"),
652                         '$xmpp' => bbcode($contact["xmpp"]),
653                         '$xmpp_label' => L10n::t("XMPP:"),
654                         '$about' => bbcode($contact["about"], false, 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 }