예제 #1
0
 function mark_for_death($contact)
 {
     if ($contact['term-date'] == '0000-00-00 00:00:00') {
         q("UPDATE `contact` SET `term-date` = '%s' WHERE `id` = %d LIMIT 1", dbesc(datetime_convert()), intval($contact['id']));
     } else {
         $expiry = $contact['term-date'] . ' + 32 days ';
         if (datetime_convert() > datetime_convert('UTC', 'UTC', $expiry)) {
             // relationship is really truly dead.
             contact_remove($contact['id']);
         }
     }
 }
예제 #2
0
function contacts_content(&$a)
{
    $sort_type = 0;
    $o = '';
    nav_set_selected('contacts');
    if (!local_user()) {
        notice(t('Permission denied.') . EOL);
        return;
    }
    if ($a->argc == 3) {
        $contact_id = intval($a->argv[1]);
        if (!$contact_id) {
            return;
        }
        $cmd = $a->argv[2];
        $orig_record = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d AND `self` = 0 LIMIT 1", intval($contact_id), intval(local_user()));
        if (!count($orig_record)) {
            notice(t('Could not access contact record.') . EOL);
            goaway($a->get_baseurl() . '/contacts');
            return;
            // NOTREACHED
        }
        if ($cmd === 'update') {
            // pull feed and consume it, which should subscribe to the hub.
            proc_run('php', "include/poller.php", "{$contact_id}");
            goaway($a->get_baseurl() . '/contacts/' . $contact_id);
            // NOTREACHED
        }
        if ($cmd === 'block') {
            $blocked = $orig_record[0]['blocked'] ? 0 : 1;
            $r = q("UPDATE `contact` SET `blocked` = %d WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($blocked), intval($contact_id), intval(local_user()));
            if ($r) {
                //notice( t('Contact has been ') . (($blocked) ? t('blocked') : t('unblocked')) . EOL );
                info(($blocked ? t('Contact has been blocked') : t('Contact has been unblocked')) . EOL);
            }
            goaway($a->get_baseurl() . '/contacts/' . $contact_id);
            return;
            // NOTREACHED
        }
        if ($cmd === 'ignore') {
            $readonly = $orig_record[0]['readonly'] ? 0 : 1;
            $r = q("UPDATE `contact` SET `readonly` = %d WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($readonly), intval($contact_id), intval(local_user()));
            if ($r) {
                info(($readonly ? t('Contact has been ignored') : t('Contact has been unignored')) . EOL);
            }
            goaway($a->get_baseurl() . '/contacts/' . $contact_id);
            return;
            // NOTREACHED
        }
        if ($cmd === 'drop') {
            // create an unfollow slap
            if ($orig_record[0]['network'] === NETWORK_OSTATUS) {
                $tpl = get_markup_template('follow_slap.tpl');
                $slap = replace_macros($tpl, array('$name' => $a->user['username'], '$profile_page' => $a->get_baseurl() . '/profile/' . $a->user['nickname'], '$photo' => $a->contact['photo'], '$thumb' => $a->contact['thumb'], '$published' => datetime_convert('UTC', 'UTC', 'now', ATOM_TIME), '$item_id' => 'urn:X-dfrn:' . $a->get_hostname() . ':unfollow:' . random_string(), '$title' => '', '$type' => 'text', '$content' => t('stopped following'), '$nick' => $a->user['nickname'], '$verb' => 'http://ostatus.org/schema/1.0/unfollow', '$ostat_follow' => ''));
                if (x($orig_record[0], 'notify') && strlen($orig_record[0]['notify'])) {
                    require_once 'include/salmon.php';
                    slapper($a->user, $orig_record[0]['notify'], $slap);
                }
            } elseif ($orig_record[0]['network'] === NETWORK_DIASPORA) {
                require_once 'include/diaspora.php';
                diaspora_unshare($a->user, $orig_record[0]);
            } elseif ($orig_record[0]['network'] === NETWORK_DFRN) {
                require_once 'include/items.php';
                dfrn_deliver($a->user, $orig_record[0], 'placeholder', 1);
            }
            contact_remove($orig_record[0]['id']);
            info(t('Contact has been removed.') . EOL);
            if (x($_SESSION, 'return_url')) {
                goaway($a->get_baseurl() . '/' . $_SESSION['return_url']);
            } else {
                goaway($a->get_baseurl() . '/contacts');
            }
            return;
            // NOTREACHED
        }
    }
    if (x($a->data, 'contact') && is_array($a->data['contact'])) {
        $contact_id = $a->data['contact']['id'];
        $contact = $a->data['contact'];
        $tpl = get_markup_template('contact_head.tpl');
        $a->page['htmlhead'] .= replace_macros($tpl, array('$baseurl' => $a->get_baseurl()));
        require_once 'include/contact_selectors.php';
        $tpl = get_markup_template("contact_edit.tpl");
        switch ($contact['rel']) {
            case CONTACT_IS_FRIEND:
                $dir_icon = 'images/lrarrow.gif';
                $relation_text = t('You are mutual friends with %s');
                break;
            case CONTACT_IS_FOLLOWER:
                $dir_icon = 'images/larrow.gif';
                $relation_text = t('You are sharing with %s');
                break;
            case CONTACT_IS_SHARING:
                $dir_icon = 'images/rarrow.gif';
                $relation_text = t('%s is sharing with you');
                break;
            default:
                break;
        }
        $relation_text = sprintf($relation_text, $contact['name']);
        if ($contact['network'] === NETWORK_DFRN && $contact['rel']) {
            $url = "redir/{$contact['id']}";
            $sparkle = ' class="sparkle" ';
        } else {
            $url = $contact['url'];
            $sparkle = '';
        }
        $insecure = t('Private communications are not available for this contact.');
        $last_update = $contact['last-update'] == '0000-00-00 00:00:00' ? t('Never') : datetime_convert('UTC', date_default_timezone_get(), $contact['last-update'], 'D, j M Y, g:i A');
        if ($contact['last-update'] !== '0000-00-00 00:00:00') {
            $last_update .= ' ' . ($contact['last-update'] == $contact['success_update'] ? t("(Update was successful)") : t("(Update was not successful)"));
        }
        $lblsuggest = $contact['network'] === NETWORK_DFRN ? t('Suggest friends') : '';
        $poll_enabled = $contact['network'] !== NETWORK_DIASPORA ? true : false;
        $nettype = sprintf(t('Network type: %s'), network_to_name($contact['network']));
        $common = count_common_friends(local_user(), $contact['id']);
        $common_text = $common ? sprintf(tt('%d contact in common', '%d contacts in common', $common), $common) : '';
        $polling = $contact['network'] === NETWORK_MAIL | $contact['network'] === NETWORK_FEED ? 'polling' : '';
        $x = count_all_friends(local_user(), $contact['id']);
        $all_friends = $x ? t('View all contacts') : '';
        // tabs
        $tabs = array(array('label' => $contact['blocked'] ? t('Unblock') : t('Block'), 'url' => $a->get_baseurl() . '/contacts/' . $contact_id . '/block', 'sel' => ''), array('label' => $contact['readonly'] ? t('Unignore') : t('Ignore'), 'url' => $a->get_baseurl() . '/contacts/' . $contact_id . '/ignore', 'sel' => ''), array('label' => t('Repair'), 'url' => $a->get_baseurl() . '/crepair/' . $contact_id, 'sel' => ''));
        $tab_tpl = get_markup_template('common_tabs.tpl');
        $tab_str = replace_macros($tab_tpl, array('$tabs' => $tabs));
        $o .= replace_macros($tpl, array('$header' => t('Contact Editor'), '$tab_str' => $tab_str, '$submit' => t('Submit'), '$lbl_vis1' => t('Profile Visibility'), '$lbl_vis2' => sprintf(t('Please choose the profile you would like to display to %s when viewing your profile securely.'), $contact['name']), '$lbl_info1' => t('Contact Information / Notes'), '$infedit' => t('Edit contact notes'), '$common_text' => $common_text, '$common_link' => $a->get_baseurl() . '/common/' . $contact['id'], '$all_friends' => $all_friends, '$relation_text' => $relation_text, '$visit' => sprintf(t('Visit %s\'s profile [%s]'), $contact['name'], $contact['url']), '$blockunblock' => t('Block/Unblock contact'), '$ignorecont' => t('Ignore contact'), '$lblcrepair' => t("Repair URL settings"), '$lblrecent' => t('View conversations'), '$lblsuggest' => $lblsuggest, '$delete' => t('Delete contact'), '$nettype' => $nettype, '$poll_interval' => contact_poll_interval($contact['priority'], !$poll_enabled), '$poll_enabled' => $poll_enabled, '$lastupdtext' => t('Last update:'), '$updpub' => t('Update public posts'), '$last_update' => $last_update, '$udnow' => t('Update now'), '$profile_select' => contact_profile_assign($contact['profile-id'], $contact['network'] !== NETWORK_DFRN ? true : false), '$contact_id' => $contact['id'], '$block_text' => $contact['blocked'] ? t('Unblock') : t('Block'), '$ignore_text' => $contact['readonly'] ? t('Unignore') : t('Ignore'), '$insecure' => $contact['network'] !== NETWORK_DFRN && $contact['network'] !== NETWORK_MAIL && $contact['network'] !== NETWORK_FACEBOOK && $contact['network'] !== NETWORK_DIASPORA ? $insecure : '', '$info' => $contact['info'], '$blocked' => $contact['blocked'] ? t('Currently blocked') : '', '$ignored' => $contact['readonly'] ? t('Currently ignored') : '', '$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')), '$photo' => $contact['photo'], '$name' => $contact['name'], '$dir_icon' => $dir_icon, '$alt_text' => $alt_text, '$sparkle' => $sparkle, '$url' => $url));
        $arr = array('contact' => $contact, 'output' => $o);
        call_hooks('contact_edit', $arr);
        return $arr['output'];
    }
    $blocked = false;
    $hidden = false;
    $ignored = false;
    $all = false;
    $_SESSION['return_url'] = $a->query_string;
    if ($a->argc == 2 && $a->argv[1] === 'all') {
        $sql_extra = '';
        $all = true;
    } elseif ($a->argc == 2 && $a->argv[1] === 'blocked') {
        $sql_extra = " AND `blocked` = 1 ";
        $blocked = true;
    } elseif ($a->argc == 2 && $a->argv[1] === 'hidden') {
        $sql_extra = " AND `hidden` = 1 ";
        $hidden = true;
    } elseif ($a->argc == 2 && $a->argv[1] === 'ignored') {
        $sql_extra = " AND `readonly` = 1 ";
        $ignored = true;
    } else {
        $sql_extra = " AND `blocked` = 0 ";
    }
    $search = x($_GET, 'search') ? notags(trim($_GET['search'])) : '';
    $nets = x($_GET, 'nets') ? notags(trim($_GET['nets'])) : '';
    $tabs = array(array('label' => t('All Contacts'), 'url' => $a->get_baseurl() . '/contacts/all', 'sel' => $all ? 'active' : ''), array('label' => t('Unblocked Contacts'), 'url' => $a->get_baseurl() . '/contacts', 'sel' => !$all && !$blocked && !$hidden && !$search && !$nets && !$ignored ? 'active' : ''), array('label' => t('Blocked Contacts'), 'url' => $a->get_baseurl() . '/contacts/blocked', 'sel' => $blocked ? 'active' : ''), array('label' => t('Ignored Contacts'), 'url' => $a->get_baseurl() . '/contacts/ignored', 'sel' => $ignored ? 'active' : ''), array('label' => t('Hidden Contacts'), 'url' => $a->get_baseurl() . '/contacts/hidden', 'sel' => $hidden ? 'active' : ''));
    $tab_tpl = get_markup_template('common_tabs.tpl');
    $t = replace_macros($tab_tpl, array('$tabs' => $tabs));
    if ($search) {
        $search_hdr = $search;
        $search = dbesc($search . '*');
    }
    $sql_extra .= strlen($search) ? " AND MATCH `name` AGAINST ('{$search}' IN BOOLEAN MODE) " : "";
    if ($nets) {
        $sql_extra .= sprintf(" AND network = '%s' ", dbesc($nets));
    }
    $sql_extra2 = $sort_type > 0 && $sort_type <= CONTACT_IS_FRIEND ? sprintf(" AND `rel` = %d ", intval($sort_type)) : '';
    $r = q("SELECT COUNT(*) AS `total` FROM `contact` \n\t\tWHERE `uid` = %d AND `pending` = 0 {$sql_extra} {$sql_extra2} ", intval($_SESSION['uid']));
    if (count($r)) {
        $a->set_pager_total($r[0]['total']);
    }
    $tpl = get_markup_template("contacts-top.tpl");
    $o .= replace_macros($tpl, array('$header' => t('Contacts') . ($nets ? ' - ' . network_to_name($nets) : ''), '$tabs' => $t, '$total' => $r[0]['total'], '$search' => $search_hdr, '$desc' => t('Search your contacts'), '$finding' => strlen($search) ? '<h4>' . t('Finding: ') . "'" . $search . "'" . '</h4>' : "", '$submit' => t('Find'), '$cmd' => $a->cmd));
    $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `pending` = 0 {$sql_extra} {$sql_extra2} ORDER BY `name` ASC LIMIT %d , %d ", intval($_SESSION['uid']), intval($a->pager['start']), intval($a->pager['itemspage']));
    if (count($r)) {
        $tpl = get_markup_template("contact_template.tpl");
        foreach ($r as $rr) {
            if ($rr['self']) {
                continue;
            }
            switch ($rr['rel']) {
                case CONTACT_IS_FRIEND:
                    $dir_icon = 'images/lrarrow.gif';
                    $alt_text = t('Mutual Friendship');
                    break;
                case CONTACT_IS_FOLLOWER:
                    $dir_icon = 'images/larrow.gif';
                    $alt_text = t('is a fan of yours');
                    break;
                case CONTACT_IS_SHARING:
                    $dir_icon = 'images/rarrow.gif';
                    $alt_text = t('you are a fan of');
                    break;
                default:
                    break;
            }
            if ($rr['network'] === 'dfrn' && $rr['rel']) {
                $url = "redir/{$rr['id']}";
                $sparkle = ' class="sparkle" ';
            } else {
                $url = $rr['url'];
                $sparkle = '';
            }
            $o .= replace_macros($tpl, array('$img_hover' => sprintf(t('Visit %s\'s profile [%s]'), $rr['name'], $rr['url']), '$edit_hover' => t('Edit contact'), '$contact_photo_menu' => contact_photo_menu($rr), '$id' => $rr['id'], '$alt_text' => $alt_text, '$dir_icon' => $dir_icon, '$thumb' => $rr['thumb'], '$name' => $rr['name'], '$username' => $rr['name'], '$sparkle' => $sparkle, '$url' => $url));
        }
        $o .= '<div id="contact-edit-end"></div>';
    }
    $o .= paginate($a);
    return $o;
}
예제 #3
0
파일: diaspora.php 프로젝트: redmatrix/red
function diaspora_retraction($importer, $xml)
{
    $guid = notags(unxmlify($xml->guid));
    $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
    $type = notags(unxmlify($xml->type));
    $contact = diaspora_get_contact_by_handle($importer['channel_id'], $diaspora_handle);
    if (!$contact) {
        return;
    }
    if ($type === 'Person') {
        require_once 'include/Contact.php';
        contact_remove($importer['channel_id'], $contact['abook_id']);
    } elseif ($type === 'Post') {
        $r = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc('guid'), intval($importer['channel_id']));
        if (count($r)) {
            if (link_compare($r[0]['author_xchan'], $contact['xchan_hash'])) {
                drop_item($r[0]['id'], false);
            }
        }
    }
    return 202;
    // NOTREACHED
}
예제 #4
0
파일: zot.php 프로젝트: royalterra/hubzilla
function zot_reply_purge($sender, $recipients)
{
    $ret = array('success' => false);
    if ($recipients) {
        // basically this means "unfriend"
        foreach ($recipients as $recip) {
            $r = q("select channel.*,xchan.* from channel \n\t\t\t\tleft join xchan on channel_hash = xchan_hash\n\t\t\t\twhere channel_guid = '%s' and channel_guid_sig = '%s' limit 1", dbesc($recip['guid']), dbesc($recip['guid_sig']));
            if ($r) {
                $r = q("select abook_id from abook where uid = %d and abook_xchan = '%s' limit 1", intval($r[0]['channel_id']), dbesc(make_xchan_hash($sender['guid'], $sender['guid_sig'])));
                if ($r) {
                    contact_remove($r[0]['channel_id'], $r[0]['abook_id']);
                }
            }
        }
        $ret['success'] = true;
    } else {
        // Unfriend everybody - basically this means the channel has committed suicide
        $arr = $sender;
        $sender_hash = make_xchan_hash($arr['guid'], $arr['guid_sig']);
        require_once 'include/Contact.php';
        remove_all_xchan_resources($sender_hash);
        $ret['success'] = true;
    }
    json_return_and_die($ret);
}
예제 #5
0
function contacts_content(&$a)
{
    $sort_type = 0;
    $o = '';
    nav_set_selected('contacts');
    if (!local_user()) {
        notice(t('Permission denied.') . EOL);
        return;
    }
    if ($a->argc == 3) {
        $contact_id = intval($a->argv[1]);
        if (!$contact_id) {
            return;
        }
        $cmd = $a->argv[2];
        $orig_record = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d AND `self` = 0 LIMIT 1", intval($contact_id), intval(local_user()));
        if (!count($orig_record)) {
            notice(t('Could not access contact record.') . EOL);
            goaway($a->get_baseurl(true) . '/contacts');
            return;
            // NOTREACHED
        }
        if ($cmd === 'update') {
            // pull feed and consume it, which should subscribe to the hub.
            proc_run('php', "include/poller.php", "{$contact_id}");
            goaway($a->get_baseurl(true) . '/contacts/' . $contact_id);
            // NOTREACHED
        }
        if ($cmd === 'block') {
            $blocked = $orig_record[0]['blocked'] ? 0 : 1;
            $r = q("UPDATE `contact` SET `blocked` = %d WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($blocked), intval($contact_id), intval(local_user()));
            if ($r) {
                //notice( t('Contact has been ') . (($blocked) ? t('blocked') : t('unblocked')) . EOL );
                info(($blocked ? t('Contact has been blocked') : t('Contact has been unblocked')) . EOL);
            }
            goaway($a->get_baseurl(true) . '/contacts/' . $contact_id);
            return;
            // NOTREACHED
        }
        if ($cmd === 'ignore') {
            $readonly = $orig_record[0]['readonly'] ? 0 : 1;
            $r = q("UPDATE `contact` SET `readonly` = %d WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($readonly), intval($contact_id), intval(local_user()));
            if ($r) {
                info(($readonly ? t('Contact has been ignored') : t('Contact has been unignored')) . EOL);
            }
            goaway($a->get_baseurl(true) . '/contacts/' . $contact_id);
            return;
            // NOTREACHED
        }
        if ($cmd === 'archive') {
            $archived = $orig_record[0]['archive'] ? 0 : 1;
            $r = q("UPDATE `contact` SET `archive` = %d WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($archived), intval($contact_id), intval(local_user()));
            if ($archived) {
                q("UPDATE `item` SET `private` = 2 WHERE `contact-id` = %d AND `uid` = %d", intval($contact_id), intval(local_user()));
            }
            if ($r) {
                //notice( t('Contact has been ') . (($archived) ? t('archived') : t('unarchived')) . EOL );
                info(($archived ? t('Contact has been archived') : t('Contact has been unarchived')) . EOL);
            }
            goaway($a->get_baseurl(true) . '/contacts/' . $contact_id);
            return;
            // NOTREACHED
        }
        if ($cmd === 'drop') {
            // Check if we should do HTML-based delete confirmation
            if ($_REQUEST['confirm']) {
                // <form> can't take arguments in its "action" parameter
                // so add any arguments as hidden inputs
                $query = explode_querystring($a->query_string);
                $inputs = array();
                foreach ($query['args'] as $arg) {
                    if (strpos($arg, 'confirm=') === false) {
                        $arg_parts = explode('=', $arg);
                        $inputs[] = array('name' => $arg_parts[0], 'value' => $arg_parts[1]);
                    }
                }
                $a->page['aside'] = '';
                return replace_macros(get_markup_template('confirm.tpl'), array('$method' => 'get', '$message' => t('Do you really want to delete this contact?'), '$extra_inputs' => $inputs, '$confirm' => t('Yes'), '$confirm_url' => $query['base'], '$confirm_name' => 'confirmed', '$cancel' => t('Cancel')));
            }
            // Now check how the user responded to the confirmation query
            if ($_REQUEST['canceled']) {
                goaway($a->get_baseurl(true) . '/' . $_SESSION['return_url']);
            }
            require_once 'include/Contact.php';
            terminate_friendship($a->user, $a->contact, $orig_record[0]);
            contact_remove($orig_record[0]['id']);
            info(t('Contact has been removed.') . EOL);
            if (x($_SESSION, 'return_url')) {
                goaway($a->get_baseurl(true) . '/' . $_SESSION['return_url']);
            } else {
                goaway($a->get_baseurl(true) . '/contacts');
            }
            return;
            // NOTREACHED
        }
    }
    $_SESSION['return_url'] = $a->query_string;
    if (x($a->data, 'contact') && is_array($a->data['contact'])) {
        $contact_id = $a->data['contact']['id'];
        $contact = $a->data['contact'];
        $editselect = 'none';
        if (feature_enabled(local_user(), 'richtext')) {
            $editselect = 'exact';
        }
        $a->page['htmlhead'] .= replace_macros(get_markup_template('contact_head.tpl'), array('$baseurl' => $a->get_baseurl(true), '$editselect' => $editselect));
        $a->page['end'] .= replace_macros(get_markup_template('contact_end.tpl'), array('$baseurl' => $a->get_baseurl(true), '$editselect' => $editselect));
        require_once 'include/contact_selectors.php';
        $tpl = get_markup_template("contact_edit.tpl");
        switch ($contact['rel']) {
            case CONTACT_IS_FRIEND:
                $dir_icon = 'images/lrarrow.gif';
                $relation_text = t('You are mutual friends with %s');
                break;
            case CONTACT_IS_FOLLOWER:
                $dir_icon = 'images/larrow.gif';
                $relation_text = t('You are sharing with %s');
                break;
            case CONTACT_IS_SHARING:
                $dir_icon = 'images/rarrow.gif';
                $relation_text = t('%s is sharing with you');
                break;
            default:
                break;
        }
        $relation_text = sprintf($relation_text, $contact['name']);
        if ($contact['network'] === NETWORK_DFRN && $contact['rel']) {
            $url = "redir/{$contact['id']}";
            $sparkle = ' class="sparkle" ';
        } else {
            $url = $contact['url'];
            $sparkle = '';
        }
        $insecure = t('Private communications are not available for this contact.');
        $last_update = $contact['last-update'] == '0000-00-00 00:00:00' ? t('Never') : datetime_convert('UTC', date_default_timezone_get(), $contact['last-update'], 'D, j M Y, g:i A');
        if ($contact['last-update'] !== '0000-00-00 00:00:00') {
            $last_update .= ' ' . ($contact['last-update'] == $contact['success_update'] ? t("(Update was successful)") : t("(Update was not successful)"));
        }
        $lblsuggest = $contact['network'] === NETWORK_DFRN ? t('Suggest friends') : '';
        $poll_enabled = $contact['network'] !== NETWORK_DIASPORA ? true : false;
        $nettype = sprintf(t('Network type: %s'), network_to_name($contact['network']));
        $common = count_common_friends(local_user(), $contact['id']);
        $common_text = $common ? sprintf(tt('%d contact in common', '%d contacts in common', $common), $common) : '';
        $polling = $contact['network'] === NETWORK_MAIL | $contact['network'] === NETWORK_FEED ? 'polling' : '';
        $x = count_all_friends(local_user(), $contact['id']);
        $all_friends = $x ? t('View all contacts') : '';
        // tabs
        $tabs = array(array('label' => $contact['blocked'] ? t('Unblock') : t('Block'), 'url' => $a->get_baseurl(true) . '/contacts/' . $contact_id . '/block', 'sel' => '', 'title' => t('Toggle Blocked status')), array('label' => $contact['readonly'] ? t('Unignore') : t('Ignore'), 'url' => $a->get_baseurl(true) . '/contacts/' . $contact_id . '/ignore', 'sel' => '', 'title' => t('Toggle Ignored status')), array('label' => $contact['archive'] ? t('Unarchive') : t('Archive'), 'url' => $a->get_baseurl(true) . '/contacts/' . $contact_id . '/archive', 'sel' => '', 'title' => t('Toggle Archive status')), array('label' => t('Repair'), 'url' => $a->get_baseurl(true) . '/crepair/' . $contact_id, 'sel' => '', 'title' => t('Advanced Contact Settings')));
        $tab_tpl = get_markup_template('common_tabs.tpl');
        $tab_str = replace_macros($tab_tpl, array('$tabs' => $tabs));
        $lost_contact = $contact['archive'] && $contact['term-date'] != '0000-00-00 00:00:00' && $contact['term-date'] < datetime_convert('', '', 'now') ? t('Communications lost with this contact!') : '';
        $o .= replace_macros($tpl, array('$header' => t('Contact Editor'), '$tab_str' => $tab_str, '$submit' => t('Submit'), '$lbl_vis1' => t('Profile Visibility'), '$lbl_vis2' => sprintf(t('Please choose the profile you would like to display to %s when viewing your profile securely.'), $contact['name']), '$lbl_info1' => t('Contact Information / Notes'), '$infedit' => t('Edit contact notes'), '$common_text' => $common_text, '$common_link' => $a->get_baseurl(true) . '/common/loc/' . local_user() . '/' . $contact['id'], '$all_friends' => $all_friends, '$relation_text' => $relation_text, '$visit' => sprintf(t('Visit %s\'s profile [%s]'), $contact['name'], $contact['url']), '$blockunblock' => t('Block/Unblock contact'), '$ignorecont' => t('Ignore contact'), '$lblcrepair' => t("Repair URL settings"), '$lblrecent' => t('View conversations'), '$lblsuggest' => $lblsuggest, '$delete' => t('Delete contact'), '$nettype' => $nettype, '$poll_interval' => contact_poll_interval($contact['priority'], !$poll_enabled), '$poll_enabled' => $poll_enabled, '$lastupdtext' => t('Last update:'), '$lost_contact' => $lost_contact, '$updpub' => t('Update public posts'), '$last_update' => $last_update, '$udnow' => t('Update now'), '$profile_select' => contact_profile_assign($contact['profile-id'], $contact['network'] !== NETWORK_DFRN ? true : false), '$contact_id' => $contact['id'], '$block_text' => $contact['blocked'] ? t('Unblock') : t('Block'), '$ignore_text' => $contact['readonly'] ? t('Unignore') : t('Ignore'), '$insecure' => $contact['network'] !== NETWORK_DFRN && $contact['network'] !== NETWORK_MAIL && $contact['network'] !== NETWORK_FACEBOOK && $contact['network'] !== NETWORK_DIASPORA ? $insecure : '', '$info' => $contact['info'], '$blocked' => $contact['blocked'] ? t('Currently blocked') : '', '$ignored' => $contact['readonly'] ? t('Currently ignored') : '', '$archived' => $contact['archive'] ? t('Currently archived') : '', '$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')), '$photo' => $contact['photo'], '$name' => $contact['name'], '$dir_icon' => $dir_icon, '$alt_text' => $alt_text, '$sparkle' => $sparkle, '$url' => $url));
        $arr = array('contact' => $contact, 'output' => $o);
        call_hooks('contact_edit', $arr);
        return $arr['output'];
    }
    $blocked = false;
    $hidden = false;
    $ignored = false;
    $all = false;
    if ($a->argc == 2 && $a->argv[1] === 'all') {
        $sql_extra = '';
        $all = true;
    } elseif ($a->argc == 2 && $a->argv[1] === 'blocked') {
        $sql_extra = " AND `blocked` = 1 ";
        $blocked = true;
    } elseif ($a->argc == 2 && $a->argv[1] === 'hidden') {
        $sql_extra = " AND `hidden` = 1 ";
        $hidden = true;
    } elseif ($a->argc == 2 && $a->argv[1] === 'ignored') {
        $sql_extra = " AND `readonly` = 1 ";
        $ignored = true;
    } elseif ($a->argc == 2 && $a->argv[1] === 'archived') {
        $sql_extra = " AND `archive` = 1 ";
        $archived = true;
    } else {
        $sql_extra = " AND `blocked` = 0 ";
    }
    $search = x($_GET, 'search') ? notags(trim($_GET['search'])) : '';
    $nets = x($_GET, 'nets') ? notags(trim($_GET['nets'])) : '';
    $tabs = array(array('label' => t('Suggestions'), 'url' => $a->get_baseurl(true) . '/suggest', 'sel' => '', 'title' => t('Suggest potential friends')), array('label' => t('All Contacts'), 'url' => $a->get_baseurl(true) . '/contacts/all', 'sel' => $all ? 'active' : '', 'title' => t('Show all contacts')), array('label' => t('Unblocked'), 'url' => $a->get_baseurl(true) . '/contacts', 'sel' => !$all && !$blocked && !$hidden && !$search && !$nets && !$ignored && !$archived ? 'active' : '', 'title' => t('Only show unblocked contacts')), array('label' => t('Blocked'), 'url' => $a->get_baseurl(true) . '/contacts/blocked', 'sel' => $blocked ? 'active' : '', 'title' => t('Only show blocked contacts')), array('label' => t('Ignored'), 'url' => $a->get_baseurl(true) . '/contacts/ignored', 'sel' => $ignored ? 'active' : '', 'title' => t('Only show ignored contacts')), array('label' => t('Archived'), 'url' => $a->get_baseurl(true) . '/contacts/archived', 'sel' => $archived ? 'active' : '', 'title' => t('Only show archived contacts')), array('label' => t('Hidden'), 'url' => $a->get_baseurl(true) . '/contacts/hidden', 'sel' => $hidden ? 'active' : '', 'title' => t('Only show hidden contacts')));
    $tab_tpl = get_markup_template('common_tabs.tpl');
    $t = replace_macros($tab_tpl, array('$tabs' => $tabs));
    $searching = false;
    if ($search) {
        $search_hdr = $search;
        $search_txt = dbesc(protect_sprintf(preg_quote($search)));
        $searching = true;
    }
    $sql_extra .= $searching ? " AND `name` REGEXP '{$search_txt}' " : "";
    if ($nets) {
        $sql_extra .= sprintf(" AND network = '%s' ", dbesc($nets));
    }
    $sql_extra2 = $sort_type > 0 && $sort_type <= CONTACT_IS_FRIEND ? sprintf(" AND `rel` = %d ", intval($sort_type)) : '';
    $r = q("SELECT COUNT(*) AS `total` FROM `contact` \n\t\tWHERE `uid` = %d AND `self` = 0 AND `pending` = 0 {$sql_extra} {$sql_extra2} ", intval($_SESSION['uid']));
    if (count($r)) {
        $a->set_pager_total($r[0]['total']);
        $total = $r[0]['total'];
    }
    $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 0 AND `pending` = 0 {$sql_extra} {$sql_extra2} ORDER BY `name` ASC LIMIT %d , %d ", intval($_SESSION['uid']), intval($a->pager['start']), intval($a->pager['itemspage']));
    $contacts = array();
    if (count($r)) {
        foreach ($r as $rr) {
            switch ($rr['rel']) {
                case CONTACT_IS_FRIEND:
                    $dir_icon = 'images/lrarrow.gif';
                    $alt_text = t('Mutual Friendship');
                    break;
                case CONTACT_IS_FOLLOWER:
                    $dir_icon = 'images/larrow.gif';
                    $alt_text = t('is a fan of yours');
                    break;
                case CONTACT_IS_SHARING:
                    $dir_icon = 'images/rarrow.gif';
                    $alt_text = t('you are a fan of');
                    break;
                default:
                    break;
            }
            if ($rr['network'] === 'dfrn' && $rr['rel']) {
                $url = "redir/{$rr['id']}";
                $sparkle = ' class="sparkle" ';
            } else {
                $url = $rr['url'];
                $sparkle = '';
            }
            $contacts[] = array('img_hover' => sprintf(t('Visit %s\'s profile [%s]'), $rr['name'], $rr['url']), 'edit_hover' => t('Edit contact'), 'photo_menu' => contact_photo_menu($rr), 'id' => $rr['id'], 'alt_text' => $alt_text, 'dir_icon' => $dir_icon, 'thumb' => $rr['thumb'], 'name' => $rr['name'], 'username' => $rr['name'], 'sparkle' => $sparkle, 'itemurl' => $rr['url'], 'url' => $url, 'network' => network_to_name($rr['network']));
        }
    }
    $tpl = get_markup_template("contacts-template.tpl");
    $o .= replace_macros($tpl, array('$header' => t('Contacts') . ($nets ? ' - ' . network_to_name($nets) : ''), '$tabs' => $t, '$total' => $total, '$search' => $search_hdr, '$desc' => t('Search your contacts'), '$finding' => $searching ? t('Finding: ') . "'" . $search . "'" : "", '$submit' => t('Find'), '$cmd' => $a->cmd, '$contacts' => $contacts, '$paginate' => paginate($a)));
    return $o;
}
예제 #6
0
function _contact_drop($contact_id, $orig_record)
{
    require_once 'include/Contact.php';
    $a = get_app();
    terminate_friendship($a->user, $a->contact, $orig_record);
    contact_remove($orig_record['id']);
}
예제 #7
0
 function get()
 {
     $sort_type = 0;
     $o = '';
     if (!local_channel()) {
         notice(t('Permission denied.') . EOL);
         return login();
     }
     $channel = \App::get_channel();
     $my_perms = get_channel_default_perms(local_channel());
     $role = get_pconfig(local_channel(), 'system', 'permissions_role');
     if ($role) {
         $x = get_role_perms($role);
         if ($x['perms_accept']) {
             $my_perms = $x['perms_accept'];
         }
     }
     $yes_no = array(t('No'), t('Yes'));
     if ($my_perms) {
         $o .= "<script>function connectDefaultShare() {\n\t\t\t\$('.abook-edit-me').each(function() {\n\t\t\t\tif(! \$(this).is(':disabled'))\n\t\t\t\t\t\$(this).prop('checked', false);\n\t\t\t});\n\n";
         $perms = get_perms();
         foreach ($perms as $p => $v) {
             if ($my_perms & $v[1]) {
                 $o .= "\$('#me_id_perms_" . $p . "').prop('checked', true); \n";
             }
         }
         $o .= " }\n</script>\n";
     }
     if (argc() == 3) {
         $contact_id = intval(argv(1));
         if (!$contact_id) {
             return;
         }
         $cmd = argv(2);
         $orig_record = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash\n\t\t\t\tWHERE abook_id = %d AND abook_channel = %d AND abook_self = 0 LIMIT 1", intval($contact_id), intval(local_channel()));
         if (!count($orig_record)) {
             notice(t('Could not access address book record.') . EOL);
             goaway(z_root() . '/connections');
         }
         if ($cmd === 'update') {
             // pull feed and consume it, which should subscribe to the hub.
             proc_run('php', "include/poller.php", "{$contact_id}");
             goaway(z_root() . '/connedit/' . $contact_id);
         }
         if ($cmd === 'refresh') {
             if ($orig_record[0]['xchan_network'] === 'zot') {
                 if (!zot_refresh($orig_record[0], \App::get_channel())) {
                     notice(t('Refresh failed - channel is currently unavailable.'));
                 }
             } else {
                 // if you are on a different network we'll force a refresh of the connection basic info
                 proc_run('php', 'include/notifier.php', 'permission_update', $contact_id);
             }
             goaway(z_root() . '/connedit/' . $contact_id);
         }
         if ($cmd === 'block') {
             if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_BLOCKED)) {
                 $this->connedit_clone($a);
             } else {
                 notice(t('Unable to set address book parameters.') . EOL);
             }
             goaway(z_root() . '/connedit/' . $contact_id);
         }
         if ($cmd === 'ignore') {
             if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_IGNORED)) {
                 $this->connedit_clone($a);
             } else {
                 notice(t('Unable to set address book parameters.') . EOL);
             }
             goaway(z_root() . '/connedit/' . $contact_id);
         }
         if ($cmd === 'archive') {
             if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_ARCHIVED)) {
                 $this->connedit_clone($a);
             } else {
                 notice(t('Unable to set address book parameters.') . EOL);
             }
             goaway(z_root() . '/connedit/' . $contact_id);
         }
         if ($cmd === 'hide') {
             if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_HIDDEN)) {
                 $this->connedit_clone($a);
             } else {
                 notice(t('Unable to set address book parameters.') . EOL);
             }
             goaway(z_root() . '/connedit/' . $contact_id);
         }
         // We'll prevent somebody from unapproving an already approved contact.
         // Though maybe somebody will want this eventually (??)
         if ($cmd === 'approve') {
             if (intval($orig_record[0]['abook_pending'])) {
                 if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_PENDING)) {
                     $this->connedit_clone($a);
                 } else {
                     notice(t('Unable to set address book parameters.') . EOL);
                 }
             }
             goaway(z_root() . '/connedit/' . $contact_id);
         }
         if ($cmd === 'drop') {
             require_once 'include/Contact.php';
             // FIXME
             // We need to send either a purge or a refresh packet to the other side (the channel being unfriended).
             // The issue is that the abook DB record _may_ get destroyed when we call contact_remove. As the notifier runs
             // in the background there could be a race condition preventing this packet from being sent in all cases.
             // PLACEHOLDER
             contact_remove(local_channel(), $orig_record[0]['abook_id']);
             build_sync_packet(0, array('abook' => array(array('abook_xchan' => $orig_record[0]['abook_xchan'], 'entry_deleted' => true))));
             info(t('Connection has been removed.') . EOL);
             if (x($_SESSION, 'return_url')) {
                 goaway(z_root() . '/' . $_SESSION['return_url']);
             }
             goaway(z_root() . '/contacts');
         }
     }
     if (\App::$poi) {
         $contact_id = \App::$poi['abook_id'];
         $contact = \App::$poi;
         $tools = array('view' => array('label' => t('View Profile'), 'url' => chanlink_cid($contact['abook_id']), 'sel' => '', 'title' => sprintf(t('View %s\'s profile'), $contact['xchan_name'])), 'refresh' => array('label' => t('Refresh Permissions'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/refresh', 'sel' => '', 'title' => t('Fetch updated permissions')), 'recent' => array('label' => t('Recent Activity'), 'url' => z_root() . '/network/?f=&cid=' . $contact['abook_id'], 'sel' => '', 'title' => t('View recent posts and comments')), 'block' => array('label' => intval($contact['abook_blocked']) ? t('Unblock') : t('Block'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/block', 'sel' => intval($contact['abook_blocked']) ? 'active' : '', 'title' => t('Block (or Unblock) all communications with this connection'), 'info' => intval($contact['abook_blocked']) ? t('This connection is blocked!') : ''), 'ignore' => array('label' => intval($contact['abook_ignored']) ? t('Unignore') : t('Ignore'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/ignore', 'sel' => intval($contact['abook_ignored']) ? 'active' : '', 'title' => t('Ignore (or Unignore) all inbound communications from this connection'), 'info' => intval($contact['abook_ignored']) ? t('This connection is ignored!') : ''), 'archive' => array('label' => intval($contact['abook_archived']) ? t('Unarchive') : t('Archive'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/archive', 'sel' => intval($contact['abook_archived']) ? 'active' : '', 'title' => t('Archive (or Unarchive) this connection - mark channel dead but keep content'), 'info' => intval($contact['abook_archived']) ? t('This connection is archived!') : ''), 'hide' => array('label' => intval($contact['abook_hidden']) ? t('Unhide') : t('Hide'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/hide', 'sel' => intval($contact['abook_hidden']) ? 'active' : '', 'title' => t('Hide or Unhide this connection from your other connections'), 'info' => intval($contact['abook_hidden']) ? t('This connection is hidden!') : ''), 'delete' => array('label' => t('Delete'), 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/drop', 'sel' => '', 'title' => t('Delete this connection')));
         $self = false;
         if (intval($contact['abook_self'])) {
             $self = true;
         }
         require_once 'include/contact_selectors.php';
         $tpl = get_markup_template("abook_edit.tpl");
         if (feature_enabled(local_channel(), 'affinity')) {
             $labels = array(t('Me'), t('Family'), t('Friends'), t('Acquaintances'), t('All'));
             call_hooks('affinity_labels', $labels);
             $label_str = '';
             if ($labels) {
                 foreach ($labels as $l) {
                     if ($label_str) {
                         $label_str .= ", '|'";
                         $label_str .= ", '" . $l . "'";
                     } else {
                         $label_str .= "'" . $l . "'";
                     }
                 }
             }
             $slider_tpl = get_markup_template('contact_slider.tpl');
             $slide = replace_macros($slider_tpl, array('$min' => 1, '$val' => $contact['abook_closeness'] ? $contact['abook_closeness'] : 99, '$labels' => $label_str));
         }
         $rating_val = 0;
         $rating_text = '';
         $xl = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1", dbesc($channel['channel_hash']), dbesc($contact['xchan_hash']));
         if ($xl) {
             $rating_val = intval($xl[0]['xlink_rating']);
             $rating_text = $xl[0]['xlink_rating_text'];
         }
         $poco_rating = get_config('system', 'poco_rating_enable');
         // if unset default to enabled
         if ($poco_rating === false) {
             $poco_rating = true;
         }
         if ($poco_rating) {
             $rating = replace_macros(get_markup_template('rating_slider.tpl'), array('$min' => -10, '$val' => $rating_val));
         } else {
             $rating = false;
         }
         $perms = array();
         $channel = \App::get_channel();
         $global_perms = get_perms();
         $existing = get_all_perms(local_channel(), $contact['abook_xchan']);
         $unapproved = array('pending', t('Approve this connection'), '', t('Accept connection to allow communication'), array(t('No'), 'Yes'));
         $multiprofs = feature_enabled(local_channel(), 'multi_profiles') ? true : false;
         if ($slide && !$multiprofs) {
             $affinity = t('Set Affinity');
         }
         if (!$slide && $multiprofs) {
             $affinity = t('Set Profile');
         }
         if ($slide && $multiprofs) {
             $affinity = t('Set Affinity & Profile');
         }
         foreach ($global_perms as $k => $v) {
             $thisperm = $contact['abook_my_perms'] & $v[1] ? "1" : '';
             $checkinherited = $channel[$v[0]] && $channel[$v[0]] != PERMS_SPECIFIC ? "1" : '';
             // For auto permissions (when $self is true) we don't want to look at existing
             // permissions because they are enabled for the channel owner
             if (!$self && $existing[$k]) {
                 $thisperm = "1";
             }
             $perms[] = array('perms_' . $k, $v[3], $contact['abook_their_perms'] & $v[1] ? "1" : "", $thisperm, $v[1], $channel[$v[0]] == PERMS_SPECIFIC ? '' : '1', $v[4], $checkinherited);
         }
         $locstr = '';
         $locs = q("select hubloc_addr as location from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s'\n\t\t\t\tand hubloc_deleted = 0 and site_dead = 0", dbesc($contact['xchan_hash']));
         if ($locs) {
             foreach ($locs as $l) {
                 if (!$l['location']) {
                     continue;
                 }
                 if (strpos($locstr, $l['location']) !== false) {
                     continue;
                 }
                 if (strlen($locstr)) {
                     $locstr .= ', ';
                 }
                 $locstr .= $l['location'];
             }
         } else {
             $locstr = t('none');
         }
         $o .= replace_macros($tpl, array('$header' => $self ? t('Connection Default Permissions') : sprintf(t('Connection: %s'), $contact['xchan_name']), '$autoperms' => array('autoperms', t('Apply these permissions automatically'), get_pconfig(local_channel(), 'system', 'autoperms') ? 1 : 0, t('Connection requests will be approved without your interaction'), $yes_no), '$addr' => $contact['xchan_addr'], '$addr_text' => t('This connection\'s primary address is'), '$loc_text' => t('Available locations:'), '$locstr' => $locstr, '$notself' => $self ? '' : '1', '$self' => $self ? '1' : '', '$autolbl' => t('The permissions indicated on this page will be applied to all new connections.'), '$tools_label' => t('Connection Tools'), '$tools' => $self ? '' : $tools, '$lbl_slider' => t('Slide to adjust your degree of friendship'), '$lbl_rating' => t('Rating'), '$lbl_rating_label' => t('Slide to adjust your rating'), '$lbl_rating_txt' => t('Optionally explain your rating'), '$connfilter' => feature_enabled(local_channel(), 'connfilter'), '$connfilter_label' => t('Custom Filter'), '$incl' => array('abook_incl', t('Only import posts with this text'), $contact['abook_incl'], t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')), '$excl' => array('abook_excl', t('Do not import posts with this text'), $contact['abook_excl'], t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')), '$rating_text' => array('rating_text', t('Optionally explain your rating'), $rating_text, ''), '$rating_info' => t('This information is public!'), '$rating' => $rating, '$rating_val' => $rating_val, '$slide' => $slide, '$affinity' => $affinity, '$pending_label' => t('Connection Pending Approval'), '$is_pending' => intval($contact['abook_pending']) ? 1 : '', '$unapproved' => $unapproved, '$inherited' => t('inherited'), '$submit' => t('Submit'), '$lbl_vis2' => sprintf(t('Please choose the profile you would like to display to %s when viewing your profile securely.'), $contact['xchan_name']), '$close' => $contact['abook_closeness'], '$them' => t('Their Settings'), '$me' => t('My Settings'), '$perms' => $perms, '$permlbl' => t('Individual Permissions'), '$permnote' => t('Some permissions may be inherited from your channel\'s <a href="settings"><strong>privacy settings</strong></a>, which have higher priority than individual settings. You can <strong>not</strong> change those settings here.'), '$permnote_self' => t('Some permissions may be inherited from your channel\'s <a href="settings"><strong>privacy settings</strong></a>, which have higher priority than individual settings. You can change those settings here but they wont have any impact unless the inherited setting changes.'), '$lastupdtext' => t('Last update:'), '$last_update' => relative_date($contact['abook_connected']), '$profile_select' => contact_profile_assign($contact['abook_profile']), '$multiprofs' => $multiprofs, '$contact_id' => $contact['abook_id'], '$name' => $contact['xchan_name']));
         $arr = array('contact' => $contact, 'output' => $o);
         call_hooks('contact_edit', $arr);
         return $arr['output'];
     }
 }
예제 #8
0
파일: zot.php 프로젝트: 23n/hubzilla
/**
 * @brief
 *
 * @param array $sender
 * @param array $arr
 * @param array $deliveries
 * @return array
 */
function process_channel_sync_delivery($sender, $arr, $deliveries)
{
    require_once 'include/import.php';
    /** @FIXME this will sync red structures (channel, pconfig and abook). Eventually we need to make this application agnostic. */
    $result = array();
    foreach ($deliveries as $d) {
        $r = q("select * from channel where channel_hash = '%s' limit 1", dbesc($d['hash']));
        if (!$r) {
            $result[] = array($d['hash'], 'not found');
            continue;
        }
        $channel = $r[0];
        $max_friends = service_class_fetch($channel['channel_id'], 'total_channels');
        $max_feeds = account_service_class_fetch($channel['channel_account_id'], 'total_feeds');
        if ($channel['channel_hash'] != $sender['hash']) {
            logger('process_channel_sync_delivery: possible forgery. Sender ' . $sender['hash'] . ' is not ' . $channel['channel_hash']);
            $result[] = array($d['hash'], 'channel mismatch', $channel['channel_name'], '');
            continue;
        }
        if (array_key_exists('config', $arr) && is_array($arr['config']) && count($arr['config'])) {
            foreach ($arr['config'] as $cat => $k) {
                foreach ($arr['config'][$cat] as $k => $v) {
                    set_pconfig($channel['channel_id'], $cat, $k, $v);
                }
            }
        }
        if (array_key_exists('obj', $arr) && $arr['obj']) {
            sync_objs($channel, $arr['obj']);
        }
        if (array_key_exists('likes', $arr) && $arr['likes']) {
            import_likes($channel, $arr['likes']);
        }
        if (array_key_exists('app', $arr) && $arr['app']) {
            sync_apps($channel, $arr['app']);
        }
        if (array_key_exists('chatroom', $arr) && $arr['chatroom']) {
            sync_chatrooms($channel, $arr['chatroom']);
        }
        if (array_key_exists('conv', $arr) && $arr['conv']) {
            import_conv($channel, $arr['conv']);
        }
        if (array_key_exists('mail', $arr) && $arr['mail']) {
            import_mail($channel, $arr['mail']);
        }
        if (array_key_exists('event', $arr) && $arr['event']) {
            sync_events($channel, $arr['event']);
        }
        if (array_key_exists('event_item', $arr) && $arr['event_item']) {
            sync_items($channel, $arr['event_item']);
        }
        if (array_key_exists('item', $arr) && $arr['item']) {
            sync_items($channel, $arr['item']);
        }
        if (array_key_exists('item_id', $arr) && $arr['item_id']) {
            sync_items($channel, $arr['item_id']);
        }
        if (array_key_exists('menu', $arr) && $arr['menu']) {
            sync_menus($channel, $arr['menu']);
        }
        if (array_key_exists('channel', $arr) && is_array($arr['channel']) && count($arr['channel'])) {
            if (array_key_exists('channel_pageflags', $arr['channel']) && intval($arr['channel']['channel_pageflags'])) {
                // These flags cannot be sync'd.
                // remove the bits from the incoming flags.
                // These correspond to PAGE_REMOVED and PAGE_SYSTEM on redmatrix
                if ($arr['channel']['channel_pageflags'] & 0x8000) {
                    $arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] - 0x8000;
                }
                if ($arr['channel']['channel_pageflags'] & 0x1000) {
                    $arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] - 0x1000;
                }
            }
            $disallowed = array('channel_id', 'channel_account_id', 'channel_primary', 'channel_prvkey', 'channel_address', 'channel_notifyflags', 'channel_removed', 'channel_deleted', 'channel_system');
            $clean = array();
            foreach ($arr['channel'] as $k => $v) {
                if (in_array($k, $disallowed)) {
                    continue;
                }
                $clean[$k] = $v;
            }
            if (count($clean)) {
                foreach ($clean as $k => $v) {
                    $r = dbq("UPDATE channel set " . dbesc($k) . " = '" . dbesc($v) . "' where channel_id = " . intval($channel['channel_id']));
                }
            }
        }
        if (array_key_exists('abook', $arr) && is_array($arr['abook']) && count($arr['abook'])) {
            $total_friends = 0;
            $total_feeds = 0;
            $r = q("select abook_id, abook_feed from abook where abook_channel = %d", intval($channel['channel_id']));
            if ($r) {
                // don't count yourself
                $total_friends = count($r) > 0 ? count($r) - 1 : 0;
                foreach ($r as $rr) {
                    if (intval($rr['abook_feed'])) {
                        $total_feeds++;
                    }
                }
            }
            $disallowed = array('abook_id', 'abook_account', 'abook_channel', 'abook_rating', 'abook_rating_text');
            foreach ($arr['abook'] as $abook) {
                if (!array_key_exists('abook_blocked', $abook)) {
                    // convert from redmatrix
                    $abook['abook_blocked'] = $abook['abook_flags'] & 0x1 ? 1 : 0;
                    $abook['abook_ignored'] = $abook['abook_flags'] & 0x2 ? 1 : 0;
                    $abook['abook_hidden'] = $abook['abook_flags'] & 0x4 ? 1 : 0;
                    $abook['abook_archived'] = $abook['abook_flags'] & 0x8 ? 1 : 0;
                    $abook['abook_pending'] = $abook['abook_flags'] & 0x10 ? 1 : 0;
                    $abook['abook_unconnected'] = $abook['abook_flags'] & 0x20 ? 1 : 0;
                    $abook['abook_self'] = $abook['abook_flags'] & 0x80 ? 1 : 0;
                    $abook['abook_feed'] = $abook['abook_flags'] & 0x100 ? 1 : 0;
                }
                $clean = array();
                if ($abook['abook_xchan'] && $abook['entry_deleted']) {
                    logger('process_channel_sync_delivery: removing abook entry for ' . $abook['abook_xchan']);
                    require_once 'include/Contact.php';
                    $r = q("select abook_id, abook_feed from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1", dbesc($abook['abook_xchan']), intval($channel['channel_id']));
                    if ($r) {
                        contact_remove($channel['channel_id'], $r[0]['abook_id']);
                        if ($total_friends) {
                            $total_friends--;
                        }
                        if (intval($r[0]['abook_feed'])) {
                            $total_feeds--;
                        }
                    }
                    continue;
                }
                // Perform discovery if the referenced xchan hasn't ever been seen on this hub.
                // This relies on the undocumented behaviour that red sites send xchan info with the abook
                // and import_author_xchan will look them up on all federated networks
                if ($abook['abook_xchan'] && $abook['xchan_addr']) {
                    $h = zot_get_hublocs($abook['abook_xchan']);
                    if (!$h) {
                        $xhash = import_author_xchan(encode_item_xchan($abook));
                        if (!$xhash) {
                            logger('process_channel_sync_delivery: import of ' . $abook['xchan_addr'] . ' failed.');
                            continue;
                        }
                    }
                }
                foreach ($abook as $k => $v) {
                    if (in_array($k, $disallowed) || strpos($k, 'abook') !== 0) {
                        continue;
                    }
                    $clean[$k] = $v;
                }
                if (!array_key_exists('abook_xchan', $clean)) {
                    continue;
                }
                $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", dbesc($clean['abook_xchan']), intval($channel['channel_id']));
                // make sure we have an abook entry for this xchan on this system
                if (!$r) {
                    if ($max_friends !== false && $total_friends > $max_friends) {
                        logger('process_channel_sync_delivery: total_channels service class limit exceeded');
                        continue;
                    }
                    if ($max_feeds !== false && intval($clean['abook_feed']) && $total_feeds > $max_feeds) {
                        logger('process_channel_sync_delivery: total_feeds service class limit exceeded');
                        continue;
                    }
                    q("insert into abook ( abook_xchan, abook_channel ) values ('%s', %d ) ", dbesc($clean['abook_xchan']), intval($channel['channel_id']));
                    $total_friends++;
                    if (intval($clean['abook_feed'])) {
                        $total_feeds++;
                    }
                }
                if (count($clean)) {
                    foreach ($clean as $k => $v) {
                        if ($k == 'abook_dob') {
                            $v = dbescdate($v);
                        }
                        $r = dbq("UPDATE abook set " . dbesc($k) . " = '" . dbesc($v) . "' where abook_xchan = '" . dbesc($clean['abook_xchan']) . "' and abook_channel = " . intval($channel['channel_id']));
                    }
                }
            }
        }
        // sync collections (privacy groups) oh joy...
        if (array_key_exists('collections', $arr) && is_array($arr['collections']) && count($arr['collections'])) {
            $x = q("select * from groups where uid = %d", intval($channel['channel_id']));
            foreach ($arr['collections'] as $cl) {
                $found = false;
                if ($x) {
                    foreach ($x as $y) {
                        if ($cl['collection'] == $y['hash']) {
                            $found = true;
                            break;
                        }
                    }
                    if ($found) {
                        if ($y['name'] != $cl['name'] || $y['visible'] != $cl['visible'] || $y['deleted'] != $cl['deleted']) {
                            q("update groups set name = '%s', visible = %d, deleted = %d where hash = '%s' and uid = %d", dbesc($cl['name']), intval($cl['visible']), intval($cl['deleted']), dbesc($cl['hash']), intval($channel['channel_id']));
                        }
                        if (intval($cl['deleted']) && !intval($y['deleted'])) {
                            q("delete from group_member where gid = %d", intval($y['id']));
                        }
                    }
                }
                if (!$found) {
                    $r = q("INSERT INTO `groups` ( hash, uid, visible, deleted, name )\n\t\t\t\t\t\tVALUES( '%s', %d, %d, %d, '%s' ) ", dbesc($cl['collection']), intval($channel['channel_id']), intval($cl['visible']), intval($cl['deleted']), dbesc($cl['name']));
                }
                // now look for any collections locally which weren't in the list we just received.
                // They need to be removed by marking deleted and removing the members.
                // This shouldn't happen except for clones created before this function was written.
                if ($x) {
                    $found_local = false;
                    foreach ($x as $y) {
                        foreach ($arr['collections'] as $cl) {
                            if ($cl['collection'] == $y['hash']) {
                                $found_local = true;
                                break;
                            }
                        }
                        if (!$found_local) {
                            q("delete from group_member where gid = %d", intval($y['id']));
                            q("update groups set deleted = 1 where id = %d and uid = %d", intval($y['id']), intval($channel['channel_id']));
                        }
                    }
                }
            }
            // reload the group list with any updates
            $x = q("select * from groups where uid = %d", intval($channel['channel_id']));
            // now sync the members
            if (array_key_exists('collection_members', $arr) && is_array($arr['collection_members']) && count($arr['collection_members'])) {
                // first sort into groups keyed by the group hash
                $members = array();
                foreach ($arr['collection_members'] as $cm) {
                    if (!array_key_exists($cm['collection'], $members)) {
                        $members[$cm['collection']] = array();
                    }
                    $members[$cm['collection']][] = $cm['member'];
                }
                // our group list is already synchronised
                if ($x) {
                    foreach ($x as $y) {
                        // for each group, loop on members list we just received
                        foreach ($members[$y['hash']] as $member) {
                            $found = false;
                            $z = q("select xchan from group_member where gid = %d and uid = %d and xchan = '%s' limit 1", intval($y['id']), intval($channel['channel_id']), dbesc($member));
                            if ($z) {
                                $found = true;
                            }
                            // if somebody is in the group that wasn't before - add them
                            if (!$found) {
                                q("INSERT INTO `group_member` (`uid`, `gid`, `xchan`)\n\t\t\t\t\t\t\t\t\tVALUES( %d, %d, '%s' ) ", intval($channel['channel_id']), intval($y['id']), dbesc($member));
                            }
                        }
                        // now retrieve a list of members we have on this site
                        $m = q("select xchan from group_member where gid = %d and uid = %d", intval($y['id']), intval($channel['channel_id']));
                        if ($m) {
                            foreach ($m as $mm) {
                                // if the local existing member isn't in the list we just received - remove them
                                if (!in_array($mm['xchan'], $members[$y['hash']])) {
                                    q("delete from group_member where xchan = '%s' and gid = %d and uid = %d", dbesc($mm['xchan']), intval($y['id']), intval($channel['channel_id']));
                                }
                            }
                        }
                    }
                }
            }
        }
        if (array_key_exists('profile', $arr) && is_array($arr['profile']) && count($arr['profile'])) {
            $disallowed = array('id', 'aid', 'uid');
            foreach ($arr['profile'] as $profile) {
                $x = q("select * from profile where profile_guid = '%s' and uid = %d limit 1", dbesc($profile['profile_guid']), intval($channel['channel_id']));
                if (!$x) {
                    q("insert into profile ( profile_guid, aid, uid ) values ('%s', %d, %d)", dbesc($profile['profile_guid']), intval($channel['channel_account_id']), intval($channel['channel_id']));
                    $x = q("select * from profile where profile_guid = '%s' and uid = %d limit 1", dbesc($profile['profile_guid']), intval($channel['channel_id']));
                    if (!$x) {
                        continue;
                    }
                }
                $clean = array();
                foreach ($profile as $k => $v) {
                    if (in_array($k, $disallowed)) {
                        continue;
                    }
                    $clean[$k] = $v;
                    /**
                     * @TODO check if these are allowed, otherwise we'll error
                     * We also need to import local photos if a custom photo is selected
                     */
                }
                if (count($clean)) {
                    foreach ($clean as $k => $v) {
                        $r = dbq("UPDATE profile set `" . dbesc($k) . "` = '" . dbesc($v) . "' where profile_guid = '" . dbesc($profile['profile_guid']) . "' and uid = " . intval($channel['channel_id']));
                    }
                }
            }
        }
        if (array_key_exists('item', $arr) && $arr['item']) {
            sync_items($channel, $arr['item']);
        }
        if (array_key_exists('item_id', $arr) && $arr['item_id']) {
            sync_items($channel, $arr['item_id']);
        }
        $addon = array('channel' => $channel, 'data' => $arr);
        call_hooks('process_channel_sync_delivery', $addon);
        // we should probably do this for all items, but usually we only send one.
        require_once 'include/DReport.php';
        if (array_key_exists('item', $arr) && is_array($arr['item'][0])) {
            $DR = new DReport(z_root(), $d['hash'], $d['hash'], $arr['item'][0]['message_id'], 'channel sync processed');
            $DR->addto_recipient($channel['channel_name'] . ' <' . $channel['channel_address'] . '@' . get_app()->get_hostname() . '>');
        } else {
            $DR = new DReport(z_root(), $d['hash'], $d['hash'], 'sync packet', 'channel sync delivered');
        }
        $result[] = $DR->get();
    }
    return $result;
}
예제 #9
0
파일: connedit.php 프로젝트: redmatrix/red
function connedit_content(&$a)
{
    $sort_type = 0;
    $o = '';
    if (!local_channel()) {
        notice(t('Permission denied.') . EOL);
        return login();
    }
    $channel = $a->get_channel();
    $my_perms = get_channel_default_perms(local_channel());
    $role = get_pconfig(local_channel(), 'system', 'permissions_role');
    if ($role) {
        $x = get_role_perms($role);
        if ($x['perms_accept']) {
            $my_perms = $x['perms_accept'];
        }
    }
    if ($my_perms) {
        $o .= "<script>function connectDefaultShare() {\n\t\t\$('.abook-edit-me').each(function() {\n\t\t\tif(! \$(this).is(':disabled'))\n\t\t\t\t\$(this).removeAttr('checked');\n\t\t});\n\n";
        $perms = get_perms();
        foreach ($perms as $p => $v) {
            if ($my_perms & $v[1]) {
                $o .= "\$('#me_id_perms_" . $p . "').attr('checked','checked'); \n";
            }
        }
        $o .= " }\n</script>\n";
    }
    if (argc() == 3) {
        $contact_id = intval(argv(1));
        if (!$contact_id) {
            return;
        }
        $cmd = argv(2);
        $orig_record = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash\n\t\t\tWHERE abook_id = %d AND abook_channel = %d AND NOT ( abook_flags & %d )>0 LIMIT 1", intval($contact_id), intval(local_channel()), intval(ABOOK_FLAG_SELF));
        if (!count($orig_record)) {
            notice(t('Could not access address book record.') . EOL);
            goaway($a->get_baseurl(true) . '/connections');
        }
        if ($cmd === 'update') {
            // pull feed and consume it, which should subscribe to the hub.
            proc_run('php', "include/poller.php", "{$contact_id}");
            goaway($a->get_baseurl(true) . '/connedit/' . $contact_id);
        }
        if ($cmd === 'refresh') {
            if (!zot_refresh($orig_record[0], get_app()->get_channel())) {
                notice(t('Refresh failed - channel is currently unavailable.'));
            }
            goaway($a->get_baseurl(true) . '/connedit/' . $contact_id);
        }
        if ($cmd === 'block') {
            if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_BLOCKED)) {
                info(($orig_record[0]['abook_flags'] & ABOOK_FLAG_BLOCKED ? t('Channel has been unblocked') : t('Channel has been blocked')) . EOL);
                connedit_clone($a);
            } else {
                notice(t('Unable to set address book parameters.') . EOL);
            }
            goaway($a->get_baseurl(true) . '/connedit/' . $contact_id);
        }
        if ($cmd === 'ignore') {
            if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_IGNORED)) {
                info(($orig_record[0]['abook_flags'] & ABOOK_FLAG_IGNORED ? t('Channel has been unignored') : t('Channel has been ignored')) . EOL);
                connedit_clone($a);
            } else {
                notice(t('Unable to set address book parameters.') . EOL);
            }
            goaway($a->get_baseurl(true) . '/connedit/' . $contact_id);
        }
        if ($cmd === 'archive') {
            if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_ARCHIVED)) {
                info(($orig_record[0]['abook_flags'] & ABOOK_FLAG_ARCHIVED ? t('Channel has been unarchived') : t('Channel has been archived')) . EOL);
                connedit_clone($a);
            } else {
                notice(t('Unable to set address book parameters.') . EOL);
            }
            goaway($a->get_baseurl(true) . '/connedit/' . $contact_id);
        }
        if ($cmd === 'hide') {
            if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_HIDDEN)) {
                info(($orig_record[0]['abook_flags'] & ABOOK_FLAG_HIDDEN ? t('Channel has been unhidden') : t('Channel has been hidden')) . EOL);
                connedit_clone($a);
            } else {
                notice(t('Unable to set address book parameters.') . EOL);
            }
            goaway($a->get_baseurl(true) . '/connedit/' . $contact_id);
        }
        // We'll prevent somebody from unapproving an already approved contact.
        // Though maybe somebody will want this eventually (??)
        if ($cmd === 'approve') {
            if ($orig_record[0]['abook_flags'] & ABOOK_FLAG_PENDING) {
                if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_PENDING)) {
                    info(($orig_record[0]['abook_flags'] & ABOOK_FLAG_PENDING ? t('Channel has been approved') : t('Channel has been unapproved')) . EOL);
                    connedit_clone($a);
                } else {
                    notice(t('Unable to set address book parameters.') . EOL);
                }
            }
            goaway($a->get_baseurl(true) . '/connedit/' . $contact_id);
        }
        if ($cmd === 'drop') {
            require_once 'include/Contact.php';
            // FIXME
            // We need to send either a purge or a refresh packet to the other side (the channel being unfriended).
            // The issue is that the abook DB record _may_ get destroyed when we call contact_remove. As the notifier runs
            // in the background there could be a race condition preventing this packet from being sent in all cases.
            // PLACEHOLDER
            contact_remove(local_channel(), $orig_record[0]['abook_id']);
            build_sync_packet(0, array('abook' => array(array('abook_xchan' => $orig_record[0]['abook_xchan'], 'entry_deleted' => true))));
            info(t('Connection has been removed.') . EOL);
            if (x($_SESSION, 'return_url')) {
                goaway($a->get_baseurl(true) . '/' . $_SESSION['return_url']);
            }
            goaway($a->get_baseurl(true) . '/contacts');
        }
    }
    if ($a->poi) {
        $contact_id = $a->poi['abook_id'];
        $contact = $a->poi;
        $tabs = array(array('label' => t('View Profile'), 'url' => chanlink_cid($contact['abook_id']), 'sel' => '', 'title' => sprintf(t('View %s\'s profile'), $contact['xchan_name'])), array('label' => t('Refresh Permissions'), 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/refresh', 'sel' => '', 'title' => t('Fetch updated permissions')), array('label' => t('Recent Activity'), 'url' => $a->get_baseurl(true) . '/network/?f=&cid=' . $contact['abook_id'], 'sel' => '', 'title' => t('View recent posts and comments')));
        $buttons = array(array('label' => $contact['abook_flags'] & ABOOK_FLAG_BLOCKED ? t('Unblock') : t('Block'), 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/block', 'sel' => $contact['abook_flags'] & ABOOK_FLAG_BLOCKED ? 'active' : '', 'title' => t('Block (or Unblock) all communications with this connection')), array('label' => $contact['abook_flags'] & ABOOK_FLAG_IGNORED ? t('Unignore') : t('Ignore'), 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/ignore', 'sel' => $contact['abook_flags'] & ABOOK_FLAG_IGNORED ? 'active' : '', 'title' => t('Ignore (or Unignore) all inbound communications from this connection')), array('label' => $contact['abook_flags'] & ABOOK_FLAG_ARCHIVED ? t('Unarchive') : t('Archive'), 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/archive', 'sel' => $contact['abook_flags'] & ABOOK_FLAG_ARCHIVED ? 'active' : '', 'title' => t('Archive (or Unarchive) this connection - mark channel dead but keep content')), array('label' => $contact['abook_flags'] & ABOOK_FLAG_HIDDEN ? t('Unhide') : t('Hide'), 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/hide', 'sel' => $contact['abook_flags'] & ABOOK_FLAG_HIDDEN ? 'active' : '', 'title' => t('Hide or Unhide this connection from your other connections')), array('label' => t('Delete'), 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/drop', 'sel' => '', 'title' => t('Delete this connection')));
        $self = false;
        if (!($contact['abook_flags'] & ABOOK_FLAG_SELF)) {
            $tab_tpl = get_markup_template('common_tabs.tpl');
            $t = replace_macros($tab_tpl, array('$tabs' => $tabs));
        } else {
            $self = true;
        }
        $a->page['htmlhead'] .= replace_macros(get_markup_template('contact_head.tpl'), array('$baseurl' => $a->get_baseurl(true), '$editselect' => $editselect));
        require_once 'include/contact_selectors.php';
        $tpl = get_markup_template("abook_edit.tpl");
        if (feature_enabled(local_channel(), 'affinity')) {
            $slider_tpl = get_markup_template('contact_slider.tpl');
            $slide = replace_macros($slider_tpl, array('$me' => t('Me'), '$min' => 1, '$val' => $contact['abook_closeness'] ? $contact['abook_closeness'] : 99, '$intimate' => t('Best Friends'), '$friends' => t('Friends'), '$oldfriends' => t('Former Friends'), '$acquaintances' => t('Acquaintances'), '$world' => t('Unknown')));
        }
        $rating_val = 0;
        $rating_text = '';
        $xl = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1", dbesc($channel['channel_hash']), dbesc($contact['xchan_hash']));
        if ($xl) {
            $rating_val = intval($xl[0]['xlink_rating']);
            $rating_text = $xl[0]['xlink_rating_text'];
        }
        $poco_rating = get_config('system', 'poco_rating_enable');
        // if unset default to enabled
        if ($poco_rating === false) {
            $poco_rating = true;
        }
        if ($poco_rating) {
            $rating = replace_macros(get_markup_template('rating_slider.tpl'), array('$min' => -10, '$val' => $rating_val));
        } else {
            $rating = false;
        }
        $perms = array();
        $channel = $a->get_channel();
        $global_perms = get_perms();
        $existing = get_all_perms(local_channel(), $contact['abook_xchan']);
        $unapproved = array('pending', t('Approve this connection'), '', t('Accept connection to allow communication'));
        foreach ($global_perms as $k => $v) {
            $thisperm = $contact['abook_my_perms'] & $v[1] ? "1" : '';
            // For auto permissions (when $self is true) we don't want to look at existing
            // permissions because they are enabled for the channel owner
            if (!$self && $existing[$k]) {
                $thisperm = "1";
            }
            $perms[] = array('perms_' . $k, $v[3], $contact['abook_their_perms'] & $v[1] ? "1" : "", $thisperm, $v[1], $channel[$v[0]] == PERMS_SPECIFIC || $self ? '' : '1', $v[4]);
        }
        $o .= replace_macros($tpl, array('$header' => $self ? t('Connection Default Permissions') : sprintf(t('Connections: settings for %s'), $contact['xchan_name']), '$autoperms' => array('autoperms', t('Apply these permissions automatically'), get_pconfig(local_channel(), 'system', 'autoperms') ? 1 : 0, ''), '$addr' => $contact['xchan_addr'], '$notself' => $self ? '' : '1', '$self' => $self ? '1' : '', '$autolbl' => t('Apply the permissions indicated on this page to all new connections.'), '$buttons' => $self ? '' : $buttons, '$viewprof' => t('View Profile'), '$clickme' => t('Click to open/close'), '$lbl_slider' => t('Slide to adjust your degree of friendship'), '$lbl_rating' => t('Rating (this information is public)'), '$lbl_rating_txt' => t('Optionally explain your rating (this information is public)'), '$rating_txt' => $rating_text, '$rating' => $rating, '$rating_val' => $rating_val, '$slide' => $slide, '$tabs' => $t, '$tab_str' => $tab_str, '$perms_step1' => t('Default permissions for your channel type have (just) been applied. They have not yet been submitted. Please review the permissions on this page and make any desired changes at this time. This new connection may <em>not</em> be able to communicate with you until you submit this page, which will install and apply the selected permissions.'), '$is_pending' => $contact['abook_flags'] & ABOOK_FLAG_PENDING ? 1 : '', '$unapproved' => $unapproved, '$inherited' => t('inherited'), '$approve' => t('Approve this connection'), '$noperms' => $contact['abook_my_perms'] ? false : true, '$no_perms' => !$self && !$contact['abook_my_perms'] ? t('Connection has no individual permissions!') : '', '$noperm_desc' => !$self && !$contact['abook_my_perms'] ? t('This may be appropriate based on your <a href="settings">privacy settings</a>, though you may wish to review the "Advanced Permissions".') : '', '$submit' => t('Submit'), '$lbl_vis1' => t('Profile Visibility'), '$lbl_vis2' => sprintf(t('Please choose the profile you would like to display to %s when viewing your profile securely.'), $contact['xchan_name']), '$lbl_info1' => t('Contact Information / Notes'), '$infedit' => t('Edit contact notes'), '$close' => $contact['abook_closeness'], '$them' => t('Their Settings'), '$me' => t('My Settings'), '$perms' => $perms, '$perms_new' => t('Default permissions for this channel type have (just) been applied. They have <em>not</em> been saved and there are currently no stored default permissions. Please review/edit the applied settings and click [Submit] to finalize.'), '$clear' => t('Clear/Disable Automatic Permissions'), '$forum' => t('Forum Members'), '$soapbox' => t('Soapbox'), '$full' => t('Full Sharing (typical social network permissions)'), '$cautious' => t('Cautious Sharing '), '$follow' => t('Follow Only'), '$permlbl' => t('Individual Permissions'), '$permnote' => t('Some permissions may be inherited from your channel <a href="settings">privacy settings</a>, which have higher priority than individual settings. Changing those inherited settings on this page will have no effect.'), '$advanced' => t('Advanced Permissions'), '$quick' => t('Simple Permissions (select one and submit)'), '$common_link' => $a->get_baseurl(true) . '/common/loc/' . local_channel() . '/' . $contact['id'], '$all_friends' => $all_friends, '$relation_text' => $relation_text, '$visit' => sprintf(t('Visit %s\'s profile - %s'), $contact['xchan_name'], $contact['xchan_url']), '$blockunblock' => t('Block/Unblock contact'), '$ignorecont' => t('Ignore contact'), '$lblcrepair' => t("Repair URL settings"), '$lblrecent' => t('View conversations'), '$lblsuggest' => $lblsuggest, '$delete' => t('Delete contact'), '$poll_interval' => contact_poll_interval($contact['priority'], !$poll_enabled), '$poll_enabled' => $poll_enabled, '$lastupdtext' => t('Last update:'), '$lost_contact' => $lost_contact, '$updpub' => t('Update public posts'), '$last_update' => relative_date($contact['abook_connected']), '$udnow' => t('Update now'), '$profile_select' => contact_profile_assign($contact['abook_profile']), '$multiprofs' => feature_enabled(local_channel(), 'multi_profiles'), '$contact_id' => $contact['abook_id'], '$block_text' => $contact['blocked'] ? t('Unblock') : t('Block'), '$ignore_text' => $contact['readonly'] ? t('Unignore') : t('Ignore'), '$blocked' => $contact['blocked'] ? t('Currently blocked') : '', '$ignored' => $contact['readonly'] ? t('Currently ignored') : '', '$archived' => $contact['archive'] ? t('Currently archived') : '', '$pending' => $contact['archive'] ? t('Currently pending') : '', '$name' => $contact['name'], '$alt_text' => $alt_text, '$url' => $url));
        $arr = array('contact' => $contact, 'output' => $o);
        call_hooks('contact_edit', $arr);
        return $arr['output'];
    }
}
예제 #10
0
파일: connedit.php 프로젝트: Mauru/red
function connedit_content(&$a)
{
    $sort_type = 0;
    $o = '';
    // this triggers some javascript to set Full Sharing by default after
    // completing a "follow" - which can be changed to something else before
    // form submission, but this gives us something useable
    if ($_GET['follow'] == 1) {
        $o .= '<script>var after_following = 1;</script>';
    }
    if (!local_user()) {
        notice(t('Permission denied.') . EOL);
        return login();
    }
    if (argc() == 3) {
        $contact_id = intval(argv(1));
        if (!$contact_id) {
            return;
        }
        $cmd = argv(2);
        $orig_record = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash\n\t\t\tWHERE abook_id = %d AND abook_channel = %d AND NOT ( abook_flags & %d ) LIMIT 1", intval($contact_id), intval(local_user()), intval(ABOOK_FLAG_SELF));
        if (!count($orig_record)) {
            notice(t('Could not access address book record.') . EOL);
            goaway($a->get_baseurl(true) . '/connections');
        }
        if ($cmd === 'update') {
            // pull feed and consume it, which should subscribe to the hub.
            proc_run('php', "include/poller.php", "{$contact_id}");
            goaway($a->get_baseurl(true) . '/connedit/' . $contact_id);
        }
        if ($cmd === 'refresh') {
            if (!zot_refresh($orig_record[0], get_app()->get_channel())) {
                notice(t('Refresh failed - channel is currently unavailable.'));
            }
            goaway($a->get_baseurl(true) . '/connedit/' . $contact_id);
        }
        if ($cmd === 'block') {
            if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_BLOCKED)) {
                info(($orig_record[0]['abook_flags'] & ABOOK_FLAG_BLOCKED ? t('Channel has been unblocked') : t('Channel has been blocked')) . EOL);
                connedit_clone($a);
            } else {
                notice(t('Unable to set address book parameters.') . EOL);
            }
            goaway($a->get_baseurl(true) . '/connedit/' . $contact_id);
        }
        if ($cmd === 'ignore') {
            if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_IGNORED)) {
                info(($orig_record[0]['abook_flags'] & ABOOK_FLAG_IGNORED ? t('Channel has been unignored') : t('Channel has been ignored')) . EOL);
                connedit_clone($a);
            } else {
                notice(t('Unable to set address book parameters.') . EOL);
            }
            goaway($a->get_baseurl(true) . '/connedit/' . $contact_id);
        }
        if ($cmd === 'archive') {
            if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_ARCHIVED)) {
                info(($orig_record[0]['abook_flags'] & ABOOK_FLAG_ARCHIVED ? t('Channel has been unarchived') : t('Channel has been archived')) . EOL);
                connedit_clone($a);
            } else {
                notice(t('Unable to set address book parameters.') . EOL);
            }
            goaway($a->get_baseurl(true) . '/connedit/' . $contact_id);
        }
        if ($cmd === 'hide') {
            if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_HIDDEN)) {
                info(($orig_record[0]['abook_flags'] & ABOOK_FLAG_HIDDEN ? t('Channel has been unhidden') : t('Channel has been hidden')) . EOL);
                connedit_clone($a);
            } else {
                notice(t('Unable to set address book parameters.') . EOL);
            }
            goaway($a->get_baseurl(true) . '/connedit/' . $contact_id);
        }
        // We'll prevent somebody from unapproving an already approved contact.
        // Though maybe somebody will want this eventually (??)
        if ($cmd === 'approve') {
            if ($orig_record[0]['abook_flags'] & ABOOK_FLAG_PENDING) {
                if (abook_toggle_flag($orig_record[0], ABOOK_FLAG_PENDING)) {
                    info(($orig_record[0]['abook_flags'] & ABOOK_FLAG_PENDING ? t('Channel has been approved') : t('Channel has been unapproved')) . EOL);
                    connedit_clone($a);
                } else {
                    notice(t('Unable to set address book parameters.') . EOL);
                }
            }
            goaway($a->get_baseurl(true) . '/connedit/' . $contact_id);
        }
        if ($cmd === 'drop') {
            require_once 'include/Contact.php';
            // FIXME
            // We need to send either a purge or a refresh packet to the other side (the channel being unfriended).
            // The issue is that the abook DB record _may_ get destroyed when we call contact_remove. As the notifier runs
            // in the background there could be a race condition preventing this packet from being sent in all cases.
            // PLACEHOLDER
            contact_remove(local_user(), $orig_record[0]['abook_id']);
            build_sync_packet(0, array('abook' => array('abook_xchan' => $orig_record[0]['abook_xchan'], 'entry_deleted' => true)));
            info(t('Connection has been removed.') . EOL);
            if (x($_SESSION, 'return_url')) {
                goaway($a->get_baseurl(true) . '/' . $_SESSION['return_url']);
            }
            goaway($a->get_baseurl(true) . '/contacts');
        }
    }
    if ($a->poi) {
        $contact_id = $a->poi['abook_id'];
        $contact = $a->poi;
        $tabs = array(array('label' => t('View Profile'), 'url' => chanlink_cid($contact['abook_id']), 'sel' => '', 'title' => sprintf(t('View %s\'s profile'), $contact['xchan_name'])), array('label' => t('Refresh Permissions'), 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/refresh', 'sel' => '', 'title' => t('Fetch updated permissions')), array('label' => t('Recent Activity'), 'url' => $a->get_baseurl(true) . '/network/?f=&cid=' . $contact['abook_id'], 'sel' => '', 'title' => t('View recent posts and comments')), array('label' => $contact['abook_flags'] & ABOOK_FLAG_BLOCKED ? t('Unblock') : t('Block'), 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/block', 'sel' => $contact['abook_flags'] & ABOOK_FLAG_BLOCKED ? 'active' : '', 'title' => t('Block or Unblock this connection')), array('label' => $contact['abook_flags'] & ABOOK_FLAG_IGNORED ? t('Unignore') : t('Ignore'), 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/ignore', 'sel' => $contact['abook_flags'] & ABOOK_FLAG_IGNORED ? 'active' : '', 'title' => t('Ignore or Unignore this connection')), array('label' => $contact['abook_flags'] & ABOOK_FLAG_ARCHIVED ? t('Unarchive') : t('Archive'), 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/archive', 'sel' => $contact['abook_flags'] & ABOOK_FLAG_ARCHIVED ? 'active' : '', 'title' => t('Archive or Unarchive this connection')), array('label' => $contact['abook_flags'] & ABOOK_FLAG_HIDDEN ? t('Unhide') : t('Hide'), 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/hide', 'sel' => $contact['abook_flags'] & ABOOK_FLAG_HIDDEN ? 'active' : '', 'title' => t('Hide or Unhide this connection')), array('label' => t('Delete'), 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/drop', 'sel' => '', 'title' => t('Delete this connection')));
        $self = false;
        if (!($contact['abook_flags'] & ABOOK_FLAG_SELF)) {
            $tab_tpl = get_markup_template('common_tabs.tpl');
            $t = replace_macros($tab_tpl, array('$tabs' => $tabs));
        } else {
            $self = true;
        }
        $a->page['htmlhead'] .= replace_macros(get_markup_template('contact_head.tpl'), array('$baseurl' => $a->get_baseurl(true), '$editselect' => $editselect));
        require_once 'include/contact_selectors.php';
        $tpl = get_markup_template("abook_edit.tpl");
        if (feature_enabled(local_user(), 'affinity')) {
            $slider_tpl = get_markup_template('contact_slider.tpl');
            $slide = replace_macros($slider_tpl, array('$me' => t('Me'), '$val' => $contact['abook_closeness'] ? $contact['abook_closeness'] : 99, '$intimate' => t('Best Friends'), '$friends' => t('Friends'), '$oldfriends' => t('Former Friends'), '$acquaintances' => t('Acquaintances'), '$world' => t('Unknown')));
        }
        $perms = array();
        $channel = $a->get_channel();
        $global_perms = get_perms();
        $existing = get_all_perms(local_user(), $contact['abook_xchan']);
        $unapproved = array('pending', t('Approve this connection'), '', t('Accept connection to allow communication'));
        foreach ($global_perms as $k => $v) {
            $thisperm = $contact['abook_my_perms'] & $v[1] ? "1" : '';
            // For auto permissions (when $self is true) we don't want to look at existing
            // permissions because they are enabled for the channel owner
            if (!$self && $existing[$k]) {
                $thisperm = "1";
            }
            $perms[] = array('perms_' . $k, $v[3], $contact['abook_their_perms'] & $v[1] ? "1" : "", $thisperm, $v[1], $channel[$v[0]] == PERMS_SPECIFIC ? '' : '1', $v[4]);
        }
        $o .= replace_macros($tpl, array('$header' => $self ? t('Automatic Permissions Settings') : sprintf(t('Connections: settings for %s'), $contact['xchan_name']), '$addr' => $contact['xchan_addr'], '$notself' => $self ? '' : '1', '$self' => $self ? '1' : '', '$autolbl' => t('When receiving a channel introduction, any permissions provided here will be applied to the new connection automatically and the introduction approved. Leave this page if you do not wish to use this feature.'), '$viewprof' => t('View Profile'), '$lbl_slider' => t('Slide to adjust your degree of friendship'), '$slide' => $slide, '$tabs' => $t, '$tab_str' => $tab_str, '$is_pending' => $contact['abook_flags'] & ABOOK_FLAG_PENDING ? 1 : '', '$unapproved' => $unapproved, '$inherited' => t('inherited'), '$approve' => t('Approve this connection'), '$noperms' => !$self && !$contact['abook_my_perms'] ? t('Connection has no individual permissions!') : '', '$noperm_desc' => !$self && !$contact['abook_my_perms'] ? t('This may be appropriate based on your <a href="settings">privacy settings</a>, though you may wish to review the "Advanced Permissions".') : '', '$submit' => t('Submit'), '$lbl_vis1' => t('Profile Visibility'), '$lbl_vis2' => sprintf(t('Please choose the profile you would like to display to %s when viewing your profile securely.'), $contact['xchan_name']), '$lbl_info1' => t('Contact Information / Notes'), '$infedit' => t('Edit contact notes'), '$close' => $contact['abook_closeness'], '$them' => t('Their Settings'), '$me' => t('My Settings'), '$perms' => $perms, '$clear' => t('Clear/Disable Automatic Permissions'), '$forum' => t('Forum Members'), '$soapbox' => t('Soapbox'), '$full' => t('Full Sharing (typical social network permissions)'), '$cautious' => t('Cautious Sharing '), '$follow' => t('Follow Only'), '$permlbl' => t('Individual Permissions'), '$permnote' => t('Some permissions may be inherited from your channel <a href="settings">privacy settings</a>, which have higher priority than individual settings. Changing those inherited settings on this page will have no effect.'), '$advanced' => t('Advanced Permissions'), '$quick' => t('Simple Permissions (select one and submit)'), '$common_link' => $a->get_baseurl(true) . '/common/loc/' . local_user() . '/' . $contact['id'], '$all_friends' => $all_friends, '$relation_text' => $relation_text, '$visit' => sprintf(t('Visit %s\'s profile - %s'), $contact['xchan_name'], $contact['xchan_url']), '$blockunblock' => t('Block/Unblock contact'), '$ignorecont' => t('Ignore contact'), '$lblcrepair' => t("Repair URL settings"), '$lblrecent' => t('View conversations'), '$lblsuggest' => $lblsuggest, '$delete' => t('Delete contact'), '$poll_interval' => contact_poll_interval($contact['priority'], !$poll_enabled), '$poll_enabled' => $poll_enabled, '$lastupdtext' => t('Last update:'), '$lost_contact' => $lost_contact, '$updpub' => t('Update public posts'), '$last_update' => relative_date($contact['abook_connected']), '$udnow' => t('Update now'), '$profile_select' => contact_profile_assign($contact['abook_profile']), '$multiprofs' => feature_enabled(local_user(), 'multi_profiles'), '$contact_id' => $contact['abook_id'], '$block_text' => $contact['blocked'] ? t('Unblock') : t('Block'), '$ignore_text' => $contact['readonly'] ? t('Unignore') : t('Ignore'), '$blocked' => $contact['blocked'] ? t('Currently blocked') : '', '$ignored' => $contact['readonly'] ? t('Currently ignored') : '', '$archived' => $contact['archive'] ? t('Currently archived') : '', '$pending' => $contact['archive'] ? t('Currently pending') : '', '$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')), '$photo' => $contact['photo'], '$name' => $contact['name'], '$dir_icon' => $dir_icon, '$alt_text' => $alt_text, '$sparkle' => $sparkle, '$url' => $url));
        $arr = array('contact' => $contact, 'output' => $o);
        call_hooks('contact_edit', $arr);
        return $arr['output'];
    }
}
예제 #11
0
function dfrn_notify_post(&$a)
{
    logger(__FUNCTION__, LOGGER_TRACE);
    $dfrn_id = x($_POST, 'dfrn_id') ? notags(trim($_POST['dfrn_id'])) : '';
    $dfrn_version = x($_POST, 'dfrn_version') ? (double) $_POST['dfrn_version'] : 2.0;
    $challenge = x($_POST, 'challenge') ? notags(trim($_POST['challenge'])) : '';
    $data = x($_POST, 'data') ? $_POST['data'] : '';
    $key = x($_POST, 'key') ? $_POST['key'] : '';
    $rino_remote = x($_POST, 'rino') ? intval($_POST['rino']) : 0;
    $dissolve = x($_POST, 'dissolve') ? intval($_POST['dissolve']) : 0;
    $perm = x($_POST, 'perm') ? notags(trim($_POST['perm'])) : 'r';
    $ssl_policy = x($_POST, 'ssl_policy') ? notags(trim($_POST['ssl_policy'])) : 'none';
    $page = x($_POST, 'page') ? intval($_POST['page']) : 0;
    $forum = $page == 1 ? 1 : 0;
    $prv = $page == 2 ? 1 : 0;
    $writable = -1;
    if ($dfrn_version >= 2.21) {
        $writable = $perm === 'rw' ? 1 : 0;
    }
    $direction = -1;
    if (strpos($dfrn_id, ':') == 1) {
        $direction = intval(substr($dfrn_id, 0, 1));
        $dfrn_id = substr($dfrn_id, 2);
    }
    $r = q("SELECT * FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1", dbesc($dfrn_id), dbesc($challenge));
    if (!count($r)) {
        logger('dfrn_notify: could not match challenge to dfrn_id ' . $dfrn_id . ' challenge=' . $challenge);
        xml_status(3);
    }
    $r = q("DELETE FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s'", dbesc($dfrn_id), dbesc($challenge));
    // find the local user who owns this relationship.
    $sql_extra = '';
    switch ($direction) {
        case -1:
            $sql_extra = sprintf(" AND ( `issued-id` = '%s' OR `dfrn-id` = '%s' ) ", dbesc($dfrn_id), dbesc($dfrn_id));
            break;
        case 0:
            $sql_extra = sprintf(" AND `issued-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id));
            break;
        case 1:
            $sql_extra = sprintf(" AND `dfrn-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id));
            break;
        default:
            xml_status(3);
            break;
            // NOTREACHED
    }
    // be careful - $importer will contain both the contact information for the contact
    // sending us the post, and also the user information for the person receiving it.
    // since they are mixed together, it is easy to get them confused.
    $r = q("SELECT\t`contact`.*, `contact`.`uid` AS `importer_uid`,\n\t\t\t\t\t`contact`.`pubkey` AS `cpubkey`,\n\t\t\t\t\t`contact`.`prvkey` AS `cprvkey`,\n\t\t\t\t\t`contact`.`thumb` AS `thumb`,\n\t\t\t\t\t`contact`.`url` as `url`,\n\t\t\t\t\t`contact`.`name` as `senderName`,\n\t\t\t\t\t`user`.*\n\t\t\tFROM `contact`\n\t\t\tLEFT JOIN `user` ON `contact`.`uid` = `user`.`uid`\n\t\t\tWHERE `contact`.`blocked` = 0 AND `contact`.`pending` = 0\n\t\t\t\tAND `user`.`nickname` = '%s' AND `user`.`account_expired` = 0 AND `user`.`account_removed` = 0 {$sql_extra} LIMIT 1", dbesc($a->argv[1]));
    if (!count($r)) {
        logger('dfrn_notify: contact not found for dfrn_id ' . $dfrn_id);
        xml_status(3);
        //NOTREACHED
    }
    // $importer in this case contains the contact record for the remote contact joined with the user record of our user.
    $importer = $r[0];
    logger("Remote rino version: " . $rino_remote . " for " . $importer["url"], LOGGER_DEBUG);
    if ($writable != -1 && $writable != $importer['writable'] || $importer['forum'] != $forum || $importer['prv'] != $prv) {
        q("UPDATE `contact` SET `writable` = %d, forum = %d, prv = %d WHERE `id` = %d", intval($writable == -1 ? $importer['writable'] : $writable), intval($forum), intval($prv), intval($importer['id']));
        if ($writable != -1) {
            $importer['writable'] = $writable;
        }
        $importer['forum'] = $page;
    }
    // if contact's ssl policy changed, update our links
    fix_contact_ssl_policy($importer, $ssl_policy);
    logger('dfrn_notify: received notify from ' . $importer['name'] . ' for ' . $importer['username']);
    logger('dfrn_notify: data: ' . $data, LOGGER_DATA);
    if ($dissolve == 1) {
        /**
         * Relationship is dissolved permanently
         */
        require_once 'include/Contact.php';
        contact_remove($importer['id']);
        logger('relationship dissolved : ' . $importer['name'] . ' dissolved ' . $importer['username']);
        xml_status(0);
    }
    // If we are setup as a soapbox we aren't accepting input from this person
    // This behaviour is deactivated since it really doesn't make sense to even disallow comments
    // The check if someone is a friend or simply a follower is done in a later place so it needn't to be done here
    //if($importer['page-flags'] == PAGE_SOAPBOX)
    //	xml_status(0);
    $rino = get_config('system', 'rino_encrypt');
    $rino = intval($rino);
    // use RINO1 if mcrypt isn't installed and RINO2 was selected
    if ($rino == 2 and !function_exists('mcrypt_create_iv')) {
        $rino = 1;
    }
    logger("Local rino version: " . $rino, LOGGER_DEBUG);
    if (strlen($key)) {
        // if local rino is lower than remote rino, abort: should not happen!
        // but only for $remote_rino > 1, because old code did't send rino version
        if ($rino_remote_version > 1 && $rino < $rino_remote) {
            logger("rino version '{$rino_remote}' is lower than supported '{$rino}'");
            xml_status(0, "rino version '{$rino_remote}' is lower than supported '{$rino}'");
        }
        $rawkey = hex2bin(trim($key));
        logger('rino: md5 raw key: ' . md5($rawkey));
        $final_key = '';
        if ($dfrn_version >= 2.1) {
            if ($importer['duplex'] && strlen($importer['cprvkey']) || !strlen($importer['cpubkey'])) {
                openssl_private_decrypt($rawkey, $final_key, $importer['cprvkey']);
            } else {
                openssl_public_decrypt($rawkey, $final_key, $importer['cpubkey']);
            }
        } else {
            if ($importer['duplex'] && strlen($importer['cpubkey']) || !strlen($importer['cprvkey'])) {
                openssl_public_decrypt($rawkey, $final_key, $importer['cpubkey']);
            } else {
                openssl_private_decrypt($rawkey, $final_key, $importer['cprvkey']);
            }
        }
        #logger('rino: received key : ' . $final_key);
        switch ($rino_remote) {
            case 0:
            case 1:
                // we got a key. old code send only the key, without RINO version.
                // we assume RINO 1 if key and no RINO version
                $data = aes_decrypt(hex2bin($data), $final_key);
                break;
            case 2:
                try {
                    $data = Crypto::decrypt(hex2bin($data), $final_key);
                } catch (InvalidCiphertext $ex) {
                    // VERY IMPORTANT
                    // Either:
                    //   1. The ciphertext was modified by the attacker,
                    //   2. The key is wrong, or
                    //   3. $ciphertext is not a valid ciphertext or was corrupted.
                    // Assume the worst.
                    logger('The ciphertext has been tampered with!');
                    xml_status(0, 'The ciphertext has been tampered with!');
                } catch (Ex\CryptoTestFailed $ex) {
                    logger('Cannot safely perform dencryption');
                    xml_status(0, 'CryptoTestFailed');
                } catch (Ex\CannotPerformOperation $ex) {
                    logger('Cannot safely perform decryption');
                    xml_status(0, 'Cannot safely perform decryption');
                }
                break;
            default:
                logger("rino: invalid sent verision '{$rino_remote}'");
                xml_status(0);
        }
        logger('rino: decrypted data: ' . $data, LOGGER_DATA);
    }
    $ret = local_delivery($importer, $data);
    xml_status($ret);
    // NOTREACHED
}
예제 #12
0
/**
 * @param App $a
 */
function facebook_post(&$a)
{
    $uid = local_user();
    if ($uid) {
        $fb_limited = get_config('facebook', 'restrict');
        $value = x($_POST, 'post_by_default') ? intval($_POST['post_by_default']) : 0;
        set_pconfig($uid, 'facebook', 'post_by_default', $value);
        $no_linking = get_pconfig($uid, 'facebook', 'no_linking');
        $no_wall = x($_POST, 'facebook_no_wall') ? intval($_POST['facebook_no_wall']) : 0;
        set_pconfig($uid, 'facebook', 'no_wall', $no_wall);
        $private_wall = x($_POST, 'facebook_private_wall') ? intval($_POST['facebook_private_wall']) : 0;
        set_pconfig($uid, 'facebook', 'private_wall', $private_wall);
        set_pconfig($uid, 'facebook', 'blocked_apps', escape_tags(trim($_POST['blocked_apps'])));
        $linkvalue = x($_POST, 'facebook_linking') ? intval($_POST['facebook_linking']) : 0;
        if ($fb_limited) {
            if ($linkvalue == 0) {
                set_pconfig($uid, 'facebook', 'no_linking', 1);
            }
        } else {
            set_pconfig($uid, 'facebook', 'no_linking', $linkvalue ? 0 : 1);
        }
        // FB linkage was allowed but has just been turned off - remove all FB contacts and posts
        if (!intval($no_linking) && !intval($linkvalue)) {
            $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `network` = '%s' ", intval($uid), dbesc(NETWORK_FACEBOOK));
            if (count($r)) {
                require_once 'include/Contact.php';
                foreach ($r as $rr) {
                    contact_remove($rr['id']);
                }
            }
        } elseif (intval($no_linking) && intval($linkvalue)) {
            // FB linkage is now allowed - import stuff.
            fb_get_self($uid);
            fb_get_friends($uid, true);
            fb_consume_all($uid);
        }
        info(t('Settings updated.') . EOL);
    }
    return;
}
예제 #13
0
파일: zot.php 프로젝트: redmatrix/red
function process_channel_sync_delivery($sender, $arr, $deliveries)
{
    /** @FIXME this will sync red structures (channel, pconfig and abook). Eventually we need to make this application agnostic. */
    $result = array();
    foreach ($deliveries as $d) {
        $r = q("select * from channel where channel_hash = '%s' limit 1", dbesc($d['hash']));
        if (!$r) {
            $result[] = array($d['hash'], 'not found');
            continue;
        }
        $channel = $r[0];
        $max_friends = service_class_fetch($channel['channel_id'], 'total_channels');
        $max_feeds = account_service_class_fetch($channel['channel_account_id'], 'total_feeds');
        if ($channel['channel_hash'] != $sender['hash']) {
            logger('process_channel_sync_delivery: possible forgery. Sender ' . $sender['hash'] . ' is not ' . $channel['channel_hash']);
            $result[] = array($d['hash'], 'channel mismatch', $channel['channel_name'], '');
            continue;
        }
        if (array_key_exists('config', $arr) && is_array($arr['config']) && count($arr['config'])) {
            foreach ($arr['config'] as $cat => $k) {
                foreach ($arr['config'][$cat] as $k => $v) {
                    set_pconfig($channel['channel_id'], $cat, $k, $v);
                }
            }
        }
        if (array_key_exists('channel', $arr) && is_array($arr['channel']) && count($arr['channel'])) {
            $disallowed = array('channel_id', 'channel_account_id', 'channel_primary', 'channel_prvkey', 'channel_address', 'channel_notifyflags');
            $clean = array();
            foreach ($arr['channel'] as $k => $v) {
                if (in_array($k, $disallowed)) {
                    continue;
                }
                $clean[$k] = $v;
            }
            if (count($clean)) {
                foreach ($clean as $k => $v) {
                    $r = dbq("UPDATE channel set " . dbesc($k) . " = '" . dbesc($v) . "' where channel_id = " . intval($channel['channel_id']));
                }
            }
        }
        if (array_key_exists('abook', $arr) && is_array($arr['abook']) && count($arr['abook'])) {
            $total_friends = 0;
            $total_feeds = 0;
            $r = q("select abook_id, abook_flags from abook where abook_channel = %d", intval($channel['channel_id']));
            if ($r) {
                // don't count yourself
                $total_friends = count($r) > 0 ? count($r) - 1 : 0;
                foreach ($r as $rr) {
                    if ($rr['abook_flags'] & ABOOK_FLAG_FEED) {
                        $total_feeds++;
                    }
                }
            }
            $disallowed = array('abook_id', 'abook_account', 'abook_channel');
            foreach ($arr['abook'] as $abook) {
                $clean = array();
                if ($abook['abook_xchan'] && $abook['entry_deleted']) {
                    logger('process_channel_sync_delivery: removing abook entry for ' . $abook['abook_xchan']);
                    require_once 'include/Contact.php';
                    $r = q("select abook_id, abook_flags from abook where abook_xchan = '%s' and abook_channel = %d and not ( abook_flags & %d )>0 limit 1", dbesc($abook['abook_xchan']), intval($channel['channel_id']), intval(ABOOK_FLAG_SELF));
                    if ($r) {
                        contact_remove($channel['channel_id'], $r[0]['abook_id']);
                        if ($total_friends) {
                            $total_friends--;
                        }
                        if ($r[0]['abook_flags'] & ABOOK_FLAG_FEED) {
                            $total_feeds--;
                        }
                    }
                    continue;
                }
                // Perform discovery if the referenced xchan hasn't ever been seen on this hub.
                // This relies on the undocumented behaviour that red sites send xchan info with the abook
                if ($abook['abook_xchan'] && $abook['xchan_address']) {
                    $h = zot_get_hublocs($abook['abook_xchan']);
                    if (!$h) {
                        $f = zot_finger($abook['xchan_address'], $channel);
                        if (!$f['success']) {
                            logger('process_channel_sync_delivery: abook not probe-able' . $abook['xchan_address']);
                            continue;
                        }
                        $j = json_decode($f['body'], true);
                        if (!($j['success'] && $j['guid'])) {
                            logger('process_channel_sync_delivery: probe failed.');
                            continue;
                        }
                        $x = import_xchan($j);
                        if (!$x['success']) {
                            logger('process_channel_sync_delivery: import failed.');
                            continue;
                        }
                    }
                }
                foreach ($abook as $k => $v) {
                    if (in_array($k, $disallowed) || strpos($k, 'abook') !== 0) {
                        continue;
                    }
                    $clean[$k] = $v;
                }
                if (!array_key_exists('abook_xchan', $clean)) {
                    continue;
                }
                $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", dbesc($clean['abook_xchan']), intval($channel['channel_id']));
                // make sure we have an abook entry for this xchan on this system
                if (!$r) {
                    if ($max_friends !== false && $total_friends > $max_friends) {
                        logger('process_channel_sync_delivery: total_channels service class limit exceeded');
                        continue;
                    }
                    if ($max_feeds !== false && $clean['abook_flags'] & ABOOK_FLAG_FEED && $total_feeds > $max_feeds) {
                        logger('process_channel_sync_delivery: total_feeds service class limit exceeded');
                        continue;
                    }
                    q("insert into abook ( abook_xchan, abook_channel ) values ('%s', %d ) ", dbesc($clean['abook_xchan']), intval($channel['channel_id']));
                    $total_friends++;
                    if ($clean['abook_flags'] & ABOOK_FLAG_FEED) {
                        $total_feeds++;
                    }
                }
                if (count($clean)) {
                    foreach ($clean as $k => $v) {
                        if ($k == 'abook_dob') {
                            $v = dbescdate($v);
                        }
                        $r = dbq("UPDATE abook set " . dbesc($k) . " = '" . dbesc($v) . "' where abook_xchan = '" . dbesc($clean['abook_xchan']) . "' and abook_channel = " . intval($channel['channel_id']));
                    }
                }
            }
        }
        // sync collections (privacy groups) oh joy...
        if (array_key_exists('collections', $arr) && is_array($arr['collections']) && count($arr['collections'])) {
            $x = q("select * from groups where uid = %d", intval($channel['channel_id']));
            foreach ($arr['collections'] as $cl) {
                $found = false;
                if ($x) {
                    foreach ($x as $y) {
                        if ($cl['collection'] == $y['hash']) {
                            $found = true;
                            break;
                        }
                    }
                    if ($found) {
                        if ($y['name'] != $cl['name'] || $y['visible'] != $cl['visible'] || $y['deleted'] != $cl['deleted']) {
                            q("update groups set name = '%s', visible = %d, deleted = %d where hash = '%s' and uid = %d", dbesc($cl['name']), intval($cl['visible']), intval($cl['deleted']), dbesc($cl['hash']), intval($channel['channel_id']));
                        }
                        if (intval($cl['deleted']) && !intval($y['deleted'])) {
                            q("delete from group_member where gid = %d", intval($y['id']));
                        }
                    }
                }
                if (!$found) {
                    $r = q("INSERT INTO `groups` ( hash, uid, visible, deleted, name )\n\t\t\t\t\t\tVALUES( '%s', %d, %d, %d, '%s' ) ", dbesc($cl['collection']), intval($channel['channel_id']), intval($cl['visible']), intval($cl['deleted']), dbesc($cl['name']));
                }
                // now look for any collections locally which weren't in the list we just received.
                // They need to be removed by marking deleted and removing the members.
                // This shouldn't happen except for clones created before this function was written.
                if ($x) {
                    $found_local = false;
                    foreach ($x as $y) {
                        foreach ($arr['collections'] as $cl) {
                            if ($cl['collection'] == $y['hash']) {
                                $found_local = true;
                                break;
                            }
                        }
                        if (!$found_local) {
                            q("delete from group_member where gid = %d", intval($y['id']));
                            q("update groups set deleted = 1 where id = %d and uid = %d", intval($y['id']), intval($channel['channel_id']));
                        }
                    }
                }
            }
            // reload the group list with any updates
            $x = q("select * from groups where uid = %d", intval($channel['channel_id']));
            // now sync the members
            if (array_key_exists('collection_members', $arr) && is_array($arr['collection_members']) && count($arr['collection_members'])) {
                // first sort into groups keyed by the group hash
                $members = array();
                foreach ($arr['collection_members'] as $cm) {
                    if (!array_key_exists($cm['collection'], $members)) {
                        $members[$cm['collection']] = array();
                    }
                    $members[$cm['collection']][] = $cm['member'];
                }
                // our group list is already synchronised
                if ($x) {
                    foreach ($x as $y) {
                        // for each group, loop on members list we just received
                        foreach ($members[$y['hash']] as $member) {
                            $found = false;
                            $z = q("select xchan from group_member where gid = %d and uid = %d and xchan = '%s' limit 1", intval($y['id']), intval($channel['channel_id']), dbesc($member));
                            if ($z) {
                                $found = true;
                            }
                            // if somebody is in the group that wasn't before - add them
                            if (!$found) {
                                q("INSERT INTO `group_member` (`uid`, `gid`, `xchan`)\n\t\t\t\t\t\t\t\t\tVALUES( %d, %d, '%s' ) ", intval($channel['channel_id']), intval($y['id']), dbesc($member));
                            }
                        }
                        // now retrieve a list of members we have on this site
                        $m = q("select xchan from group_member where gid = %d and uid = %d", intval($y['id']), intval($channel['channel_id']));
                        if ($m) {
                            foreach ($m as $mm) {
                                // if the local existing member isn't in the list we just received - remove them
                                if (!in_array($mm['xchan'], $members[$y['hash']])) {
                                    q("delete from group_member where xchan = '%s' and gid = %d and uid = %d", dbesc($mm['xchan']), intval($y['id']), intval($channel['channel_id']));
                                }
                            }
                        }
                    }
                }
            }
        }
        if (array_key_exists('profile', $arr) && is_array($arr['profile']) && count($arr['profile'])) {
            $disallowed = array('id', 'aid', 'uid');
            foreach ($arr['profile'] as $profile) {
                $x = q("select * from profile where profile_guid = '%s' and uid = %d limit 1", dbesc($profile['profile_guid']), intval($channel['channel_id']));
                if (!$x) {
                    q("insert into profile ( profile_guid, aid, uid ) values ('%s', %d, %d)", dbesc($profile['profile_guid']), intval($channel['channel_account_id']), intval($channel['channel_id']));
                    $x = q("select * from profile where profile_guid = '%s' and uid = %d limit 1", dbesc($profile['profile_guid']), intval($channel['channel_id']));
                    if (!$x) {
                        continue;
                    }
                }
                $clean = array();
                foreach ($profile as $k => $v) {
                    if (in_array($k, $disallowed)) {
                        continue;
                    }
                    $clean[$k] = $v;
                    /**
                     * @TODO check if these are allowed, otherwise we'll error
                     * We also need to import local photos if a custom photo is selected
                     */
                }
                if (count($clean)) {
                    foreach ($clean as $k => $v) {
                        $r = dbq("UPDATE profile set " . dbesc($k) . " = '" . dbesc($v) . "' where profile_guid = '" . dbesc($profile['profile_guid']) . "' and uid = " . intval($channel['channel_id']));
                    }
                }
            }
        }
        $result[] = array($d['hash'], 'channel sync updated', $channel['channel_name'], '');
    }
    return $result;
}
예제 #14
0
function lose_sharer($importer, $contact, $datarray, $item)
{
    if ($contact['rel'] == CONTACT_IS_FRIEND || $contact['rel'] == CONTACT_IS_FOLLOWER) {
        q("UPDATE `contact` SET `rel` = %d WHERE `id` = %d", intval(CONTACT_IS_FOLLOWER), intval($contact['id']));
    } else {
        contact_remove($contact['id']);
    }
}
예제 #15
0
파일: post.php 프로젝트: Mauru/red
/**
 * @function post_post(&$a)
 *     zot communications and messaging
 *
 *     Sender HTTP posts to this endpoint ($site/post typically) with 'data' parameter set to json zot message packet.
 *     This packet is optionally encrypted, which we will discover if the json has an 'iv' element.
 *     $contents => array( 'alg' => 'aes256cbc', 'iv' => initialisation vector, 'key' => decryption key, 'data' => encrypted data);
 *     $contents->iv and $contents->key are random strings encrypted with this site's RSA public key and then base64url encoded.
 *     Currently only 'aes256cbc' is used, but this is extensible should that algorithm prove inadequate.
 *
 *     Once decrypted, one will find the normal json_encoded zot message packet. 
 * 
 * Defined packet types are: notify, purge, refresh, force_refresh, auth_check, ping, and pickup 
 *
 * Standard packet: (used by notify, purge, refresh, force_refresh, and auth_check)
 *
 * {
 *  "type": "notify",
 *  "sender":{
 *       "guid":"kgVFf_1...",
 *       "guid_sig":"PT9-TApzp...",
 *       "url":"http:\/\/podunk.edu",
 *       "url_sig":"T8Bp7j5...",
 *    },
 *  "recipients": { optional recipient array },
 *  "callback":"\/post",
 *  "version":1,
 *  "secret":"1eaa...",
 *  "secret_sig": "df89025470fac8..."
 * }
 * 
 * Signature fields are all signed with the sender channel private key and base64url encoded.
 * Recipients are arrays of guid and guid_sig, which were previously signed with the recipients private 
 * key and base64url encoded and later obtained via channel discovery. Absence of recipients indicates
 * a public message or visible to all potential listeners on this site.
 *
 * "pickup" packet:
 * The pickup packet is sent in response to a notify packet from another site
 * 
 * {
 *  "type":"pickup",
 *  "url":"http:\/\/example.com",
 *  "callback":"http:\/\/example.com\/post",
 *  "callback_sig":"teE1_fLI...",
 *  "secret":"1eaa...",
 *  "secret_sig":"O7nB4_..."
 * }
 *
 * In the pickup packet, the sig fields correspond to the respective data element signed with this site's system 
 * private key and then base64url encoded.
 * The "secret" is the same as the original secret from the notify packet. 
 *
 * If verification is successful, a json structure is returned
 * containing a success indicator and an array of type 'pickup'.
 * Each pickup element contains the original notify request and a message field whose contents are 
 * dependent on the message type
 *
 * This JSON array is AES encapsulated using the site public key of the site that sent the initial zot pickup packet.
 * Using the above example, this would be example.com.
 * 
 * 
 * {
 * "success":1,
 * "pickup":{
 *   "notify":{
 *     "type":"notify",
 *     "sender":{
 *       "guid":"kgVFf_...",
 *       "guid_sig":"PT9-TApz...",
 *       "url":"http:\/\/z.podunk.edu",
 *       "url_sig":"T8Bp7j5D..."
 *     },
 *     "callback":"\/post",
 *     "version":1,
 *     "secret":"1eaa661..."
 *   },
 *   "message":{
 *     "type":"activity",
 *     "message_id":"*****@*****.**",
 *     "message_top":"*****@*****.**",
 *     "message_parent":"*****@*****.**",
 *     "created":"2012-11-20 04:04:16",
 *     "edited":"2012-11-20 04:04:16",
 *     "title":"",
 *     "body":"Hi Nickordo",
 *     "app":"",
 *     "verb":"post",
 *     "object_type":"",
 *     "target_type":"",
 *     "permalink":"",
 *     "location":"",
 *     "longlat":"",
 *     "owner":{
 *       "name":"Indigo",
 *       "address":"*****@*****.**",
 *       "url":"http:\/\/podunk.edu",
 *       "photo":{
 *         "mimetype":"image\/jpeg",
 *         "src":"http:\/\/podunk.edu\/photo\/profile\/m\/5"
 *       },
 *       "guid":"kgVFf_...",
 *       "guid_sig":"PT9-TAp...",
 *     },
 *     "author":{
 *       "name":"Indigo",
 *       "address":"*****@*****.**",
 *       "url":"http:\/\/podunk.edu",
 *       "photo":{
 *         "mimetype":"image\/jpeg",
 *         "src":"http:\/\/podunk.edu\/photo\/profile\/m\/5"
 *       },
 *       "guid":"kgVFf_...",
 *       "guid_sig":"PT9-TAp..."
 *     }
 *   }
 * }
 *} 
 *
 * Currently defined message types are 'activity', 'mail', 'profile' and 'channel_sync', which each have 
 * different content schemas.
 *
 * Ping packet:
 * A ping packet does not require any parameters except the type. It may or may not be encrypted.
 * 
 * {
 *  "type": "ping"
 * }
 * 
 * On receipt of a ping packet a ping response will be returned:
 *
 * {
 *   "success" : 1,
 *   "site" {
 *       "url":"http:\/\/podunk.edu",
 *       "url_sig":"T8Bp7j5...",
 *       "sitekey": "-----BEGIN PUBLIC KEY-----
 *                  MIICIjANBgkqhkiG9w0BAQE..."
 *    }
 * }
 * 
 * The ping packet can be used to verify that a site has not been re-installed, and to 
 * initiate corrective action if it has. The url_sig is signed with the site private key
 * and base64url encoded - and this should verify with the enclosed sitekey. Failure to
 * verify indicates the site is corrupt or otherwise unable to communicate using zot.
 * This return packet is not otherwise verified, so should be compared with other
 * results obtained from this site which were verified prior to taking action. For instance
 * if you have one verified result with this signature and key, and other records for this 
 * url which have different signatures and keys, it indicates that the site was re-installed
 * and corrective action may commence (remove or mark invalid any entries with different
 * signatures).
 * If you have no records which match this url_sig and key - no corrective action should
 * be taken as this packet may have been returned by an imposter.  
 *
 */
function post_post(&$a)
{
    $encrypted_packet = false;
    $ret = array('success' => false);
    $data = json_decode($_REQUEST['data'], true);
    /**
     * Many message packets will arrive encrypted. The existence of an 'iv' element 
     * tells us we need to unencapsulate the AES-256-CBC content using the site private key
     */
    if (array_key_exists('iv', $data)) {
        $encrypted_packet = true;
        $data = crypto_unencapsulate($data, get_config('system', 'prvkey'));
        logger('mod_zot: decrypt1: ' . $data, LOGGER_DATA);
        $data = json_decode($data, true);
    }
    if (!$data) {
        // possible Bleichenbacher's attack, just treat it as a
        // message we have no handler for. It should fail a bit
        // further along with "no hub". Our public key is public
        // knowledge. There's no reason why anybody should get the
        // encryption wrong unless they're fishing or hacking. If
        // they're developing and made a goof, this can be discovered
        // in the logs of the destination site. If they're fishing or
        // hacking, the bottom line is we can't verify their hub.
        // That's all we're going to tell them.
        $data = array('type' => 'bogus');
    }
    $msgtype = array_key_exists('type', $data) ? $data['type'] : '';
    if ($msgtype === 'ping') {
        // Useful to get a health check on a remote site.
        // This will let us know if any important communication details
        // that we may have stored are no longer valid, regardless of xchan details.
        logger('POST: got ping send pong now back: ' . z_root(), LOGGER_DEBUG);
        $ret['success'] = true;
        $ret['site'] = array();
        $ret['site']['url'] = z_root();
        $ret['site']['url_sig'] = base64url_encode(rsa_sign(z_root(), get_config('system', 'prvkey')));
        $ret['site']['sitekey'] = get_config('system', 'pubkey');
        json_return_and_die($ret);
    }
    if ($msgtype === 'pickup') {
        /**
         * The 'pickup' message arrives with a tracking ID which is associated with a particular outq_hash
         * First verify that that the returned signatures verify, then check that we have an outbound queue item
         * with the correct hash.
         * If everything verifies, find any/all outbound messages in the queue for this hubloc and send them back
         *
         */
        if (!$data['secret'] || !$data['secret_sig']) {
            $ret['message'] = 'no verification signature';
            logger('mod_zot: pickup: ' . $ret['message'], LOGGER_DEBUG);
            json_return_and_die($ret);
        }
        $r = q("select distinct hubloc_sitekey from hubloc where hubloc_url = '%s' and hubloc_callback = '%s' and hubloc_sitekey != '' group by hubloc_sitekey ", dbesc($data['url']), dbesc($data['callback']));
        if (!$r) {
            $ret['message'] = 'site not found';
            logger('mod_zot: pickup: ' . $ret['message']);
            json_return_and_die($ret);
        }
        foreach ($r as $hubsite) {
            // verify the url_sig
            // If the server was re-installed at some point, there could be multiple hubs with the same url and callback.
            // Only one will have a valid key.
            $forgery = true;
            $secret_fail = true;
            $sitekey = $hubsite['hubloc_sitekey'];
            logger('mod_zot: Checking sitekey: ' . $sitekey, LOGGER_DATA);
            if (rsa_verify($data['callback'], base64url_decode($data['callback_sig']), $sitekey)) {
                $forgery = false;
            }
            if (rsa_verify($data['secret'], base64url_decode($data['secret_sig']), $sitekey)) {
                $secret_fail = false;
            }
            if (!$forgery && !$secret_fail) {
                break;
            }
        }
        if ($forgery) {
            $ret['message'] = 'possible site forgery';
            logger('mod_zot: pickup: ' . $ret['message']);
            json_return_and_die($ret);
        }
        if ($secret_fail) {
            $ret['message'] = 'secret validation failed';
            logger('mod_zot: pickup: ' . $ret['message']);
            json_return_and_die($ret);
        }
        /**
         * If we made it to here, the signatures verify, but we still don't know if the tracking ID is valid.
         * It wouldn't be an error if the tracking ID isn't found, because we may have sent this particular
         * queue item with another pickup (after the tracking ID for the other pickup  was verified). 
         */
        $r = q("select outq_posturl from outq where outq_hash = '%s' and outq_posturl = '%s' limit 1", dbesc($data['secret']), dbesc($data['callback']));
        if (!$r) {
            $ret['message'] = 'nothing to pick up';
            logger('mod_zot: pickup: ' . $ret['message']);
            json_return_and_die($ret);
        }
        /**
         * Everything is good if we made it here, so find all messages that are going to this location
         * and send them all.
         */
        $r = q("select * from outq where outq_posturl = '%s'", dbesc($data['callback']));
        if ($r) {
            logger('mod_zot: succesful pickup message received from ' . $data['callback'] . ' ' . count($r) . ' message(s) picked up', LOGGER_DEBUG);
            $ret['success'] = true;
            $ret['pickup'] = array();
            foreach ($r as $rr) {
                $ret['pickup'][] = array('notify' => json_decode($rr['outq_notify'], true), 'message' => json_decode($rr['outq_msg'], true));
                $x = q("delete from outq where outq_hash = '%s' limit 1", dbesc($rr['outq_hash']));
            }
        }
        $encrypted = crypto_encapsulate(json_encode($ret), $sitekey);
        json_return_and_die($encrypted);
        /** pickup: end */
    }
    /**
     * All other message types require us to verify the sender. This is a generic check, so we 
     * will do it once here and bail if anything goes wrong.
     */
    if (array_key_exists('sender', $data)) {
        $sender = $data['sender'];
    }
    /** Check if the sender is already verified here */
    $hub = zot_gethub($sender);
    if (!$hub) {
        /** Have never seen this guid or this guid coming from this location. Check it and register it. */
        // (!!) this will validate the sender
        $result = zot_register_hub($sender);
        if (!$result['success'] || !($hub = zot_gethub($sender))) {
            $ret['message'] = 'Hub not available.';
            logger('mod_zot: no hub');
            json_return_and_die($ret);
        }
    }
    // Update our DB to show when we last communicated successfully with this hub
    // This will allow us to prune dead hubs from using up resources
    $r = q("update hubloc set hubloc_connected = '%s' where hubloc_id = %d limit 1", dbesc(datetime_convert()), intval($hub['hubloc_id']));
    // a dead hub came back to life - reset any tombstones we might have
    if ($hub['hubloc_status'] & HUBLOC_OFFLINE) {
        q("update hubloc set hubloc_status = (hubloc_status ^ %d) where hubloc_id = %d limit 1", intval(HUBLOC_OFFLINE), intval($hub['hubloc_id']));
        if ($r[0]['hubloc_flags'] & HUBLOC_FLAGS_ORPHANCHECK) {
            q("update hubloc set hubloc_flags = (hubloc_flags ^ %d) where hubloc_id = %d limit 1", intval(HUBLOC_FLAGS_ORPHANCHECK), intval($hub['hubloc_id']));
        }
        q("update xchan set xchan_flags = (xchan_flags ^ %d) where (xchan_flags & %d) and xchan_hash = '%s' limit 1", intval(XCHAN_FLAGS_ORPHAN), intval(XCHAN_FLAGS_ORPHAN), dbesc($hub['hubloc_hash']));
    }
    /** 
     * This hub has now been proven to be valid.
     * Any hub with the same URL and a different sitekey cannot be valid.
     * Get rid of them (mark them deleted). There's a good chance they were re-installs.
     *
     */
    q("update hubloc set hubloc_flags = ( hubloc_flags | %d ) where hubloc_url = '%s' and hubloc_sitekey != '%s' ", intval(HUBLOC_FLAGS_DELETED), dbesc($hub['hubloc_url']), dbesc($hub['hubloc_sitekey']));
    // TODO: check which hub is primary and take action if mismatched
    if (array_key_exists('recipients', $data)) {
        $recipients = $data['recipients'];
    }
    if ($msgtype === 'auth_check') {
        /**
         * Requestor visits /magic/?dest=somewhere on their own site with a browser
         * magic redirects them to $destsite/post [with auth args....]
         * $destsite sends an auth_check packet to originator site
         * The auth_check packet is handled here by the originator's site 
         * - the browser session is still waiting
         * inside $destsite/post for everything to verify
         * If everything checks out we'll return a token to $destsite
         * and then $destsite will verify the token, authenticate the browser
         * session and then redirect to the original destination.
         * If authentication fails, the redirection to the original destination
         * will still take place but without authentication.
         */
        logger('mod_zot: auth_check', LOGGER_DEBUG);
        if (!$encrypted_packet) {
            logger('mod_zot: auth_check packet was not encrypted.');
            $ret['message'] .= 'no packet encryption' . EOL;
            json_return_and_die($ret);
        }
        $arr = $data['sender'];
        $sender_hash = make_xchan_hash($arr['guid'], $arr['guid_sig']);
        // garbage collect any old unused notifications
        q("delete from verify where type = 'auth' and created < UTC_TIMESTAMP() - INTERVAL 10 MINUTE");
        $y = q("select xchan_pubkey from xchan where xchan_hash = '%s' limit 1", dbesc($sender_hash));
        // We created a unique hash in mod/magic.php when we invoked remote auth, and stored it in
        // the verify table. It is now coming back to us as 'secret' and is signed by a channel at the other end.
        // First verify their signature. We will have obtained a zot-info packet from them as part of the sender
        // verification.
        if (!$y || !rsa_verify($data['secret'], base64url_decode($data['secret_sig']), $y[0]['xchan_pubkey'])) {
            logger('mod_zot: auth_check: sender not found or secret_sig invalid.');
            $ret['message'] .= 'sender not found or sig invalid ' . print_r($y, true) . EOL;
            json_return_and_die($ret);
        }
        // There should be exactly one recipient, the original auth requestor
        $ret['message'] .= 'recipients ' . print_r($recipients, true) . EOL;
        if ($data['recipients']) {
            $arr = $data['recipients'][0];
            $recip_hash = make_xchan_hash($arr['guid'], $arr['guid_sig']);
            $c = q("select channel_id, channel_account_id, channel_prvkey from channel where channel_hash = '%s' limit 1", dbesc($recip_hash));
            if (!$c) {
                logger('mod_zot: auth_check: recipient channel not found.');
                $ret['message'] .= 'recipient not found.' . EOL;
                json_return_and_die($ret);
            }
            $confirm = base64url_encode(rsa_sign($data['secret'] . $recip_hash, $c[0]['channel_prvkey']));
            // This additionally checks for forged sites since we already stored the expected result in meta
            // and we've already verified that this is them via zot_gethub() and that their key signed our token
            $z = q("select id from verify where channel = %d and type = 'auth' and token = '%s' and meta = '%s' limit 1", intval($c[0]['channel_id']), dbesc($data['secret']), dbesc($data['sender']['url']));
            if (!$z) {
                logger('mod_zot: auth_check: verification key not found.');
                $ret['message'] .= 'verification key not found' . EOL;
                json_return_and_die($ret);
            }
            $r = q("delete from verify where id = %d limit 1", intval($z[0]['id']));
            $u = q("select account_service_class from account where account_id = %d limit 1", intval($c[0]['channel_account_id']));
            logger('mod_zot: auth_check: success', LOGGER_DEBUG);
            $ret['success'] = true;
            $ret['confirm'] = $confirm;
            if ($u && $u[0]['account_service_class']) {
                $ret['service_class'] = $u[0]['account_service_class'];
            }
            // Set "do not track" flag if this site or this channel's profile is restricted
            if (intval(get_config('system', 'block_public'))) {
                $ret['DNT'] = true;
            }
            if (!perm_is_allowed($c[0]['channel_id'], '', 'view_profile')) {
                $ret['DNT'] = true;
            }
            if (get_pconfig($c[0]['channel_id'], 'system', 'do_not_track')) {
                $ret['DNT'] = true;
            }
            json_return_and_die($ret);
        }
        json_return_and_die($ret);
    }
    if ($msgtype === 'purge') {
        if ($recipients) {
            // basically this means "unfriend"
            foreach ($recipients as $recip) {
                $r = q("select channel.*,xchan.* from channel \n\t\t\t\t\tleft join xchan on channel_hash = xchan_hash\n\t\t\t\t\twhere channel_guid = '%s' and channel_guid_sig = '%s' limit 1", dbesc($recip['guid']), dbesc($recip['guid_sig']));
                if ($r) {
                    $r = q("select abook_id from abook where uid = %d and abook_xchan = '%s' limit 1", intval($r[0]['channel_id']), dbesc(make_xchan_hash($sender['guid'], $sender['guid_sig'])));
                    if ($r) {
                        contact_remove($r[0]['channel_id'], $r[0]['abook_id']);
                    }
                }
            }
        } else {
            // Unfriend everybody - basically this means the channel has committed suicide
            $arr = $data['sender'];
            $sender_hash = make_xchan_hash($arr['guid'], $arr['guid_sig']);
            require_once 'include/Contact.php';
            remove_all_xchan_resources($sender_hash);
            $ret['success'] = true;
            json_return_and_die($ret);
        }
    }
    if ($msgtype === 'refresh' || $msgtype === 'force_refresh') {
        // remote channel info (such as permissions or photo or something)
        // has been updated. Grab a fresh copy and sync it.
        // The difference between refresh and force_refresh is that
        // force_refresh unconditionally creates a directory update record,
        // even if no changes were detected upon processing.
        if ($recipients) {
            // This would be a permissions update, typically for one connection
            foreach ($recipients as $recip) {
                $r = q("select channel.*,xchan.* from channel \n\t\t\t\t\tleft join xchan on channel_hash = xchan_hash\n\t\t\t\t\twhere channel_guid = '%s' and channel_guid_sig = '%s' limit 1", dbesc($recip['guid']), dbesc($recip['guid_sig']));
                $x = zot_refresh(array('xchan_guid' => $sender['guid'], 'xchan_guid_sig' => $sender['guid_sig'], 'hubloc_url' => $sender['url']), $r[0], $msgtype === 'force_refresh' ? true : false);
            }
        } else {
            // system wide refresh
            $x = zot_refresh(array('xchan_guid' => $sender['guid'], 'xchan_guid_sig' => $sender['guid_sig'], 'hubloc_url' => $sender['url']), null, $msgtype === 'force_refresh' ? true : false);
        }
        $ret['success'] = true;
        json_return_and_die($ret);
    }
    if ($msgtype === 'notify') {
        $async = get_config('system', 'queued_fetch');
        if ($async) {
            // add to receive queue
            // qreceive_add($data);
        } else {
            $x = zot_fetch($data);
            $ret['delivery_report'] = $x;
        }
        $ret['success'] = true;
        json_return_and_die($ret);
    }
    // catchall
    json_return_and_die($ret);
}
예제 #16
0
function dfrn_notify_post(&$a)
{
    $dfrn_id = x($_POST, 'dfrn_id') ? notags(trim($_POST['dfrn_id'])) : '';
    $dfrn_version = x($_POST, 'dfrn_version') ? (double) $_POST['dfrn_version'] : 2.0;
    $challenge = x($_POST, 'challenge') ? notags(trim($_POST['challenge'])) : '';
    $data = x($_POST, 'data') ? $_POST['data'] : '';
    $key = x($_POST, 'key') ? $_POST['key'] : '';
    $dissolve = x($_POST, 'dissolve') ? intval($_POST['dissolve']) : 0;
    $perm = x($_POST, 'perm') ? notags(trim($_POST['perm'])) : 'r';
    $ssl_policy = x($_POST, 'ssl_policy') ? notags(trim($_POST['ssl_policy'])) : 'none';
    $page = x($_POST, 'page') ? intval($_POST['page']) : 0;
    $forum = $page == 1 ? 1 : 0;
    $prv = $page == 2 ? 1 : 0;
    $writable = -1;
    if ($dfrn_version >= 2.21) {
        $writable = $perm === 'rw' ? 1 : 0;
    }
    $direction = -1;
    if (strpos($dfrn_id, ':') == 1) {
        $direction = intval(substr($dfrn_id, 0, 1));
        $dfrn_id = substr($dfrn_id, 2);
    }
    $r = q("SELECT * FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1", dbesc($dfrn_id), dbesc($challenge));
    if (!count($r)) {
        logger('dfrn_notify: could not match challenge to dfrn_id ' . $dfrn_id . ' challenge=' . $challenge);
        xml_status(3);
    }
    $r = q("DELETE FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1", dbesc($dfrn_id), dbesc($challenge));
    // find the local user who owns this relationship.
    $sql_extra = '';
    switch ($direction) {
        case -1:
            $sql_extra = sprintf(" AND ( `issued-id` = '%s' OR `dfrn-id` = '%s' ) ", dbesc($dfrn_id), dbesc($dfrn_id));
            break;
        case 0:
            $sql_extra = sprintf(" AND `issued-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id));
            break;
        case 1:
            $sql_extra = sprintf(" AND `dfrn-id` = '%s' AND `duplex` = 1 ", dbesc($dfrn_id));
            break;
        default:
            xml_status(3);
            break;
            // NOTREACHED
    }
    // be careful - $importer will contain both the contact information for the contact
    // sending us the post, and also the user information for the person receiving it.
    // since they are mixed together, it is easy to get them confused.
    $r = q("SELECT\t`contact`.*, `contact`.`uid` AS `importer_uid`, \n\t\t\t\t\t`contact`.`pubkey` AS `cpubkey`, \n\t\t\t\t\t`contact`.`prvkey` AS `cprvkey`, \n\t\t\t\t\t`contact`.`thumb` AS `thumb`, \n\t\t\t\t\t`contact`.`url` as `url`,\n\t\t\t\t\t`contact`.`name` as `senderName`,\n\t\t\t\t\t`user`.* \n\t\t\tFROM `contact` \n\t\t\tLEFT JOIN `user` ON `contact`.`uid` = `user`.`uid` \n\t\t\tWHERE `contact`.`blocked` = 0 AND `contact`.`pending` = 0 \n\t\t\t\tAND `user`.`nickname` = '%s' AND `user`.`account_expired` = 0 {$sql_extra} LIMIT 1", dbesc($a->argv[1]));
    if (!count($r)) {
        logger('dfrn_notify: contact not found for dfrn_id ' . $dfrn_id);
        xml_status(3);
        //NOTREACHED
    }
    // $importer in this case contains the contact record for the remote contact joined with the user record of our user.
    $importer = $r[0];
    if ($writable != -1 && $writable != $importer['writable'] || $importer['forum'] != $forum || $importer['prv'] != $prv) {
        q("UPDATE `contact` SET `writable` = %d, forum = %d, prv = %d WHERE `id` = %d LIMIT 1", intval($writable == -1 ? $importer['writable'] : $writable), intval($forum), intval($prv), intval($importer['id']));
        if ($writable != -1) {
            $importer['writable'] = $writable;
        }
        $importer['forum'] = $page;
    }
    // if contact's ssl policy changed, update our links
    fix_contact_ssl_policy($importer, $ssl_policy);
    logger('dfrn_notify: received notify from ' . $importer['name'] . ' for ' . $importer['username']);
    logger('dfrn_notify: data: ' . $data, LOGGER_DATA);
    if ($dissolve == 1) {
        /**
         * Relationship is dissolved permanently
         */
        require_once 'include/Contact.php';
        contact_remove($importer['id']);
        logger('relationship dissolved : ' . $importer['name'] . ' dissolved ' . $importer['username']);
        xml_status(0);
    }
    // If we are setup as a soapbox we aren't accepting input from this person
    if ($importer['page-flags'] == PAGE_SOAPBOX) {
        xml_status(0);
    }
    if (strlen($key)) {
        $rawkey = hex2bin(trim($key));
        logger('rino: md5 raw key: ' . md5($rawkey));
        $final_key = '';
        if ($dfrn_version >= 2.1) {
            if ($importer['duplex'] && strlen($importer['cprvkey']) || !strlen($importer['cpubkey'])) {
                openssl_private_decrypt($rawkey, $final_key, $importer['cprvkey']);
            } else {
                openssl_public_decrypt($rawkey, $final_key, $importer['cpubkey']);
            }
        } else {
            if ($importer['duplex'] && strlen($importer['cpubkey']) || !strlen($importer['cprvkey'])) {
                openssl_public_decrypt($rawkey, $final_key, $importer['cpubkey']);
            } else {
                openssl_private_decrypt($rawkey, $final_key, $importer['cprvkey']);
            }
        }
        logger('rino: received key : ' . $final_key);
        $data = aes_decrypt(hex2bin($data), $final_key);
        logger('rino: decrypted data: ' . $data, LOGGER_DATA);
    }
    $ret = local_delivery($importer, $data);
    xml_status($ret);
    // NOTREACHED
}
예제 #17
0
function diaspora_retraction($importer, $xml, $msg = null)
{
    $guid = notags(diaspora_get_target_guid($xml));
    $diaspora_handle = notags(diaspora_get_author($xml));
    $type = notags(diaspora_get_type($xml));
    $contact = diaspora_get_contact_by_handle($importer['channel_id'], $diaspora_handle);
    if (!$contact) {
        return;
    }
    if ($type === 'Person' || $type === 'Contact') {
        contact_remove($importer['channel_id'], $contact['abook_id']);
    } elseif ($type === 'Post' || $type === 'StatusMessage' || $type === 'Comment' || $type === 'Like') {
        $r = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc('guid'), intval($importer['channel_id']));
        if ($r) {
            if (link_compare($r[0]['author_xchan'], $contact['xchan_hash']) || link_compare($r[0]['owner_xchan'], $contact['xchan_hash'])) {
                drop_item($r[0]['id'], false);
            }
            // @FIXME - ensure that relay is performed if this was an upstream
            // Could probably check if we're the owner and it is a like or comment
            // This may or may not be handled by drop_item
        }
    }
    return 202;
    // NOTREACHED
}
예제 #18
0
function diaspora_retraction($importer, $xml)
{
    $guid = notags(unxmlify($xml->guid));
    $diaspora_handle = notags(unxmlify($xml->diaspora_handle));
    $type = notags(unxmlify($xml->type));
    $contact = diaspora_get_contact_by_handle($importer['uid'], $diaspora_handle);
    if (!$contact) {
        return;
    }
    if ($type === 'Person') {
        require_once 'include/Contact.php';
        contact_remove($contact['id']);
    } elseif ($type === 'Post') {
        $r = q("select * from item where guid = '%s' and uid = %d and not file like '%%[%%' limit 1", dbesc('guid'), intval($importer['uid']));
        if (count($r)) {
            if (link_compare($r[0]['author-link'], $contact['url'])) {
                q("update item set `deleted` = 1, `changed` = '%s' where `id` = %d", dbesc(datetime_convert()), intval($r[0]['id']));
                delete_thread($r[0]['id'], $r[0]['parent-uri']);
            }
        }
    }
    return 202;
    // NOTREACHED
}
예제 #19
0
function contacts_content(&$a)
{
    if (!local_user()) {
        notice(t('Permission denied.') . EOL);
        return;
    }
    if ($a->argc == 3) {
        $contact_id = intval($a->argv[1]);
        if (!$contact_id) {
            return;
        }
        $cmd = $a->argv[2];
        $orig_record = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1", intval($contact_id));
        if (!count($orig_record)) {
            notice(t('Could not access contact record.') . EOL);
            goaway($a->get_baseurl() . '/contacts');
            return;
            // NOTREACHED
        }
        if ($cmd == 'block') {
            $blocked = $orig_record[0]['blocked'] ? 0 : 1;
            $r = q("UPDATE `contact` SET `blocked` = %d WHERE `id` = %d LIMIT 1", intval($blocked), intval($contact_id));
            if ($r) {
                notice(t('Contact has been ') . ($blocked ? t('blocked') : t('unblocked')) . EOL);
            }
            goaway($a->get_baseurl() . '/contacts/' . $contact_id);
            return;
            // NOTREACHED
        }
        if ($cmd == 'ignore') {
            $readonly = $orig_record[0]['readonly'] ? 0 : 1;
            $r = q("UPDATE `contact` SET `readonly` = %d WHERE `id` = %d LIMIT 1", intval($readonly), intval($contact_id));
            if ($r) {
                notice(t('Contact has been ') . ($readonly ? t('ignored') : t('unignored')) . EOL);
            }
            goaway($a->get_baseurl() . '/contacts/' . $contact_id);
            return;
            // NOTREACHED
        }
        if ($cmd == 'drop') {
            contact_remove($contact_id);
            notice(t("Contact has been removed.") . EOL);
            goaway($a->get_baseurl() . '/contacts');
            return;
            // NOTREACHED
        }
    }
    if ($a->argc == 2 && intval($a->argv[1])) {
        $contact_id = intval($a->argv[1]);
        $r = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1", intval($contact_id));
        if (!count($r)) {
            notice(t('Contact not found.') . EOL);
            return;
        }
        require_once 'view/contact_selectors.php';
        $tpl = file_get_contents("view/contact_edit.tpl");
        switch ($r[0]['rel']) {
            case DIRECTION_BOTH:
                $dir_icon = 'images/lrarrow.gif';
                $alt_text = t('Mutual Friendship');
                break;
            case DIRECTION_IN:
                $dir_icon = 'images/larrow.gif';
                $alt_text = t('is a fan of yours');
                break;
            case DIRECTION_OUT:
                $dir_icon = 'images/rarrow.gif';
                $alt_text = t('you are a fan of');
                break;
            default:
                break;
        }
        $o .= replace_macros($tpl, array('$poll_interval' => contact_poll_interval($r[0]['priority']), '$last_update' => $r[0]['last-update'] == '0000-00-00 00:00:00' ? t('Never') : datetime_convert('UTC', date_default_timezone_get(), $r[0]['last-update'], 'D, j M Y, g:i A'), '$profile_select' => contact_profile_assign($r[0]['profile-id']), '$contact_id' => $r[0]['id'], '$block_text' => $r[0]['blocked'] ? t('Unblock this contact') : t('Block this contact'), '$ignore_text' => $r[0]['readonly'] ? t('Unignore this contact') : t('Ignore this contact'), '$blocked' => $r[0]['blocked'] ? '<div id="block-message">' . t('Currently blocked') . '</div>' : '', '$ignored' => $r[0]['readonly'] ? '<div id="ignore-message">' . t('Currently ignored') . '</div>' : '', '$rating' => contact_reputation($r[0]['rating']), '$reason' => $r[0]['reason'], '$groups' => '', '$photo' => $r[0]['photo'], '$name' => $r[0]['name'], '$dir_icon' => $dir_icon, '$alt_text' => $alt_text, '$url' => $r[0]['rel'] != DIRECTION_OUT ? "redir/{$r[0]['id']}" : $r[0]['url']));
        return $o;
    }
    if ($a->argc == 2 && $a->argv[1] == 'all') {
        $sql_extra = '';
    } else {
        $sql_extra = " AND `blocked` = 0 ";
    }
    $search = x($_GET, 'search') ? notags(trim($_GET['search'])) : '';
    $tpl = file_get_contents("view/contacts-top.tpl");
    $o .= replace_macros($tpl, array('$hide_url' => strlen($sql_extra) ? 'contacts/all' : 'contacts', '$hide_text' => strlen($sql_extra) ? t('Show Blocked Connections') : t('Hide Blocked Connections'), '$search' => $search, '$finding' => strlen($search) ? '<h4>' . t('Finding: ') . "'" . $search . "'" . '</h4>' : "", '$submit' => t('Find'), '$cmd' => $a->cmd));
    if ($search) {
        $search = dbesc($search . '*');
    }
    $sql_extra .= strlen($search) ? " AND MATCH `name` AGAINST ('{$search}' IN BOOLEAN MODE) " : "";
    switch ($sort_type) {
        case DIRECTION_BOTH:
            $sql_extra2 = " AND `dfrn-id` != '' AND `issued-id` != '' ";
            break;
        case DIRECTION_IN:
            $sql_extra2 = " AND `dfrn-id` = '' AND `issued-id` != '' ";
            break;
        case DIRECTION_OUT:
            $sql_extra2 = " AND `dfrn-id` != '' AND `issued-id` = '' ";
            break;
        case DIRECTION_NONE:
        default:
            $sql_extra2 = '';
            break;
    }
    $r = q("SELECT COUNT(*) AS `total` FROM `contact` \n\t\tWHERE `pending` = 0 {$sql_extra} {$sql_extra2} ");
    if (count($r)) {
        $a->set_pager_total($r[0]['total']);
    }
    $r = q("SELECT * FROM `contact` WHERE `pending` = 0 {$sql_extra} {$sql_extra2} ORDER BY `name` ASC LIMIT %d , %d ", intval($a->pager['start']), intval($a->pager['itemspage']));
    if (count($r)) {
        $tpl = file_get_contents("view/contact_template.tpl");
        foreach ($r as $rr) {
            if ($rr['self']) {
                continue;
            }
            switch ($rr['rel']) {
                case DIRECTION_BOTH:
                    $dir_icon = 'images/lrarrow.gif';
                    $alt_text = t('Mutual Friendship');
                    break;
                case DIRECTION_IN:
                    $dir_icon = 'images/larrow.gif';
                    $alt_text = t('is a fan of yours');
                    break;
                case DIRECTION_OUT:
                    $dir_icon = 'images/rarrow.gif';
                    $alt_text = t('you are a fan of');
                    break;
                default:
                    break;
            }
            $o .= replace_macros($tpl, array('$img_hover' => t('Visit ') . $rr['name'] . t('\'s profile'), '$edit_hover' => t('Edit contact'), '$id' => $rr['id'], '$alt_text' => $alt_text, '$dir_icon' => $dir_icon, '$thumb' => $rr['thumb'], '$name' => $rr['name'], '$url' => $rr['rel'] != DIRECTION_OUT ? "redir/{$rr['id']}" : $rr['url']));
        }
        $o .= '<div id="contact-edit-end"></div>';
    }
    $o .= paginate($a);
    return $o;
}