]> git.mxchange.org Git - friendica.git/blob - mod/contacts.php
90c4af7d1bcbe967d4cd2fd267245dfdc6969fd4
[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\Core\System;
8 use Friendica\Core\Worker;
9 use Friendica\Database\DBM;
10 use Friendica\Model\Contact;
11 use Friendica\Model\GContact;
12 use Friendica\Model\Group;
13 use Friendica\Network\Probe;
14
15 require_once 'include/contact_widgets.php';
16 require_once 'mod/proxy.php';
17
18 function contacts_init(App $a)
19 {
20         if (!local_user()) {
21                 return;
22         }
23
24         $nets = defaults($_GET, 'nets', '');
25         if ($nets == "all") {
26                 $nets = "";
27         }
28
29         if (!x($a->page, 'aside')) {
30                 $a->page['aside'] = '';
31         }
32
33         $contact = [];
34         if ((($a->argc == 2) && intval($a->argv[1])) || (($a->argc == 3) && intval($a->argv[1]) && ($a->argv[2] == "posts"))) {
35                 $contact_id = intval($a->argv[1]);
36                 $contact = dba::selectFirst('contact', [], ['id' => $contact_id, 'uid' => local_user()]);
37         }
38
39         if (DBM::is_result($contact)) {
40                 $a->data['contact'] = $contact;
41
42                 if (($a->data['contact']['network'] != "") && ($a->data['contact']['network'] != NETWORK_DFRN)) {
43                         $networkname = format_network_name($a->data['contact']['network'], $a->data['contact']['url']);
44                 } else {
45                         $networkname = '';
46                 }
47
48                 /// @TODO Add nice spaces
49                 $vcard_widget = replace_macros(get_markup_template("vcard-widget.tpl"), array(
50                         '$name' => htmlentities($a->data['contact']['name']),
51                         '$photo' => $a->data['contact']['photo'],
52                         '$url' => ($a->data['contact']['network'] == NETWORK_DFRN) ? "redir/" . $a->data['contact']['id'] : $a->data['contact']['url'],
53                         '$addr' => (($a->data['contact']['addr'] != "") ? ($a->data['contact']['addr']) : ""),
54                         '$network_name' => $networkname,
55                         '$network' => t('Network:'),
56                         '$account_type' => Contact::getAccountType($a->data['contact'])
57                 ));
58
59                 $findpeople_widget = '';
60                 $follow_widget = '';
61                 $networks_widget = '';
62         } else {
63                 $vcard_widget = '';
64                 $networks_widget = networks_widget('contacts', $nets);
65                 if (isset($_GET['add'])) {
66                         $follow_widget = follow_widget($_GET['add']);
67                 } else {
68                         $follow_widget = follow_widget();
69                 }
70
71                 $findpeople_widget = findpeople_widget();
72         }
73
74         $groups_widget = Group::sidebarWidget('contacts', 'group', 'full', 0, $contact_id);
75
76         $a->page['aside'] .= replace_macros(get_markup_template("contacts-widget-sidebar.tpl"), array(
77                 '$vcard_widget' => $vcard_widget,
78                 '$findpeople_widget' => $findpeople_widget,
79                 '$follow_widget' => $follow_widget,
80                 '$groups_widget' => $groups_widget,
81                 '$networks_widget' => $networks_widget
82         ));
83
84         $base = System::baseUrl();
85         $tpl = get_markup_template("contacts-head.tpl");
86         $a->page['htmlhead'] .= replace_macros($tpl, array(
87                 '$baseurl' => System::baseUrl(true),
88                 '$base' => $base
89         ));
90
91         $tpl = get_markup_template("contacts-end.tpl");
92         $a->page['end'] .= replace_macros($tpl, array(
93                 '$baseurl' => System::baseUrl(true),
94                 '$base' => $base
95         ));
96 }
97
98 function contacts_batch_actions(App $a)
99 {
100         $contacts_id = $_POST['contact_batch'];
101         if (!is_array($contacts_id)) {
102                 return;
103         }
104
105         $orig_records = q("SELECT * FROM `contact` WHERE `id` IN (%s) AND `uid` = %d AND `self` = 0",
106                 implode(",", $contacts_id),
107                 intval(local_user())
108         );
109
110         $count_actions = 0;
111         foreach ($orig_records as $orig_record) {
112                 $contact_id = $orig_record['id'];
113                 if (x($_POST, 'contacts_batch_update')) {
114                         _contact_update($contact_id);
115                         $count_actions++;
116                 }
117                 if (x($_POST, 'contacts_batch_block')) {
118                         $r = _contact_block($contact_id, $orig_record);
119                         if ($r) {
120                                 $count_actions++;
121                         }
122                 }
123                 if (x($_POST, 'contacts_batch_ignore')) {
124                         $r = _contact_ignore($contact_id, $orig_record);
125                         if ($r) {
126                                 $count_actions++;
127                         }
128                 }
129                 if (x($_POST, 'contacts_batch_archive')) {
130                         $r = _contact_archive($contact_id, $orig_record);
131                         if ($r) {
132                                 $count_actions++;
133                         }
134                 }
135                 if (x($_POST, 'contacts_batch_drop')) {
136                         _contact_drop($orig_record);
137                         $count_actions++;
138                 }
139         }
140         if ($count_actions > 0) {
141                 info(tt("%d contact edited.", "%d contacts edited.", $count_actions));
142         }
143
144         if (x($_SESSION, 'return_url')) {
145                 goaway('' . $_SESSION['return_url']);
146         } else {
147                 goaway('contacts');
148         }
149 }
150
151 function contacts_post(App $a)
152 {
153         if (!local_user()) {
154                 return;
155         }
156
157         if ($a->argv[1] === "batch") {
158                 contacts_batch_actions($a);
159                 return;
160         }
161
162         $contact_id = intval($a->argv[1]);
163         if (!$contact_id) {
164                 return;
165         }
166
167         $orig_record = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
168                 intval($contact_id),
169                 intval(local_user())
170         );
171         if (!DBM::is_result($orig_record)) {
172                 notice(t('Could not access contact record.') . EOL);
173                 goaway('contacts');
174                 return; // NOTREACHED
175         }
176
177         call_hooks('contact_edit_post', $_POST);
178
179         $profile_id = intval($_POST['profile-assign']);
180         if ($profile_id) {
181                 $r = q("SELECT `id` FROM `profile` WHERE `id` = %d AND `uid` = %d LIMIT 1",
182                         intval($profile_id),
183                         intval(local_user())
184                 );
185                 if (!DBM::is_result($r)) {
186                         notice(t('Could not locate selected profile.') . EOL);
187                         return;
188                 }
189         }
190
191         $hidden = intval($_POST['hidden']);
192
193         $notify = intval($_POST['notify']);
194
195         $fetch_further_information = intval($_POST['fetch_further_information']);
196
197         $ffi_keyword_blacklist = escape_tags(trim($_POST['ffi_keyword_blacklist']));
198
199         $priority = intval($_POST['poll']);
200         if ($priority > 5 || $priority < 0) {
201                 $priority = 0;
202         }
203
204         $info = escape_tags(trim($_POST['info']));
205
206         $r = q("UPDATE `contact` SET `profile-id` = %d, `priority` = %d , `info` = '%s',
207                 `hidden` = %d, `notify_new_posts` = %d, `fetch_further_information` = %d,
208                 `ffi_keyword_blacklist` = '%s' WHERE `id` = %d AND `uid` = %d",
209                 intval($profile_id),
210                 intval($priority),
211                 dbesc($info),
212                 intval($hidden),
213                 intval($notify),
214                 intval($fetch_further_information),
215                 dbesc($ffi_keyword_blacklist),
216                 intval($contact_id),
217                 intval(local_user())
218         );
219         if (DBM::is_result($r)) {
220                 info(t('Contact updated.') . EOL);
221         } else {
222                 notice(t('Failed to update contact record.') . EOL);
223         }
224
225         $contact = dba::selectFirst('contact', [], ['id' => $contact_id, 'uid' => local_user()]);
226         if (DBM::is_result($contact)) {
227                 $a->data['contact'] = $contact;
228         }
229
230         return;
231 }
232 /* 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 ($r[0]["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"], array(NETWORK_FEED, NETWORK_PHANTOM))) && ($data["network"] != $contact["network"])) {
268                 return;
269         }
270
271         $updatefields = array("name", "nick", "url", "addr", "batch", "notify", "poll", "request", "confirm",
272                 "poco", "network", "alias");
273         $update = array();
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_set_selected('contacts');
378
379         if (!local_user()) {
380                 notice(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(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) ? t('Contact has been blocked') : 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) ? t('Contact has been ignored') : 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) ? t('Contact has been archived') : 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 = array();
451                                 foreach ($query['args'] as $arg) {
452                                         if (strpos($arg, 'confirm=') === false) {
453                                                 $arg_parts = explode('=', $arg);
454                                                 $inputs[] = array('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'), array(
461                                         '$header' => t('Drop contact'),
462                                         '$contact' => _contact_detail_for_template($orig_record),
463                                         '$method' => 'get',
464                                         '$message' => t('Do you really want to delete this contact?'),
465                                         '$extra_inputs' => $inputs,
466                                         '$confirm' => t('Yes'),
467                                         '$confirm_url' => $query['base'],
468                                         '$confirm_name' => 'confirmed',
469                                         '$cancel' => 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(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'), array(
502                         '$baseurl' => System::baseUrl(true),
503                 ));
504                 $a->page['end'] .= replace_macros(get_markup_template('contact_end.tpl'), array(
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 = t('You are mutual friends with %s');
514                                 break;
515                         case CONTACT_IS_FOLLOWER;
516                                 $dir_icon = 'images/larrow.gif';
517                                 $relation_text = t('You are sharing with %s');
518                                 break;
519                         case CONTACT_IS_SHARING;
520                                 $dir_icon = 'images/rarrow.gif';
521                                 $relation_text = t('%s is sharing with you');
522                                 break;
523                         default:
524                                 break;
525                 }
526
527                 if (!in_array($contact['network'], array(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 = t('Private communications are not available for this contact.');
542
543                 $last_update = (($contact['last-update'] <= NULL_DATE) ? t('Never') : datetime_convert('UTC', date_default_timezone_get(), $contact['last-update'], 'D, j M Y, g:i A'));
544
545                 if ($contact['last-update'] > NULL_DATE) {
546                         $last_update .= ' ' . (($contact['last-update'] <= $contact['success_update']) ? t("\x28Update was successful\x29") : t("\x28Update was not successful\x29"));
547                 }
548                 $lblsuggest = (($contact['network'] === NETWORK_DFRN) ? t('Suggest friends') : '');
549
550                 $poll_enabled = in_array($contact['network'], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_FEED, NETWORK_MAIL));
551
552                 $nettype = 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')) ? t('Communications lost with this contact!') : '');
558
559                 $fetch_further_information = null;
560                 if ($contact['network'] == NETWORK_FEED) {
561                         $fetch_further_information = array(
562                                 'fetch_further_information',
563                                 t('Fetch further information for feeds'),
564                                 $contact['fetch_further_information'],
565                                 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                                 array('0' => t('Disabled'),
567                                         '1' => t('Fetch information'),
568                                         '3' => t('Fetch keywords'),
569                                         '2' => t('Fetch information and keywords')
570                                 )
571                         );
572                 }
573
574                 $poll_interval = null;
575                 if (in_array($contact['network'], array(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'], array(NETWORK_DIASPORA, NETWORK_OSTATUS))) {
587                         if ($contact['rel'] == CONTACT_IS_FOLLOWER) {
588                                 $follow = System::baseUrl(true) . "/follow?url=" . urlencode($contact["url"]);
589                                 $follow_text = t("Connect/Follow");
590                         } elseif ($contact['rel'] == CONTACT_IS_FRIEND) {
591                                 $follow = System::baseUrl(true) . "/unfollow?url=" . urlencode($contact["url"]);
592                                 $follow_text = 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, array(
601                         '$header' => t("Contact"),
602                         '$tab_str' => $tab_str,
603                         '$submit' => t('Submit'),
604                         '$lbl_vis1' => t('Profile Visibility'),
605                         '$lbl_vis2' => t('Please choose the profile you would like to display to %s when viewing your profile securely.', $contact['name']),
606                         '$lbl_info1' => t('Contact Information / Notes'),
607                         '$lbl_info2' => t('Their personal note'),
608                         '$reason' => trim(notags($contact['reason'])),
609                         '$infedit' => t('Edit contact notes'),
610                         '$common_link' => 'common/loc/' . local_user() . '/' . $contact['id'],
611                         '$relation_text' => $relation_text,
612                         '$visit' => t('Visit %s\'s profile [%s]', $contact['name'], $contact['url']),
613                         '$blockunblock' => t('Block/Unblock contact'),
614                         '$ignorecont' => t('Ignore contact'),
615                         '$lblcrepair' => t("Repair URL settings"),
616                         '$lblrecent' => t('View conversations'),
617                         '$lblsuggest' => $lblsuggest,
618                         '$nettype' => $nettype,
619                         '$poll_interval' => $poll_interval,
620                         '$poll_enabled' => $poll_enabled,
621                         '$lastupdtext' => t('Last update:'),
622                         '$lost_contact' => $lost_contact,
623                         '$updpub' => t('Update public posts'),
624                         '$last_update' => $last_update,
625                         '$udnow' => 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']) ? t('Unblock') : t('Block') ),
631                         '$ignore_text' => (($contact['readonly']) ? t('Unignore') : 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' => array('info', '', $contact['info'], ''),
635                         '$blocked' => (($contact['blocked']) ? t('Currently blocked') : ''),
636                         '$ignored' => (($contact['readonly']) ? t('Currently ignored') : ''),
637                         '$archived' => (($contact['archive']) ? t('Currently archived') : ''),
638                         '$pending' => (($contact['pending']) ? t('Awaiting connection acknowledge') : ''),
639                         '$hidden' => array('hidden', t('Hide this contact from others'), ($contact['hidden'] == 1), t('Replies/likes to your public posts <strong>may</strong> still be visible')),
640                         '$notify' => array('notify', t('Notification for new posts'), ($contact['notify_new_posts'] == 1), 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' => array('ffi_keyword_blacklist', t('Blacklisted keywords'), $contact['ffi_keyword_blacklist'], 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' => t('Profile URL'),
650                         '$profileurl' => $contact['url'],
651                         '$account_type' => Contact::getAccountType($contact),
652                         '$location' => bbcode($contact["location"]),
653                         '$location_label' => t("Location:"),
654                         '$xmpp' => bbcode($contact["xmpp"]),
655                         '$xmpp_label' => t("XMPP:"),
656                         '$about' => bbcode($contact["about"], false, false),
657                         '$about_label' => t("About:"),
658                         '$keywords' => $contact["keywords"],
659                         '$keywords_label' => t("Tags:"),
660                         '$contact_action_button' => t("Actions"),
661                         '$contact_actions' => $contact_actions,
662                         '$contact_status' => t("Status"),
663                         '$contact_settings_label' => t('Contact Settings'),
664                         '$contact_profile_label' => t("Profile"),
665                 ));
666
667                 $arr = array('contact' => $contact, 'output' => $o);
668
669                 call_hooks('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 = array(
703                 array(
704                         'label' => t('Suggestions'),
705                         'url'   => 'suggest',
706                         'sel'   => '',
707                         'title' => t('Suggest potential friends'),
708                         'id'    => 'suggestions-tab',
709                         'accesskey' => 'g',
710                 ),
711                 array(
712                         'label' => t('All Contacts'),
713                         'url'   => 'contacts/all',
714                         'sel'   => ($all) ? 'active' : '',
715                         'title' => t('Show all contacts'),
716                         'id'    => 'showall-tab',
717                         'accesskey' => 'l',
718                 ),
719                 array(
720                         'label' => t('Unblocked'),
721                         'url'   => 'contacts',
722                         'sel'   => ((!$all) && (!$blocked) && (!$hidden) && (!$search) && (!$nets) && (!$ignored) && (!$archived)) ? 'active' : '',
723                         'title' => t('Only show unblocked contacts'),
724                         'id'    => 'showunblocked-tab',
725                         'accesskey' => 'o',
726                 ),
727                 array(
728                         'label' => t('Blocked'),
729                         'url'   => 'contacts/blocked',
730                         'sel'   => ($blocked) ? 'active' : '',
731                         'title' => t('Only show blocked contacts'),
732                         'id'    => 'showblocked-tab',
733                         'accesskey' => 'b',
734                 ),
735                 array(
736                         'label' => t('Ignored'),
737                         'url'   => 'contacts/ignored',
738                         'sel'   => ($ignored) ? 'active' : '',
739                         'title' => t('Only show ignored contacts'),
740                         'id'    => 'showignored-tab',
741                         'accesskey' => 'i',
742                 ),
743                 array(
744                         'label' => t('Archived'),
745                         'url'   => 'contacts/archived',
746                         'sel'   => ($archived) ? 'active' : '',
747                         'title' => t('Only show archived contacts'),
748                         'id'    => 'showarchived-tab',
749                         'accesskey' => 'y',
750                 ),
751                 array(
752                         'label' => t('Hidden'),
753                         'url'   => 'contacts/hidden',
754                         'sel'   => ($hidden) ? 'active' : '',
755                         'title' => 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, array('$tabs' => $tabs));
763
764         $total = 0;
765         $searching = false;
766         $search_hdr = null;
767         $search_txt = '';
768         if ($search) {
769                 $searching = true;
770                 $search_hdr = $search;
771                 $search_txt = dbesc(protect_sprintf(preg_quote($search)));
772                 $sql_extra .= " AND (name REGEXP '$search_txt' OR url REGEXP '$search_txt'  OR nick REGEXP '$search_txt') ";
773         }
774
775         if ($nets) {
776                 $sql_extra .= sprintf(" AND network = '%s' ", dbesc($nets));
777         }
778
779         $sql_extra2 = ((($sort_type > 0) && ($sort_type <= CONTACT_IS_FRIEND)) ? sprintf(" AND `rel` = %d ", intval($sort_type)) : '');
780
781         $r = q("SELECT COUNT(*) AS `total` FROM `contact`
782                 WHERE `uid` = %d AND `self` = 0 AND `pending` = 0 $sql_extra $sql_extra2 ",
783                 intval($_SESSION['uid'])
784         );
785         if (DBM::is_result($r)) {
786                 $a->set_pager_total($r[0]['total']);
787                 $total = $r[0]['total'];
788         }
789
790         $sql_extra3 = unavailable_networks();
791
792         $contacts = array();
793
794         $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 ",
795                 intval($_SESSION['uid']),
796                 intval($a->pager['start']),
797                 intval($a->pager['itemspage'])
798         );
799         if (DBM::is_result($r)) {
800                 foreach ($r as $rr) {
801                         $contacts[] = _contact_detail_for_template($rr);
802                 }
803         }
804
805         $tpl = get_markup_template("contacts-template.tpl");
806         $o .= replace_macros($tpl, array(
807                 '$baseurl' => System::baseUrl(),
808                 '$header' => t('Contacts') . (($nets) ? ' - ' . ContactSelector::networkToName($nets) : ''),
809                 '$tabs' => $t,
810                 '$total' => $total,
811                 '$search' => $search_hdr,
812                 '$desc' => t('Search your contacts'),
813                 '$finding' => $searching ? t('Results for: %s', $search) : "",
814                 '$submit' => t('Find'),
815                 '$cmd' => $a->cmd,
816                 '$contacts' => $contacts,
817                 '$contact_drop_confirm' => t('Do you really want to delete this contact?'),
818                 'multiselect' => 1,
819                 '$batch_actions' => array(
820                         'contacts_batch_update'  => t('Update'),
821                         'contacts_batch_block'   => t('Block') . "/" . t("Unblock"),
822                         "contacts_batch_ignore"  => t('Ignore') . "/" . t("Unignore"),
823                         "contacts_batch_archive" => t('Archive') . "/" . t("Unarchive"),
824                         "contacts_batch_drop"    => t('Delete'),
825                 ),
826                 '$h_batch_actions' => t('Batch Actions'),
827                 '$paginate' => paginate($a),
828         ));
829
830         return $o;
831 }
832
833 /**
834  * @brief List of pages for the Contact TabBar
835  *
836  * Available Pages are 'Status', 'Profile', 'Contacts' and 'Common Friends'
837  *
838  * @param App $a
839  * @param int $contact_id The ID of the contact
840  * @param int $active_tab 1 if tab should be marked as active
841  *
842  * @return string
843  */
844 function contacts_tab($a, $contact_id, $active_tab)
845 {
846         // tabs
847         $tabs = array(
848                 array(
849                         'label' => t('Status'),
850                         'url'   => "contacts/" . $contact_id . "/posts",
851                         'sel'   => (($active_tab == 1) ? 'active' : ''),
852                         'title' => t('Status Messages and Posts'),
853                         'id'    => 'status-tab',
854                         'accesskey' => 'm',
855                 ),
856                 array(
857                         'label' => t('Profile'),
858                         'url'   => "contacts/" . $contact_id,
859                         'sel'   => (($active_tab == 2) ? 'active' : ''),
860                         'title' => t('Profile Details'),
861                         'id'    => 'profile-tab',
862                         'accesskey' => 'o',
863                 )
864         );
865
866         // Show this tab only if there is visible friend list
867         $x = GContact::countAllFriends(local_user(), $contact_id);
868         if ($x) {
869                 $tabs[] = array('label' => t('Contacts'),
870                         'url'   => "allfriends/" . $contact_id,
871                         'sel'   => (($active_tab == 3) ? 'active' : ''),
872                         'title' => t('View all contacts'),
873                         'id'    => 'allfriends-tab',
874                         'accesskey' => 't');
875         }
876
877         // Show this tab only if there is visible common friend list
878         $common = GContact::countCommonFriends(local_user(), $contact_id);
879         if ($common) {
880                 $tabs[] = array('label' => t('Common Friends'),
881                         'url'   => "common/loc/" . local_user() . "/" . $contact_id,
882                         'sel'   => (($active_tab == 4) ? 'active' : ''),
883                         'title' => t('View all common friends'),
884                         'id'    => 'common-loc-tab',
885                         'accesskey' => 'd'
886                 );
887         }
888
889         $tabs[] = array('label' => t('Advanced'),
890                 'url'   => 'crepair/' . $contact_id,
891                 'sel'   => (($active_tab == 5) ? 'active' : ''),
892                 'title' => t('Advanced Contact Settings'),
893                 'id'    => 'advanced-tab',
894                 'accesskey' => 'r'
895         );
896
897         $tab_tpl = get_markup_template('common_tabs.tpl');
898         $tab_str = replace_macros($tab_tpl, array('$tabs' => $tabs));
899
900         return $tab_str;
901 }
902
903 function contact_posts($a, $contact_id)
904 {
905         $o = contacts_tab($a, $contact_id, 1);
906
907         $contact = dba::selectFirst('contact', ['url'], ['id' => $contact_id]);
908         if (DBM::is_result($contact)) {
909                 $a->page['aside'] = "";
910                 profile_load($a, "", 0, Contact::getDetailsByURL($contact["url"]));
911                 $o .= Contact::getPostsFromUrl($contact["url"]);
912         }
913
914         return $o;
915 }
916
917 function _contact_detail_for_template($rr)
918 {
919         $dir_icon = '';
920         $alt_text = '';
921         switch ($rr['rel']) {
922                 case CONTACT_IS_FRIEND:
923                         $dir_icon = 'images/lrarrow.gif';
924                         $alt_text = t('Mutual Friendship');
925                         break;
926                 case CONTACT_IS_FOLLOWER;
927                         $dir_icon = 'images/larrow.gif';
928                         $alt_text = t('is a fan of yours');
929                         break;
930                 case CONTACT_IS_SHARING;
931                         $dir_icon = 'images/rarrow.gif';
932                         $alt_text = t('you are a fan of');
933                         break;
934                 default:
935                         break;
936         }
937         if (($rr['network'] === NETWORK_DFRN) && ($rr['rel'])) {
938                 $url = "redir/{$rr['id']}";
939                 $sparkle = ' class="sparkle" ';
940         } else {
941                 $url = $rr['url'];
942                 $sparkle = '';
943         }
944
945         return array(
946                 'img_hover' => t('Visit %s\'s profile [%s]', $rr['name'], $rr['url']),
947                 'edit_hover' => t('Edit contact'),
948                 'photo_menu' => Contact::photoMenu($rr),
949                 'id' => $rr['id'],
950                 'alt_text' => $alt_text,
951                 'dir_icon' => $dir_icon,
952                 'thumb' => proxy_url($rr['thumb'], false, PROXY_SIZE_THUMB),
953                 'name' => htmlentities($rr['name']),
954                 'username' => htmlentities($rr['name']),
955                 'account_type' => Contact::getAccountType($rr),
956                 'sparkle' => $sparkle,
957                 'itemurl' => (($rr['addr'] != "") ? $rr['addr'] : $rr['url']),
958                 'url' => $url,
959                 'network' => ContactSelector::networkToName($rr['network'], $rr['url']),
960         );
961 }
962
963 /**
964  * @brief Gives a array with actions which can performed to a given contact
965  *
966  * This includes actions like e.g. 'block', 'hide', 'archive', 'delete' and others
967  *
968  * @param array $contact Data about the Contact
969  * @return array with contact related actions
970  */
971 function contact_actions($contact)
972 {
973         $poll_enabled = in_array($contact['network'], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_FEED, NETWORK_MAIL));
974         $contact_actions = array();
975
976         // Provide friend suggestion only for Friendica contacts
977         if ($contact['network'] === NETWORK_DFRN) {
978                 $contact_actions['suggest'] = array(
979                         'label' => t('Suggest friends'),
980                         'url'   => 'fsuggest/' . $contact['id'],
981                         'title' => '',
982                         'sel'   => '',
983                         'id'    => 'suggest',
984                 );
985         }
986
987         if ($poll_enabled) {
988                 $contact_actions['update'] = array(
989                         'label' => t('Update now'),
990                         'url'   => 'contacts/' . $contact['id'] . '/update',
991                         'title' => '',
992                         'sel'   => '',
993                         'id'    => 'update',
994                 );
995         }
996
997         $contact_actions['block'] = array(
998                 'label' => (intval($contact['blocked']) ? t('Unblock') : t('Block') ),
999                 'url'   => 'contacts/' . $contact['id'] . '/block',
1000                 'title' => t('Toggle Blocked status'),
1001                 'sel'   => (intval($contact['blocked']) ? 'active' : ''),
1002                 'id'    => 'toggle-block',
1003         );
1004
1005         $contact_actions['ignore'] = array(
1006                 'label' => (intval($contact['readonly']) ? t('Unignore') : t('Ignore') ),
1007                 'url'   => 'contacts/' . $contact['id'] . '/ignore',
1008                 'title' => t('Toggle Ignored status'),
1009                 'sel'   => (intval($contact['readonly']) ? 'active' : ''),
1010                 'id'    => 'toggle-ignore',
1011         );
1012
1013         $contact_actions['archive'] = array(
1014                 'label' => (intval($contact['archive']) ? t('Unarchive') : t('Archive') ),
1015                 'url'   => 'contacts/' . $contact['id'] . '/archive',
1016                 'title' => t('Toggle Archive status'),
1017                 'sel'   => (intval($contact['archive']) ? 'active' : ''),
1018                 'id'    => 'toggle-archive',
1019         );
1020
1021         $contact_actions['delete'] = array(
1022                 'label' => t('Delete'),
1023                 'url'   => 'contacts/' . $contact['id'] . '/drop',
1024                 'title' => t('Delete contact'),
1025                 'sel'   => '',
1026                 'id'    => 'delete',
1027         );
1028
1029         return $contact_actions;
1030 }