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