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