3 * @file mod/contacts.php
6 use Friendica\Content\ContactSelector;
7 use Friendica\Content\Widget;
8 use Friendica\Core\System;
9 use Friendica\Core\Worker;
10 use Friendica\Database\DBM;
11 use Friendica\Model\Contact;
12 use Friendica\Model\GContact;
13 use Friendica\Model\Group;
14 use Friendica\Model\Profile;
15 use Friendica\Network\Probe;
17 require_once 'mod/proxy.php';
19 function contacts_init(App $a)
25 $nets = defaults($_GET, 'nets', '');
30 if (!x($a->page, 'aside')) {
31 $a->page['aside'] = '';
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::selectFirst('contact', [], ['id' => $contact_id, 'uid' => local_user()]);
41 if (DBM::is_result($contact)) {
42 $a->data['contact'] = $contact;
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']);
50 /// @TODO Add nice spaces
51 $vcard_widget = replace_macros(get_markup_template("vcard-widget.tpl"), [
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'])
61 $findpeople_widget = '';
63 $networks_widget = '';
66 $networks_widget = Widget::networks('contacts', $nets);
67 if (isset($_GET['add'])) {
68 $follow_widget = Widget::follow($_GET['add']);
70 $follow_widget = Widget::follow();
73 $findpeople_widget = Widget::findPeople();
76 $groups_widget = Group::sidebarWidget('contacts', 'group', 'full', 0, $contact_id);
78 $a->page['aside'] .= replace_macros(get_markup_template("contacts-widget-sidebar.tpl"), [
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
86 $base = System::baseUrl();
87 $tpl = get_markup_template("contacts-head.tpl");
88 $a->page['htmlhead'] .= replace_macros($tpl, [
89 '$baseurl' => System::baseUrl(true),
93 $tpl = get_markup_template("contacts-end.tpl");
94 $a->page['end'] .= replace_macros($tpl, [
95 '$baseurl' => System::baseUrl(true),
100 function contacts_batch_actions(App $a)
102 $contacts_id = $_POST['contact_batch'];
103 if (!is_array($contacts_id)) {
107 $orig_records = q("SELECT * FROM `contact` WHERE `id` IN (%s) AND `uid` = %d AND `self` = 0",
108 implode(",", $contacts_id),
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);
119 if (x($_POST, 'contacts_batch_block')) {
120 $r = _contact_block($contact_id, $orig_record);
125 if (x($_POST, 'contacts_batch_ignore')) {
126 $r = _contact_ignore($contact_id, $orig_record);
131 if (x($_POST, 'contacts_batch_archive')) {
132 $r = _contact_archive($contact_id, $orig_record);
137 if (x($_POST, 'contacts_batch_drop')) {
138 _contact_drop($orig_record);
142 if ($count_actions > 0) {
143 info(tt("%d contact edited.", "%d contacts edited.", $count_actions));
146 if (x($_SESSION, 'return_url')) {
147 goaway('' . $_SESSION['return_url']);
153 function contacts_post(App $a)
159 if ($a->argv[1] === "batch") {
160 contacts_batch_actions($a);
164 $contact_id = intval($a->argv[1]);
169 if (!dba::exists('contact', ['id' => $contact_id, 'uid' => local_user()])) {
170 notice(t('Could not access contact record.') . EOL);
172 return; // NOTREACHED
175 call_hooks('contact_edit_post', $_POST);
177 $profile_id = intval($_POST['profile-assign']);
179 if (!dba::exists('profile', ['id' => $profile_id, 'uid' => local_user()])) {
180 notice(t('Could not locate selected profile.') . EOL);
185 $hidden = intval($_POST['hidden']);
187 $notify = intval($_POST['notify']);
189 $fetch_further_information = intval($_POST['fetch_further_information']);
191 $ffi_keyword_blacklist = escape_tags(trim($_POST['ffi_keyword_blacklist']));
193 $priority = intval($_POST['poll']);
194 if ($priority > 5 || $priority < 0) {
198 $info = escape_tags(trim($_POST['info']));
200 $r = q("UPDATE `contact` SET `profile-id` = %d, `priority` = %d , `info` = '%s',
201 `hidden` = %d, `notify_new_posts` = %d, `fetch_further_information` = %d,
202 `ffi_keyword_blacklist` = '%s' WHERE `id` = %d AND `uid` = %d",
208 intval($fetch_further_information),
209 dbesc($ffi_keyword_blacklist),
213 if (DBM::is_result($r)) {
214 info(t('Contact updated.') . EOL);
216 notice(t('Failed to update contact record.') . EOL);
219 $contact = dba::selectFirst('contact', [], ['id' => $contact_id, 'uid' => local_user()]);
220 if (DBM::is_result($contact)) {
221 $a->data['contact'] = $contact;
227 /* contact actions */
229 function _contact_update($contact_id)
231 $contact = dba::selectFirst('contact', ['uid', 'url', 'network'], ['id' => $contact_id, 'uid' => local_user()]);
232 if (!DBM::is_result($contact)) {
236 $uid = $contact["uid"];
238 if ($contact["network"] == NETWORK_OSTATUS) {
239 $result = Contact::createFromProbe($uid, $contact["url"], false, $contact["network"]);
241 if ($result['success']) {
242 q("UPDATE `contact` SET `subhub` = 1 WHERE `id` = %d", intval($contact_id));
245 // pull feed and consume it, which should subscribe to the hub.
246 Worker::add(PRIORITY_HIGH, "OnePoll", $contact_id, "force");
250 function _contact_update_profile($contact_id)
252 $contact = dba::selectFirst('contact', ['uid', 'url', 'network'], ['id' => $contact_id, 'uid' => local_user()]);
253 if (!DBM::is_result($contact)) {
257 $uid = $contact["uid"];
259 $data = Probe::uri($contact["url"], "", 0, false);
261 // "Feed" or "Unknown" is mostly a sign of communication problems
262 if ((in_array($data["network"], [NETWORK_FEED, NETWORK_PHANTOM])) && ($data["network"] != $contact["network"])) {
266 $updatefields = ["name", "nick", "url", "addr", "batch", "notify", "poll", "request", "confirm",
267 "poco", "network", "alias"];
270 if ($data["network"] == NETWORK_OSTATUS) {
271 $result = Contact::createFromProbe($uid, $data["url"], false);
273 if ($result['success']) {
274 $update["subhub"] = true;
278 foreach ($updatefields AS $field) {
279 if (isset($data[$field]) && ($data[$field] != "")) {
280 $update[$field] = $data[$field];
284 $update["nurl"] = normalise_link($data["url"]);
288 if (isset($data["priority"]) && ($data["priority"] != 0)) {
289 $query = "`priority` = " . intval($data["priority"]);
292 foreach ($update AS $key => $value) {
297 $query .= "`" . $key . "` = '" . dbesc($value) . "'";
304 $r = q("UPDATE `contact` SET $query WHERE `id` = %d AND `uid` = %d",
309 // Update the entry in the contact table
310 Contact::updateAvatar($data['photo'], local_user(), $contact_id, true);
312 // Update the entry in the gcontact table
313 GContact::updateFromProbe($data["url"]);
316 function _contact_block($contact_id, $orig_record)
318 $blocked = (($orig_record['blocked']) ? 0 : 1);
319 $r = q("UPDATE `contact` SET `blocked` = %d WHERE `id` = %d AND `uid` = %d",
324 return DBM::is_result($r);
327 function _contact_ignore($contact_id, $orig_record)
329 $readonly = (($orig_record['readonly']) ? 0 : 1);
330 $r = q("UPDATE `contact` SET `readonly` = %d WHERE `id` = %d AND `uid` = %d",
335 return DBM::is_result($r);
338 function _contact_archive($contact_id, $orig_record)
340 $archived = (($orig_record['archive']) ? 0 : 1);
341 $r = q("UPDATE `contact` SET `archive` = %d WHERE `id` = %d AND `uid` = %d",
347 q("UPDATE `item` SET `private` = 2 WHERE `contact-id` = %d AND `uid` = %d", intval($contact_id), intval(local_user()));
349 return DBM::is_result($r);
352 function _contact_drop($orig_record)
356 $r = q("SELECT `contact`.*, `user`.* FROM `contact` INNER JOIN `user` ON `contact`.`uid` = `user`.`uid`
357 WHERE `user`.`uid` = %d AND `contact`.`self` LIMIT 1",
358 intval($a->user['uid'])
360 if (!DBM::is_result($r)) {
364 Contact::terminateFriendship($r[0], $orig_record);
365 Contact::remove($orig_record['id']);
368 function contacts_content(App $a)
372 nav_set_selected('contacts');
375 notice(t('Permission denied.') . EOL);
380 $contact_id = intval($a->argv[1]);
387 $orig_record = dba::selectFirst('contact', [], ['id' => $contact_id, 'uid' => local_user(), 'self' => false]);
388 if (!DBM::is_result($orig_record)) {
389 notice(t('Could not access contact record.') . EOL);
391 return; // NOTREACHED
394 if ($cmd === 'update') {
395 _contact_update($contact_id);
396 goaway('contacts/' . $contact_id);
400 if ($cmd === 'updateprofile') {
401 _contact_update_profile($contact_id);
402 goaway('crepair/' . $contact_id);
406 if ($cmd === 'block') {
407 $r = _contact_block($contact_id, $orig_record);
409 $blocked = (($orig_record['blocked']) ? 0 : 1);
410 info((($blocked) ? t('Contact has been blocked') : t('Contact has been unblocked')) . EOL);
413 goaway('contacts/' . $contact_id);
414 return; // NOTREACHED
417 if ($cmd === 'ignore') {
418 $r = _contact_ignore($contact_id, $orig_record);
420 $readonly = (($orig_record['readonly']) ? 0 : 1);
421 info((($readonly) ? t('Contact has been ignored') : t('Contact has been unignored')) . EOL);
424 goaway('contacts/' . $contact_id);
425 return; // NOTREACHED
428 if ($cmd === 'archive') {
429 $r = _contact_archive($contact_id, $orig_record);
431 $archived = (($orig_record['archive']) ? 0 : 1);
432 info((($archived) ? t('Contact has been archived') : t('Contact has been unarchived')) . EOL);
435 goaway('contacts/' . $contact_id);
436 return; // NOTREACHED
439 if ($cmd === 'drop') {
440 // Check if we should do HTML-based delete confirmation
441 if (x($_REQUEST, 'confirm')) {
442 // <form> can't take arguments in its "action" parameter
443 // so add any arguments as hidden inputs
444 $query = explode_querystring($a->query_string);
446 foreach ($query['args'] as $arg) {
447 if (strpos($arg, 'confirm=') === false) {
448 $arg_parts = explode('=', $arg);
449 $inputs[] = ['name' => $arg_parts[0], 'value' => $arg_parts[1]];
453 $a->page['aside'] = '';
455 return replace_macros(get_markup_template('contact_drop_confirm.tpl'), [
456 '$header' => t('Drop contact'),
457 '$contact' => _contact_detail_for_template($orig_record),
459 '$message' => t('Do you really want to delete this contact?'),
460 '$extra_inputs' => $inputs,
461 '$confirm' => t('Yes'),
462 '$confirm_url' => $query['base'],
463 '$confirm_name' => 'confirmed',
464 '$cancel' => t('Cancel'),
467 // Now check how the user responded to the confirmation query
468 if (x($_REQUEST, 'canceled')) {
469 if (x($_SESSION, 'return_url')) {
470 goaway('' . $_SESSION['return_url']);
476 _contact_drop($orig_record);
477 info(t('Contact has been removed.') . EOL);
478 if (x($_SESSION, 'return_url')) {
479 goaway('' . $_SESSION['return_url']);
483 return; // NOTREACHED
485 if ($cmd === 'posts') {
486 return contact_posts($a, $contact_id);
490 $_SESSION['return_url'] = $a->query_string;
492 if ((x($a->data, 'contact')) && (is_array($a->data['contact']))) {
493 $contact_id = $a->data['contact']['id'];
494 $contact = $a->data['contact'];
496 $a->page['htmlhead'] .= replace_macros(get_markup_template('contact_head.tpl'), [
497 '$baseurl' => System::baseUrl(true),
499 $a->page['end'] .= replace_macros(get_markup_template('contact_end.tpl'), [
500 '$baseurl' => System::baseUrl(true),
505 switch ($contact['rel']) {
506 case CONTACT_IS_FRIEND:
507 $dir_icon = 'images/lrarrow.gif';
508 $relation_text = t('You are mutual friends with %s');
510 case CONTACT_IS_FOLLOWER;
511 $dir_icon = 'images/larrow.gif';
512 $relation_text = t('You are sharing with %s');
514 case CONTACT_IS_SHARING;
515 $dir_icon = 'images/rarrow.gif';
516 $relation_text = t('%s is sharing with you');
522 if (!in_array($contact['network'], [NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_DIASPORA])) {
526 $relation_text = sprintf($relation_text, htmlentities($contact['name']));
528 if (($contact['network'] === NETWORK_DFRN) && ($contact['rel'])) {
529 $url = "redir/{$contact['id']}";
530 $sparkle = ' class="sparkle" ';
532 $url = $contact['url'];
536 $insecure = t('Private communications are not available for this contact.');
538 $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'));
540 if ($contact['last-update'] > NULL_DATE) {
541 $last_update .= ' ' . (($contact['last-update'] <= $contact['success_update']) ? t("\x28Update was successful\x29") : t("\x28Update was not successful\x29"));
543 $lblsuggest = (($contact['network'] === NETWORK_DFRN) ? t('Suggest friends') : '');
545 $poll_enabled = in_array($contact['network'], [NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_FEED, NETWORK_MAIL]);
547 $nettype = t('Network type: %s', ContactSelector::networkToName($contact['network'], $contact["url"]));
550 $tab_str = contacts_tab($a, $contact_id, 2);
552 $lost_contact = (($contact['archive'] && $contact['term-date'] > NULL_DATE && $contact['term-date'] < datetime_convert('', '', 'now')) ? t('Communications lost with this contact!') : '');
554 $fetch_further_information = null;
555 if ($contact['network'] == NETWORK_FEED) {
556 $fetch_further_information = [
557 'fetch_further_information',
558 t('Fetch further information for feeds'),
559 $contact['fetch_further_information'],
560 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."),
561 ['0' => t('Disabled'),
562 '1' => t('Fetch information'),
563 '3' => t('Fetch keywords'),
564 '2' => t('Fetch information and keywords')
569 $poll_interval = null;
570 if (in_array($contact['network'], [NETWORK_FEED, NETWORK_MAIL])) {
571 $poll_interval = ContactSelector::pollInterval($contact['priority'], (!$poll_enabled));
574 $profile_select = null;
575 if ($contact['network'] == NETWORK_DFRN) {
576 $profile_select = ContactSelector::profileAssign($contact['profile-id'], (($contact['network'] !== NETWORK_DFRN) ? true : false));
581 if (in_array($contact['network'], [NETWORK_DIASPORA, NETWORK_OSTATUS])) {
582 if ($contact['rel'] == CONTACT_IS_FOLLOWER) {
583 $follow = System::baseUrl(true) . "/follow?url=" . urlencode($contact["url"]);
584 $follow_text = t("Connect/Follow");
585 } elseif ($contact['rel'] == CONTACT_IS_FRIEND) {
586 $follow = System::baseUrl(true) . "/unfollow?url=" . urlencode($contact["url"]);
587 $follow_text = t("Disconnect/Unfollow");
591 // Load contactact related actions like hide, suggest, delete and others
592 $contact_actions = contact_actions($contact);
594 $tpl = get_markup_template("contact_edit.tpl");
595 $o .= replace_macros($tpl, [
596 '$header' => t("Contact"),
597 '$tab_str' => $tab_str,
598 '$submit' => t('Submit'),
599 '$lbl_vis1' => t('Profile Visibility'),
600 '$lbl_vis2' => t('Please choose the profile you would like to display to %s when viewing your profile securely.', $contact['name']),
601 '$lbl_info1' => t('Contact Information / Notes'),
602 '$lbl_info2' => t('Their personal note'),
603 '$reason' => trim(notags($contact['reason'])),
604 '$infedit' => t('Edit contact notes'),
605 '$common_link' => 'common/loc/' . local_user() . '/' . $contact['id'],
606 '$relation_text' => $relation_text,
607 '$visit' => t('Visit %s\'s profile [%s]', $contact['name'], $contact['url']),
608 '$blockunblock' => t('Block/Unblock contact'),
609 '$ignorecont' => t('Ignore contact'),
610 '$lblcrepair' => t("Repair URL settings"),
611 '$lblrecent' => t('View conversations'),
612 '$lblsuggest' => $lblsuggest,
613 '$nettype' => $nettype,
614 '$poll_interval' => $poll_interval,
615 '$poll_enabled' => $poll_enabled,
616 '$lastupdtext' => t('Last update:'),
617 '$lost_contact' => $lost_contact,
618 '$updpub' => t('Update public posts'),
619 '$last_update' => $last_update,
620 '$udnow' => t('Update now'),
621 '$follow' => $follow,
622 '$follow_text' => $follow_text,
623 '$profile_select' => $profile_select,
624 '$contact_id' => $contact['id'],
625 '$block_text' => (($contact['blocked']) ? t('Unblock') : t('Block') ),
626 '$ignore_text' => (($contact['readonly']) ? t('Unignore') : t('Ignore') ),
627 '$insecure' => (($contact['network'] !== NETWORK_DFRN && $contact['network'] !== NETWORK_MAIL && $contact['network'] !== NETWORK_FACEBOOK && $contact['network'] !== NETWORK_DIASPORA) ? $insecure : ''),
628 '$info' => $contact['info'],
629 '$cinfo' => ['info', '', $contact['info'], ''],
630 '$blocked' => (($contact['blocked']) ? t('Currently blocked') : ''),
631 '$ignored' => (($contact['readonly']) ? t('Currently ignored') : ''),
632 '$archived' => (($contact['archive']) ? t('Currently archived') : ''),
633 '$pending' => (($contact['pending']) ? t('Awaiting connection acknowledge') : ''),
634 '$hidden' => ['hidden', t('Hide this contact from others'), ($contact['hidden'] == 1), t('Replies/likes to your public posts <strong>may</strong> still be visible')],
635 '$notify' => ['notify', t('Notification for new posts'), ($contact['notify_new_posts'] == 1), t('Send a notification of every new post of this contact')],
636 '$fetch_further_information' => $fetch_further_information,
637 '$ffi_keyword_blacklist' => $contact['ffi_keyword_blacklist'],
638 '$ffi_keyword_blacklist' => ['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')],
639 '$photo' => $contact['photo'],
640 '$name' => htmlentities($contact['name']),
641 '$dir_icon' => $dir_icon,
642 '$sparkle' => $sparkle,
644 '$profileurllabel' => t('Profile URL'),
645 '$profileurl' => $contact['url'],
646 '$account_type' => Contact::getAccountType($contact),
647 '$location' => bbcode($contact["location"]),
648 '$location_label' => t("Location:"),
649 '$xmpp' => bbcode($contact["xmpp"]),
650 '$xmpp_label' => t("XMPP:"),
651 '$about' => bbcode($contact["about"], false, false),
652 '$about_label' => t("About:"),
653 '$keywords' => $contact["keywords"],
654 '$keywords_label' => t("Tags:"),
655 '$contact_action_button' => t("Actions"),
656 '$contact_actions' => $contact_actions,
657 '$contact_status' => t("Status"),
658 '$contact_settings_label' => t('Contact Settings'),
659 '$contact_profile_label' => t("Profile"),
662 $arr = ['contact' => $contact, 'output' => $o];
664 call_hooks('contact_edit', $arr);
666 return $arr['output'];
675 if (($a->argc == 2) && ($a->argv[1] === 'all')) {
678 } elseif (($a->argc == 2) && ($a->argv[1] === 'blocked')) {
679 $sql_extra = " AND `blocked` = 1 ";
681 } elseif (($a->argc == 2) && ($a->argv[1] === 'hidden')) {
682 $sql_extra = " AND `hidden` = 1 ";
684 } elseif (($a->argc == 2) && ($a->argv[1] === 'ignored')) {
685 $sql_extra = " AND `readonly` = 1 ";
687 } elseif (($a->argc == 2) && ($a->argv[1] === 'archived')) {
688 $sql_extra = " AND `archive` = 1 ";
691 $sql_extra = " AND `blocked` = 0 ";
694 $search = x($_GET, 'search') ? notags(trim($_GET['search'])) : '';
695 $nets = x($_GET, 'nets' ) ? notags(trim($_GET['nets'])) : '';
699 'label' => t('Suggestions'),
702 'title' => t('Suggest potential friends'),
703 'id' => 'suggestions-tab',
707 'label' => t('All Contacts'),
708 'url' => 'contacts/all',
709 'sel' => ($all) ? 'active' : '',
710 'title' => t('Show all contacts'),
711 'id' => 'showall-tab',
715 'label' => t('Unblocked'),
717 'sel' => ((!$all) && (!$blocked) && (!$hidden) && (!$search) && (!$nets) && (!$ignored) && (!$archived)) ? 'active' : '',
718 'title' => t('Only show unblocked contacts'),
719 'id' => 'showunblocked-tab',
723 'label' => t('Blocked'),
724 'url' => 'contacts/blocked',
725 'sel' => ($blocked) ? 'active' : '',
726 'title' => t('Only show blocked contacts'),
727 'id' => 'showblocked-tab',
731 'label' => t('Ignored'),
732 'url' => 'contacts/ignored',
733 'sel' => ($ignored) ? 'active' : '',
734 'title' => t('Only show ignored contacts'),
735 'id' => 'showignored-tab',
739 'label' => t('Archived'),
740 'url' => 'contacts/archived',
741 'sel' => ($archived) ? 'active' : '',
742 'title' => t('Only show archived contacts'),
743 'id' => 'showarchived-tab',
747 'label' => t('Hidden'),
748 'url' => 'contacts/hidden',
749 'sel' => ($hidden) ? 'active' : '',
750 'title' => t('Only show hidden contacts'),
751 'id' => 'showhidden-tab',
756 $tab_tpl = get_markup_template('common_tabs.tpl');
757 $t = replace_macros($tab_tpl, ['$tabs' => $tabs]);
764 $search_hdr = $search;
765 $search_txt = dbesc(protect_sprintf(preg_quote($search)));
766 $sql_extra .= " AND (name REGEXP '$search_txt' OR url REGEXP '$search_txt' OR nick REGEXP '$search_txt') ";
770 $sql_extra .= sprintf(" AND network = '%s' ", dbesc($nets));
773 $sql_extra2 = ((($sort_type > 0) && ($sort_type <= CONTACT_IS_FRIEND)) ? sprintf(" AND `rel` = %d ", intval($sort_type)) : '');
775 $r = q("SELECT COUNT(*) AS `total` FROM `contact`
776 WHERE `uid` = %d AND `self` = 0 AND `pending` = 0 $sql_extra $sql_extra2 ",
777 intval($_SESSION['uid'])
779 if (DBM::is_result($r)) {
780 $a->set_pager_total($r[0]['total']);
781 $total = $r[0]['total'];
784 $sql_extra3 = Widget::unavailableNetworks();
788 $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 ",
789 intval($_SESSION['uid']),
790 intval($a->pager['start']),
791 intval($a->pager['itemspage'])
793 if (DBM::is_result($r)) {
794 foreach ($r as $rr) {
795 $contacts[] = _contact_detail_for_template($rr);
799 $tpl = get_markup_template("contacts-template.tpl");
800 $o .= replace_macros($tpl, [
801 '$baseurl' => System::baseUrl(),
802 '$header' => t('Contacts') . (($nets) ? ' - ' . ContactSelector::networkToName($nets) : ''),
805 '$search' => $search_hdr,
806 '$desc' => t('Search your contacts'),
807 '$finding' => $searching ? t('Results for: %s', $search) : "",
808 '$submit' => t('Find'),
810 '$contacts' => $contacts,
811 '$contact_drop_confirm' => t('Do you really want to delete this contact?'),
813 '$batch_actions' => [
814 'contacts_batch_update' => t('Update'),
815 'contacts_batch_block' => t('Block') . "/" . t("Unblock"),
816 "contacts_batch_ignore" => t('Ignore') . "/" . t("Unignore"),
817 "contacts_batch_archive" => t('Archive') . "/" . t("Unarchive"),
818 "contacts_batch_drop" => t('Delete'),
820 '$h_batch_actions' => t('Batch Actions'),
821 '$paginate' => paginate($a),
828 * @brief List of pages for the Contact TabBar
830 * Available Pages are 'Status', 'Profile', 'Contacts' and 'Common Friends'
833 * @param int $contact_id The ID of the contact
834 * @param int $active_tab 1 if tab should be marked as active
838 function contacts_tab($a, $contact_id, $active_tab)
843 'label' => t('Status'),
844 'url' => "contacts/" . $contact_id . "/posts",
845 'sel' => (($active_tab == 1) ? 'active' : ''),
846 'title' => t('Status Messages and Posts'),
847 'id' => 'status-tab',
851 'label' => t('Profile'),
852 'url' => "contacts/" . $contact_id,
853 'sel' => (($active_tab == 2) ? 'active' : ''),
854 'title' => t('Profile Details'),
855 'id' => 'profile-tab',
860 // Show this tab only if there is visible friend list
861 $x = GContact::countAllFriends(local_user(), $contact_id);
863 $tabs[] = ['label' => t('Contacts'),
864 'url' => "allfriends/" . $contact_id,
865 'sel' => (($active_tab == 3) ? 'active' : ''),
866 'title' => t('View all contacts'),
867 'id' => 'allfriends-tab',
871 // Show this tab only if there is visible common friend list
872 $common = GContact::countCommonFriends(local_user(), $contact_id);
874 $tabs[] = ['label' => t('Common Friends'),
875 'url' => "common/loc/" . local_user() . "/" . $contact_id,
876 'sel' => (($active_tab == 4) ? 'active' : ''),
877 'title' => t('View all common friends'),
878 'id' => 'common-loc-tab',
883 $tabs[] = ['label' => t('Advanced'),
884 'url' => 'crepair/' . $contact_id,
885 'sel' => (($active_tab == 5) ? 'active' : ''),
886 'title' => t('Advanced Contact Settings'),
887 'id' => 'advanced-tab',
891 $tab_tpl = get_markup_template('common_tabs.tpl');
892 $tab_str = replace_macros($tab_tpl, ['$tabs' => $tabs]);
897 function contact_posts($a, $contact_id)
899 $o = contacts_tab($a, $contact_id, 1);
901 $contact = dba::selectFirst('contact', ['url'], ['id' => $contact_id]);
902 if (DBM::is_result($contact)) {
903 $a->page['aside'] = "";
904 Profile::load($a, "", 0, Contact::getDetailsByURL($contact["url"]));
905 $o .= Contact::getPostsFromUrl($contact["url"]);
911 function _contact_detail_for_template($rr)
915 switch ($rr['rel']) {
916 case CONTACT_IS_FRIEND:
917 $dir_icon = 'images/lrarrow.gif';
918 $alt_text = t('Mutual Friendship');
920 case CONTACT_IS_FOLLOWER;
921 $dir_icon = 'images/larrow.gif';
922 $alt_text = t('is a fan of yours');
924 case CONTACT_IS_SHARING;
925 $dir_icon = 'images/rarrow.gif';
926 $alt_text = t('you are a fan of');
931 if (($rr['network'] === NETWORK_DFRN) && ($rr['rel'])) {
932 $url = "redir/{$rr['id']}";
933 $sparkle = ' class="sparkle" ';
940 'img_hover' => t('Visit %s\'s profile [%s]', $rr['name'], $rr['url']),
941 'edit_hover' => t('Edit contact'),
942 'photo_menu' => Contact::photoMenu($rr),
944 'alt_text' => $alt_text,
945 'dir_icon' => $dir_icon,
946 'thumb' => proxy_url($rr['thumb'], false, PROXY_SIZE_THUMB),
947 'name' => htmlentities($rr['name']),
948 'username' => htmlentities($rr['name']),
949 'account_type' => Contact::getAccountType($rr),
950 'sparkle' => $sparkle,
951 'itemurl' => (($rr['addr'] != "") ? $rr['addr'] : $rr['url']),
953 'network' => ContactSelector::networkToName($rr['network'], $rr['url']),
958 * @brief Gives a array with actions which can performed to a given contact
960 * This includes actions like e.g. 'block', 'hide', 'archive', 'delete' and others
962 * @param array $contact Data about the Contact
963 * @return array with contact related actions
965 function contact_actions($contact)
967 $poll_enabled = in_array($contact['network'], [NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_FEED, NETWORK_MAIL]);
968 $contact_actions = [];
970 // Provide friend suggestion only for Friendica contacts
971 if ($contact['network'] === NETWORK_DFRN) {
972 $contact_actions['suggest'] = [
973 'label' => t('Suggest friends'),
974 'url' => 'fsuggest/' . $contact['id'],
982 $contact_actions['update'] = [
983 'label' => t('Update now'),
984 'url' => 'contacts/' . $contact['id'] . '/update',
991 $contact_actions['block'] = [
992 'label' => (intval($contact['blocked']) ? t('Unblock') : t('Block') ),
993 'url' => 'contacts/' . $contact['id'] . '/block',
994 'title' => t('Toggle Blocked status'),
995 'sel' => (intval($contact['blocked']) ? 'active' : ''),
996 'id' => 'toggle-block',
999 $contact_actions['ignore'] = [
1000 'label' => (intval($contact['readonly']) ? t('Unignore') : t('Ignore') ),
1001 'url' => 'contacts/' . $contact['id'] . '/ignore',
1002 'title' => t('Toggle Ignored status'),
1003 'sel' => (intval($contact['readonly']) ? 'active' : ''),
1004 'id' => 'toggle-ignore',
1007 $contact_actions['archive'] = [
1008 'label' => (intval($contact['archive']) ? t('Unarchive') : t('Archive') ),
1009 'url' => 'contacts/' . $contact['id'] . '/archive',
1010 'title' => t('Toggle Archive status'),
1011 'sel' => (intval($contact['archive']) ? 'active' : ''),
1012 'id' => 'toggle-archive',
1015 $contact_actions['delete'] = [
1016 'label' => t('Delete'),
1017 'url' => 'contacts/' . $contact['id'] . '/drop',
1018 'title' => t('Delete contact'),
1023 return $contact_actions;