3 * @file mod/contacts.php
6 use Friendica\Content\ContactSelector;
7 use Friendica\Content\Nav;
8 use Friendica\Content\Widget;
9 use Friendica\Core\System;
10 use Friendica\Core\Worker;
11 use Friendica\Database\DBM;
12 use Friendica\Model\Contact;
13 use Friendica\Model\GContact;
14 use Friendica\Model\Group;
15 use Friendica\Model\Profile;
16 use Friendica\Network\Probe;
18 require_once 'mod/proxy.php';
20 function contacts_init(App $a)
26 $nets = defaults($_GET, 'nets', '');
31 if (!x($a->page, 'aside')) {
32 $a->page['aside'] = '';
37 if ((($a->argc == 2) && intval($a->argv[1])) || (($a->argc == 3) && intval($a->argv[1]) && ($a->argv[2] == "posts"))) {
38 $contact_id = intval($a->argv[1]);
39 $contact = dba::selectFirst('contact', [], ['id' => $contact_id, 'uid' => local_user()]);
42 if (DBM::is_result($contact)) {
43 $a->data['contact'] = $contact;
45 if (($a->data['contact']['network'] != "") && ($a->data['contact']['network'] != NETWORK_DFRN)) {
46 $networkname = format_network_name($a->data['contact']['network'], $a->data['contact']['url']);
51 /// @TODO Add nice spaces
52 $vcard_widget = replace_macros(get_markup_template("vcard-widget.tpl"), [
53 '$name' => htmlentities($a->data['contact']['name']),
54 '$photo' => $a->data['contact']['photo'],
55 '$url' => ($a->data['contact']['network'] == NETWORK_DFRN) ? "redir/" . $a->data['contact']['id'] : $a->data['contact']['url'],
56 '$addr' => (($a->data['contact']['addr'] != "") ? ($a->data['contact']['addr']) : ""),
57 '$network_name' => $networkname,
58 '$network' => t('Network:'),
59 '$account_type' => Contact::getAccountType($a->data['contact'])
62 $findpeople_widget = '';
64 $networks_widget = '';
67 $networks_widget = Widget::networks('contacts', $nets);
68 if (isset($_GET['add'])) {
69 $follow_widget = Widget::follow($_GET['add']);
71 $follow_widget = Widget::follow();
74 $findpeople_widget = Widget::findPeople();
77 $groups_widget = Group::sidebarWidget('contacts', 'group', 'full', 0, $contact_id);
79 $a->page['aside'] .= replace_macros(get_markup_template("contacts-widget-sidebar.tpl"), [
80 '$vcard_widget' => $vcard_widget,
81 '$findpeople_widget' => $findpeople_widget,
82 '$follow_widget' => $follow_widget,
83 '$groups_widget' => $groups_widget,
84 '$networks_widget' => $networks_widget
87 $base = System::baseUrl();
88 $tpl = get_markup_template("contacts-head.tpl");
89 $a->page['htmlhead'] .= replace_macros($tpl, [
90 '$baseurl' => System::baseUrl(true),
94 $tpl = get_markup_template("contacts-end.tpl");
95 $a->page['end'] .= replace_macros($tpl, [
96 '$baseurl' => System::baseUrl(true),
101 function contacts_batch_actions(App $a)
103 $contacts_id = $_POST['contact_batch'];
104 if (!is_array($contacts_id)) {
108 $orig_records = q("SELECT * FROM `contact` WHERE `id` IN (%s) AND `uid` = %d AND `self` = 0",
109 implode(",", $contacts_id),
114 foreach ($orig_records as $orig_record) {
115 $contact_id = $orig_record['id'];
116 if (x($_POST, 'contacts_batch_update')) {
117 _contact_update($contact_id);
120 if (x($_POST, 'contacts_batch_block')) {
121 $r = _contact_block($contact_id, $orig_record);
126 if (x($_POST, 'contacts_batch_ignore')) {
127 $r = _contact_ignore($contact_id, $orig_record);
132 if (x($_POST, 'contacts_batch_archive')) {
133 $r = _contact_archive($contact_id, $orig_record);
138 if (x($_POST, 'contacts_batch_drop')) {
139 _contact_drop($orig_record);
143 if ($count_actions > 0) {
144 info(tt("%d contact edited.", "%d contacts edited.", $count_actions));
147 if (x($_SESSION, 'return_url')) {
148 goaway('' . $_SESSION['return_url']);
154 function contacts_post(App $a)
160 if ($a->argv[1] === "batch") {
161 contacts_batch_actions($a);
165 $contact_id = intval($a->argv[1]);
170 if (!dba::exists('contact', ['id' => $contact_id, 'uid' => local_user()])) {
171 notice(t('Could not access contact record.') . EOL);
173 return; // NOTREACHED
176 call_hooks('contact_edit_post', $_POST);
178 $profile_id = intval($_POST['profile-assign']);
180 if (!dba::exists('profile', ['id' => $profile_id, 'uid' => local_user()])) {
181 notice(t('Could not locate selected profile.') . EOL);
186 $hidden = intval($_POST['hidden']);
188 $notify = intval($_POST['notify']);
190 $fetch_further_information = intval($_POST['fetch_further_information']);
192 $ffi_keyword_blacklist = escape_tags(trim($_POST['ffi_keyword_blacklist']));
194 $priority = intval($_POST['poll']);
195 if ($priority > 5 || $priority < 0) {
199 $info = escape_tags(trim($_POST['info']));
201 $r = q("UPDATE `contact` SET `profile-id` = %d, `priority` = %d , `info` = '%s',
202 `hidden` = %d, `notify_new_posts` = %d, `fetch_further_information` = %d,
203 `ffi_keyword_blacklist` = '%s' WHERE `id` = %d AND `uid` = %d",
209 intval($fetch_further_information),
210 dbesc($ffi_keyword_blacklist),
214 if (DBM::is_result($r)) {
215 info(t('Contact updated.') . EOL);
217 notice(t('Failed to update contact record.') . EOL);
220 $contact = dba::selectFirst('contact', [], ['id' => $contact_id, 'uid' => local_user()]);
221 if (DBM::is_result($contact)) {
222 $a->data['contact'] = $contact;
228 /* contact actions */
230 function _contact_update($contact_id)
232 $contact = dba::selectFirst('contact', ['uid', 'url', 'network'], ['id' => $contact_id, 'uid' => local_user()]);
233 if (!DBM::is_result($contact)) {
237 $uid = $contact["uid"];
239 if ($contact["network"] == NETWORK_OSTATUS) {
240 $result = Contact::createFromProbe($uid, $contact["url"], false, $contact["network"]);
242 if ($result['success']) {
243 q("UPDATE `contact` SET `subhub` = 1 WHERE `id` = %d", intval($contact_id));
246 // pull feed and consume it, which should subscribe to the hub.
247 Worker::add(PRIORITY_HIGH, "OnePoll", $contact_id, "force");
251 function _contact_update_profile($contact_id)
253 $contact = dba::selectFirst('contact', ['uid', 'url', 'network'], ['id' => $contact_id, 'uid' => local_user()]);
254 if (!DBM::is_result($contact)) {
258 $uid = $contact["uid"];
260 $data = Probe::uri($contact["url"], "", 0, false);
262 // "Feed" or "Unknown" is mostly a sign of communication problems
263 if ((in_array($data["network"], [NETWORK_FEED, NETWORK_PHANTOM])) && ($data["network"] != $contact["network"])) {
267 $updatefields = ["name", "nick", "url", "addr", "batch", "notify", "poll", "request", "confirm",
268 "poco", "network", "alias"];
271 if ($data["network"] == NETWORK_OSTATUS) {
272 $result = Contact::createFromProbe($uid, $data["url"], false);
274 if ($result['success']) {
275 $update["subhub"] = true;
279 foreach ($updatefields AS $field) {
280 if (isset($data[$field]) && ($data[$field] != "")) {
281 $update[$field] = $data[$field];
285 $update["nurl"] = normalise_link($data["url"]);
289 if (isset($data["priority"]) && ($data["priority"] != 0)) {
290 $query = "`priority` = " . intval($data["priority"]);
293 foreach ($update AS $key => $value) {
298 $query .= "`" . $key . "` = '" . dbesc($value) . "'";
305 $r = q("UPDATE `contact` SET $query WHERE `id` = %d AND `uid` = %d",
310 // Update the entry in the contact table
311 Contact::updateAvatar($data['photo'], local_user(), $contact_id, true);
313 // Update the entry in the gcontact table
314 GContact::updateFromProbe($data["url"]);
317 function _contact_block($contact_id, $orig_record)
319 $blocked = (($orig_record['blocked']) ? 0 : 1);
320 $r = q("UPDATE `contact` SET `blocked` = %d WHERE `id` = %d AND `uid` = %d",
325 return DBM::is_result($r);
328 function _contact_ignore($contact_id, $orig_record)
330 $readonly = (($orig_record['readonly']) ? 0 : 1);
331 $r = q("UPDATE `contact` SET `readonly` = %d WHERE `id` = %d AND `uid` = %d",
336 return DBM::is_result($r);
339 function _contact_archive($contact_id, $orig_record)
341 $archived = (($orig_record['archive']) ? 0 : 1);
342 $r = q("UPDATE `contact` SET `archive` = %d WHERE `id` = %d AND `uid` = %d",
348 q("UPDATE `item` SET `private` = 2 WHERE `contact-id` = %d AND `uid` = %d", intval($contact_id), intval(local_user()));
350 return DBM::is_result($r);
353 function _contact_drop($orig_record)
357 $r = q("SELECT `contact`.*, `user`.* FROM `contact` INNER JOIN `user` ON `contact`.`uid` = `user`.`uid`
358 WHERE `user`.`uid` = %d AND `contact`.`self` LIMIT 1",
359 intval($a->user['uid'])
361 if (!DBM::is_result($r)) {
365 Contact::terminateFriendship($r[0], $orig_record);
366 Contact::remove($orig_record['id']);
369 function contacts_content(App $a)
373 Nav::setSelected('contacts');
376 notice(t('Permission denied.') . EOL);
381 $contact_id = intval($a->argv[1]);
388 $orig_record = dba::selectFirst('contact', [], ['id' => $contact_id, 'uid' => local_user(), 'self' => false]);
389 if (!DBM::is_result($orig_record)) {
390 notice(t('Could not access contact record.') . EOL);
392 return; // NOTREACHED
395 if ($cmd === 'update') {
396 _contact_update($contact_id);
397 goaway('contacts/' . $contact_id);
401 if ($cmd === 'updateprofile') {
402 _contact_update_profile($contact_id);
403 goaway('crepair/' . $contact_id);
407 if ($cmd === 'block') {
408 $r = _contact_block($contact_id, $orig_record);
410 $blocked = (($orig_record['blocked']) ? 0 : 1);
411 info((($blocked) ? t('Contact has been blocked') : t('Contact has been unblocked')) . EOL);
414 goaway('contacts/' . $contact_id);
415 return; // NOTREACHED
418 if ($cmd === 'ignore') {
419 $r = _contact_ignore($contact_id, $orig_record);
421 $readonly = (($orig_record['readonly']) ? 0 : 1);
422 info((($readonly) ? t('Contact has been ignored') : t('Contact has been unignored')) . EOL);
425 goaway('contacts/' . $contact_id);
426 return; // NOTREACHED
429 if ($cmd === 'archive') {
430 $r = _contact_archive($contact_id, $orig_record);
432 $archived = (($orig_record['archive']) ? 0 : 1);
433 info((($archived) ? t('Contact has been archived') : t('Contact has been unarchived')) . EOL);
436 goaway('contacts/' . $contact_id);
437 return; // NOTREACHED
440 if ($cmd === 'drop') {
441 // Check if we should do HTML-based delete confirmation
442 if (x($_REQUEST, 'confirm')) {
443 // <form> can't take arguments in its "action" parameter
444 // so add any arguments as hidden inputs
445 $query = explode_querystring($a->query_string);
447 foreach ($query['args'] as $arg) {
448 if (strpos($arg, 'confirm=') === false) {
449 $arg_parts = explode('=', $arg);
450 $inputs[] = ['name' => $arg_parts[0], 'value' => $arg_parts[1]];
454 $a->page['aside'] = '';
456 return replace_macros(get_markup_template('contact_drop_confirm.tpl'), [
457 '$header' => t('Drop contact'),
458 '$contact' => _contact_detail_for_template($orig_record),
460 '$message' => t('Do you really want to delete this contact?'),
461 '$extra_inputs' => $inputs,
462 '$confirm' => t('Yes'),
463 '$confirm_url' => $query['base'],
464 '$confirm_name' => 'confirmed',
465 '$cancel' => t('Cancel'),
468 // Now check how the user responded to the confirmation query
469 if (x($_REQUEST, 'canceled')) {
470 if (x($_SESSION, 'return_url')) {
471 goaway('' . $_SESSION['return_url']);
477 _contact_drop($orig_record);
478 info(t('Contact has been removed.') . EOL);
479 if (x($_SESSION, 'return_url')) {
480 goaway('' . $_SESSION['return_url']);
484 return; // NOTREACHED
486 if ($cmd === 'posts') {
487 return contact_posts($a, $contact_id);
491 $_SESSION['return_url'] = $a->query_string;
493 if ((x($a->data, 'contact')) && (is_array($a->data['contact']))) {
494 $contact_id = $a->data['contact']['id'];
495 $contact = $a->data['contact'];
497 $a->page['htmlhead'] .= replace_macros(get_markup_template('contact_head.tpl'), [
498 '$baseurl' => System::baseUrl(true),
500 $a->page['end'] .= replace_macros(get_markup_template('contact_end.tpl'), [
501 '$baseurl' => System::baseUrl(true),
506 switch ($contact['rel']) {
507 case CONTACT_IS_FRIEND:
508 $dir_icon = 'images/lrarrow.gif';
509 $relation_text = t('You are mutual friends with %s');
511 case CONTACT_IS_FOLLOWER;
512 $dir_icon = 'images/larrow.gif';
513 $relation_text = t('You are sharing with %s');
515 case CONTACT_IS_SHARING;
516 $dir_icon = 'images/rarrow.gif';
517 $relation_text = t('%s is sharing with you');
523 if (!in_array($contact['network'], [NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_DIASPORA])) {
527 $relation_text = sprintf($relation_text, htmlentities($contact['name']));
529 if (($contact['network'] === NETWORK_DFRN) && ($contact['rel'])) {
530 $url = "redir/{$contact['id']}";
531 $sparkle = ' class="sparkle" ';
533 $url = $contact['url'];
537 $insecure = t('Private communications are not available for this contact.');
539 $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'));
541 if ($contact['last-update'] > NULL_DATE) {
542 $last_update .= ' ' . (($contact['last-update'] <= $contact['success_update']) ? t("\x28Update was successful\x29") : t("\x28Update was not successful\x29"));
544 $lblsuggest = (($contact['network'] === NETWORK_DFRN) ? t('Suggest friends') : '');
546 $poll_enabled = in_array($contact['network'], [NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_FEED, NETWORK_MAIL]);
548 $nettype = t('Network type: %s', ContactSelector::networkToName($contact['network'], $contact["url"]));
551 $tab_str = contacts_tab($a, $contact_id, 2);
553 $lost_contact = (($contact['archive'] && $contact['term-date'] > NULL_DATE && $contact['term-date'] < datetime_convert('', '', 'now')) ? t('Communications lost with this contact!') : '');
555 $fetch_further_information = null;
556 if ($contact['network'] == NETWORK_FEED) {
557 $fetch_further_information = [
558 'fetch_further_information',
559 t('Fetch further information for feeds'),
560 $contact['fetch_further_information'],
561 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."),
562 ['0' => t('Disabled'),
563 '1' => t('Fetch information'),
564 '3' => t('Fetch keywords'),
565 '2' => t('Fetch information and keywords')
570 $poll_interval = null;
571 if (in_array($contact['network'], [NETWORK_FEED, NETWORK_MAIL])) {
572 $poll_interval = ContactSelector::pollInterval($contact['priority'], (!$poll_enabled));
575 $profile_select = null;
576 if ($contact['network'] == NETWORK_DFRN) {
577 $profile_select = ContactSelector::profileAssign($contact['profile-id'], (($contact['network'] !== NETWORK_DFRN) ? true : false));
582 if (in_array($contact['network'], [NETWORK_DIASPORA, NETWORK_OSTATUS])) {
583 if ($contact['rel'] == CONTACT_IS_FOLLOWER) {
584 $follow = System::baseUrl(true) . "/follow?url=" . urlencode($contact["url"]);
585 $follow_text = t("Connect/Follow");
586 } elseif ($contact['rel'] == CONTACT_IS_FRIEND) {
587 $follow = System::baseUrl(true) . "/unfollow?url=" . urlencode($contact["url"]);
588 $follow_text = t("Disconnect/Unfollow");
592 // Load contactact related actions like hide, suggest, delete and others
593 $contact_actions = contact_actions($contact);
595 $tpl = get_markup_template("contact_edit.tpl");
596 $o .= replace_macros($tpl, [
597 '$header' => t("Contact"),
598 '$tab_str' => $tab_str,
599 '$submit' => t('Submit'),
600 '$lbl_vis1' => t('Profile Visibility'),
601 '$lbl_vis2' => t('Please choose the profile you would like to display to %s when viewing your profile securely.', $contact['name']),
602 '$lbl_info1' => t('Contact Information / Notes'),
603 '$lbl_info2' => t('Their personal note'),
604 '$reason' => trim(notags($contact['reason'])),
605 '$infedit' => t('Edit contact notes'),
606 '$common_link' => 'common/loc/' . local_user() . '/' . $contact['id'],
607 '$relation_text' => $relation_text,
608 '$visit' => t('Visit %s\'s profile [%s]', $contact['name'], $contact['url']),
609 '$blockunblock' => t('Block/Unblock contact'),
610 '$ignorecont' => t('Ignore contact'),
611 '$lblcrepair' => t("Repair URL settings"),
612 '$lblrecent' => t('View conversations'),
613 '$lblsuggest' => $lblsuggest,
614 '$nettype' => $nettype,
615 '$poll_interval' => $poll_interval,
616 '$poll_enabled' => $poll_enabled,
617 '$lastupdtext' => t('Last update:'),
618 '$lost_contact' => $lost_contact,
619 '$updpub' => t('Update public posts'),
620 '$last_update' => $last_update,
621 '$udnow' => t('Update now'),
622 '$follow' => $follow,
623 '$follow_text' => $follow_text,
624 '$profile_select' => $profile_select,
625 '$contact_id' => $contact['id'],
626 '$block_text' => (($contact['blocked']) ? t('Unblock') : t('Block') ),
627 '$ignore_text' => (($contact['readonly']) ? t('Unignore') : t('Ignore') ),
628 '$insecure' => (($contact['network'] !== NETWORK_DFRN && $contact['network'] !== NETWORK_MAIL && $contact['network'] !== NETWORK_FACEBOOK && $contact['network'] !== NETWORK_DIASPORA) ? $insecure : ''),
629 '$info' => $contact['info'],
630 '$cinfo' => ['info', '', $contact['info'], ''],
631 '$blocked' => (($contact['blocked']) ? t('Currently blocked') : ''),
632 '$ignored' => (($contact['readonly']) ? t('Currently ignored') : ''),
633 '$archived' => (($contact['archive']) ? t('Currently archived') : ''),
634 '$pending' => (($contact['pending']) ? t('Awaiting connection acknowledge') : ''),
635 '$hidden' => ['hidden', t('Hide this contact from others'), ($contact['hidden'] == 1), t('Replies/likes to your public posts <strong>may</strong> still be visible')],
636 '$notify' => ['notify', t('Notification for new posts'), ($contact['notify_new_posts'] == 1), t('Send a notification of every new post of this contact')],
637 '$fetch_further_information' => $fetch_further_information,
638 '$ffi_keyword_blacklist' => $contact['ffi_keyword_blacklist'],
639 '$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')],
640 '$photo' => $contact['photo'],
641 '$name' => htmlentities($contact['name']),
642 '$dir_icon' => $dir_icon,
643 '$sparkle' => $sparkle,
645 '$profileurllabel' => t('Profile URL'),
646 '$profileurl' => $contact['url'],
647 '$account_type' => Contact::getAccountType($contact),
648 '$location' => bbcode($contact["location"]),
649 '$location_label' => t("Location:"),
650 '$xmpp' => bbcode($contact["xmpp"]),
651 '$xmpp_label' => t("XMPP:"),
652 '$about' => bbcode($contact["about"], false, false),
653 '$about_label' => t("About:"),
654 '$keywords' => $contact["keywords"],
655 '$keywords_label' => t("Tags:"),
656 '$contact_action_button' => t("Actions"),
657 '$contact_actions' => $contact_actions,
658 '$contact_status' => t("Status"),
659 '$contact_settings_label' => t('Contact Settings'),
660 '$contact_profile_label' => t("Profile"),
663 $arr = ['contact' => $contact, 'output' => $o];
665 call_hooks('contact_edit', $arr);
667 return $arr['output'];
676 if (($a->argc == 2) && ($a->argv[1] === 'all')) {
679 } elseif (($a->argc == 2) && ($a->argv[1] === 'blocked')) {
680 $sql_extra = " AND `blocked` = 1 ";
682 } elseif (($a->argc == 2) && ($a->argv[1] === 'hidden')) {
683 $sql_extra = " AND `hidden` = 1 ";
685 } elseif (($a->argc == 2) && ($a->argv[1] === 'ignored')) {
686 $sql_extra = " AND `readonly` = 1 ";
688 } elseif (($a->argc == 2) && ($a->argv[1] === 'archived')) {
689 $sql_extra = " AND `archive` = 1 ";
692 $sql_extra = " AND `blocked` = 0 ";
695 $search = x($_GET, 'search') ? notags(trim($_GET['search'])) : '';
696 $nets = x($_GET, 'nets' ) ? notags(trim($_GET['nets'])) : '';
700 'label' => t('Suggestions'),
703 'title' => t('Suggest potential friends'),
704 'id' => 'suggestions-tab',
708 'label' => t('All Contacts'),
709 'url' => 'contacts/all',
710 'sel' => ($all) ? 'active' : '',
711 'title' => t('Show all contacts'),
712 'id' => 'showall-tab',
716 'label' => t('Unblocked'),
718 'sel' => ((!$all) && (!$blocked) && (!$hidden) && (!$search) && (!$nets) && (!$ignored) && (!$archived)) ? 'active' : '',
719 'title' => t('Only show unblocked contacts'),
720 'id' => 'showunblocked-tab',
724 'label' => t('Blocked'),
725 'url' => 'contacts/blocked',
726 'sel' => ($blocked) ? 'active' : '',
727 'title' => t('Only show blocked contacts'),
728 'id' => 'showblocked-tab',
732 'label' => t('Ignored'),
733 'url' => 'contacts/ignored',
734 'sel' => ($ignored) ? 'active' : '',
735 'title' => t('Only show ignored contacts'),
736 'id' => 'showignored-tab',
740 'label' => t('Archived'),
741 'url' => 'contacts/archived',
742 'sel' => ($archived) ? 'active' : '',
743 'title' => t('Only show archived contacts'),
744 'id' => 'showarchived-tab',
748 'label' => t('Hidden'),
749 'url' => 'contacts/hidden',
750 'sel' => ($hidden) ? 'active' : '',
751 'title' => t('Only show hidden contacts'),
752 'id' => 'showhidden-tab',
757 $tab_tpl = get_markup_template('common_tabs.tpl');
758 $t = replace_macros($tab_tpl, ['$tabs' => $tabs]);
765 $search_hdr = $search;
766 $search_txt = dbesc(protect_sprintf(preg_quote($search)));
767 $sql_extra .= " AND (name REGEXP '$search_txt' OR url REGEXP '$search_txt' OR nick REGEXP '$search_txt') ";
771 $sql_extra .= sprintf(" AND network = '%s' ", dbesc($nets));
774 $sql_extra2 = ((($sort_type > 0) && ($sort_type <= CONTACT_IS_FRIEND)) ? sprintf(" AND `rel` = %d ", intval($sort_type)) : '');
776 $r = q("SELECT COUNT(*) AS `total` FROM `contact`
777 WHERE `uid` = %d AND `self` = 0 AND `pending` = 0 $sql_extra $sql_extra2 ",
778 intval($_SESSION['uid'])
780 if (DBM::is_result($r)) {
781 $a->set_pager_total($r[0]['total']);
782 $total = $r[0]['total'];
785 $sql_extra3 = Widget::unavailableNetworks();
789 $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 ",
790 intval($_SESSION['uid']),
791 intval($a->pager['start']),
792 intval($a->pager['itemspage'])
794 if (DBM::is_result($r)) {
795 foreach ($r as $rr) {
796 $contacts[] = _contact_detail_for_template($rr);
800 $tpl = get_markup_template("contacts-template.tpl");
801 $o .= replace_macros($tpl, [
802 '$baseurl' => System::baseUrl(),
803 '$header' => t('Contacts') . (($nets) ? ' - ' . ContactSelector::networkToName($nets) : ''),
806 '$search' => $search_hdr,
807 '$desc' => t('Search your contacts'),
808 '$finding' => $searching ? t('Results for: %s', $search) : "",
809 '$submit' => t('Find'),
811 '$contacts' => $contacts,
812 '$contact_drop_confirm' => t('Do you really want to delete this contact?'),
814 '$batch_actions' => [
815 'contacts_batch_update' => t('Update'),
816 'contacts_batch_block' => t('Block') . "/" . t("Unblock"),
817 "contacts_batch_ignore" => t('Ignore') . "/" . t("Unignore"),
818 "contacts_batch_archive" => t('Archive') . "/" . t("Unarchive"),
819 "contacts_batch_drop" => t('Delete'),
821 '$h_batch_actions' => t('Batch Actions'),
822 '$paginate' => paginate($a),
829 * @brief List of pages for the Contact TabBar
831 * Available Pages are 'Status', 'Profile', 'Contacts' and 'Common Friends'
834 * @param int $contact_id The ID of the contact
835 * @param int $active_tab 1 if tab should be marked as active
839 function contacts_tab($a, $contact_id, $active_tab)
844 'label' => t('Status'),
845 'url' => "contacts/" . $contact_id . "/posts",
846 'sel' => (($active_tab == 1) ? 'active' : ''),
847 'title' => t('Status Messages and Posts'),
848 'id' => 'status-tab',
852 'label' => t('Profile'),
853 'url' => "contacts/" . $contact_id,
854 'sel' => (($active_tab == 2) ? 'active' : ''),
855 'title' => t('Profile Details'),
856 'id' => 'profile-tab',
861 // Show this tab only if there is visible friend list
862 $x = GContact::countAllFriends(local_user(), $contact_id);
864 $tabs[] = ['label' => t('Contacts'),
865 'url' => "allfriends/" . $contact_id,
866 'sel' => (($active_tab == 3) ? 'active' : ''),
867 'title' => t('View all contacts'),
868 'id' => 'allfriends-tab',
872 // Show this tab only if there is visible common friend list
873 $common = GContact::countCommonFriends(local_user(), $contact_id);
875 $tabs[] = ['label' => t('Common Friends'),
876 'url' => "common/loc/" . local_user() . "/" . $contact_id,
877 'sel' => (($active_tab == 4) ? 'active' : ''),
878 'title' => t('View all common friends'),
879 'id' => 'common-loc-tab',
884 $tabs[] = ['label' => t('Advanced'),
885 'url' => 'crepair/' . $contact_id,
886 'sel' => (($active_tab == 5) ? 'active' : ''),
887 'title' => t('Advanced Contact Settings'),
888 'id' => 'advanced-tab',
892 $tab_tpl = get_markup_template('common_tabs.tpl');
893 $tab_str = replace_macros($tab_tpl, ['$tabs' => $tabs]);
898 function contact_posts($a, $contact_id)
900 $o = contacts_tab($a, $contact_id, 1);
902 $contact = dba::selectFirst('contact', ['url'], ['id' => $contact_id]);
903 if (DBM::is_result($contact)) {
904 $a->page['aside'] = "";
905 Profile::load($a, "", 0, Contact::getDetailsByURL($contact["url"]));
906 $o .= Contact::getPostsFromUrl($contact["url"]);
912 function _contact_detail_for_template($rr)
916 switch ($rr['rel']) {
917 case CONTACT_IS_FRIEND:
918 $dir_icon = 'images/lrarrow.gif';
919 $alt_text = t('Mutual Friendship');
921 case CONTACT_IS_FOLLOWER;
922 $dir_icon = 'images/larrow.gif';
923 $alt_text = t('is a fan of yours');
925 case CONTACT_IS_SHARING;
926 $dir_icon = 'images/rarrow.gif';
927 $alt_text = t('you are a fan of');
932 if (($rr['network'] === NETWORK_DFRN) && ($rr['rel'])) {
933 $url = "redir/{$rr['id']}";
934 $sparkle = ' class="sparkle" ';
941 'img_hover' => t('Visit %s\'s profile [%s]', $rr['name'], $rr['url']),
942 'edit_hover' => t('Edit contact'),
943 'photo_menu' => Contact::photoMenu($rr),
945 'alt_text' => $alt_text,
946 'dir_icon' => $dir_icon,
947 'thumb' => proxy_url($rr['thumb'], false, PROXY_SIZE_THUMB),
948 'name' => htmlentities($rr['name']),
949 'username' => htmlentities($rr['name']),
950 'account_type' => Contact::getAccountType($rr),
951 'sparkle' => $sparkle,
952 'itemurl' => (($rr['addr'] != "") ? $rr['addr'] : $rr['url']),
954 'network' => ContactSelector::networkToName($rr['network'], $rr['url']),
959 * @brief Gives a array with actions which can performed to a given contact
961 * This includes actions like e.g. 'block', 'hide', 'archive', 'delete' and others
963 * @param array $contact Data about the Contact
964 * @return array with contact related actions
966 function contact_actions($contact)
968 $poll_enabled = in_array($contact['network'], [NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_FEED, NETWORK_MAIL]);
969 $contact_actions = [];
971 // Provide friend suggestion only for Friendica contacts
972 if ($contact['network'] === NETWORK_DFRN) {
973 $contact_actions['suggest'] = [
974 'label' => t('Suggest friends'),
975 'url' => 'fsuggest/' . $contact['id'],
983 $contact_actions['update'] = [
984 'label' => t('Update now'),
985 'url' => 'contacts/' . $contact['id'] . '/update',
992 $contact_actions['block'] = [
993 'label' => (intval($contact['blocked']) ? t('Unblock') : t('Block') ),
994 'url' => 'contacts/' . $contact['id'] . '/block',
995 'title' => t('Toggle Blocked status'),
996 'sel' => (intval($contact['blocked']) ? 'active' : ''),
997 'id' => 'toggle-block',
1000 $contact_actions['ignore'] = [
1001 'label' => (intval($contact['readonly']) ? t('Unignore') : t('Ignore') ),
1002 'url' => 'contacts/' . $contact['id'] . '/ignore',
1003 'title' => t('Toggle Ignored status'),
1004 'sel' => (intval($contact['readonly']) ? 'active' : ''),
1005 'id' => 'toggle-ignore',
1008 $contact_actions['archive'] = [
1009 'label' => (intval($contact['archive']) ? t('Unarchive') : t('Archive') ),
1010 'url' => 'contacts/' . $contact['id'] . '/archive',
1011 'title' => t('Toggle Archive status'),
1012 'sel' => (intval($contact['archive']) ? 'active' : ''),
1013 'id' => 'toggle-archive',
1016 $contact_actions['delete'] = [
1017 'label' => t('Delete'),
1018 'url' => 'contacts/' . $contact['id'] . '/drop',
1019 'title' => t('Delete contact'),
1024 return $contact_actions;