Exemplo n.º 1
0
function diaspora_mention_callback($matches)
{
    $webbie = $matches[2] . '@' . $matches[3];
    $link = '';
    if ($webbie) {
        $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_addr = '%s' limit 1", dbesc($webbie));
        if (!$r) {
            $x = discover_by_webbie($webbie);
            if ($x) {
                $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_addr = '%s' limit 1", dbesc($webbie));
            }
        }
        if ($r) {
            $link = $r[0]['xchan_url'];
        }
    }
    if (!$link) {
        $link = 'https://' . $matches[3] . '/u/' . $matches[2];
    }
    if ($r && $r[0]['hubloc_network'] === 'zot') {
        return '@[zrl=' . $link . ']' . trim($matches[1]) . (substr($matches[0], -1, 1) === '+' ? '+' : '') . '[/zrl]';
    } else {
        return '@[url=' . $link . ']' . trim($matches[1]) . (substr($matches[0], -1, 1) === '+' ? '+' : '') . '[/url]';
    }
}
Exemplo n.º 2
0
function find_diaspora_person_by_handle($handle)
{
    $person = false;
    $refresh = false;
    if (diaspora_is_blacklisted($handle)) {
        return false;
    }
    $r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' limit 1", dbesc($handle));
    if ($r) {
        $person = $r[0];
        logger('find_diaspora_person_by handle: in cache ' . print_r($r, true), LOGGER_DATA, LOG_DEBUG);
        if ($person['xchan_name_date'] < datetime_convert('UTC', 'UTC', 'now - 1 month')) {
            logger('Updating Diaspora cached record for ' . $handle);
            $refresh = true;
        }
    }
    if (!$person || $refresh) {
        // try webfinger. Make sure to distinguish between diaspora,
        // hubzilla w/diaspora protocol and friendica w/diaspora protocol.
        $result = discover_by_webbie($handle);
        if ($result) {
            $r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' limit 1", dbesc(str_replace('acct:', '', $handle)));
            if ($r) {
                $person = $r[0];
                logger('find_diaspora_person_by handle: discovered ' . print_r($r, true), LOGGER_DATA, LOG_DEBUG);
            }
        }
    }
    return $person;
}
Exemplo n.º 3
0
function gnusoc_follow_from_feed(&$a, &$b)
{
    $item = $b['item'];
    $importer = $b['channel'];
    $xchan = $b['xchan'];
    $author = $b['author'];
    $b['caught'] = true;
    logger('follow activity received');
    if ($author && !$xchan) {
        $r = q("select * from xchan where xchan_guid = '%s' limit 1", dbesc($author['author_link']));
        if (!$r) {
            if (discover_by_webbie($author['author_link'])) {
                $r = q("select * from xchan where xchan_guid = '%s' limit 1", dbesc($author['author_link']));
                if (!$r) {
                    logger('discovery failed');
                    return;
                }
            }
            $xchan = $r[0];
        }
        $x = \Zotlabs\Access\PermissionRoles::role_perms('social');
        $their_perms = \Zotlabs\Access\Permissions::FilledPerms($x['perms_connect']);
        $r = q("select * from abook where abook_channel = %d and abook_xchan = '%s' limit 1", intval($importer['channel_id']), dbesc($xchan['xchan_hash']));
        if ($r) {
            $contact = $r[0];
            $abook_instance = $contact['abook_instance'];
            if ($abook_instance) {
                $abook_instance .= ',';
            }
            $abook_instance .= z_root();
            $r = q("update abook set abook_instance = '%s' where abook_id = %d and abook_channel = %d", dbesc($abook_instance), intval($contact['abook_id']), intval($importer['channel_id']));
            foreach ($their_perms as $k => $v) {
                set_abconfig($importer['channel_id'], $contact['abook_xchan'], 'their_perms', $k, $v);
            }
        } else {
            $role = get_pconfig($importer['channel_id'], 'system', 'permissions_role');
            if ($role) {
                $x = \Zotlabs\Access\PermissionRoles::role_perms($role);
                if ($x['perms_auto']) {
                    $my_perms = \Zotlabs\Access\Permissions::FilledPerms($x['perms_connect']);
                }
            }
            if (!$my_perms) {
                $my_perms = \Zotlabs\Access\Permissions::FilledAutoperms($importer['channel_id']);
            }
            $closeness = get_pconfig($importer['channel_id'], 'system', 'new_abook_closeness');
            if ($closeness === false) {
                $closeness = 80;
            }
            $r = q("insert into abook ( abook_account, abook_channel, abook_xchan, abook_closeness, abook_created, abook_updated, abook_connected, abook_dob, abook_pending, abook_instance ) values ( %d, %d, '%s', %d, '%s', '%s', '%s', '%s', %d, '%s' )", intval($importer['channel_account_id']), intval($importer['channel_id']), dbesc($xchan['xchan_hash']), intval($closeness), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(NULL_DATE), intval($my_perms ? 0 : 1), dbesc(z_root()));
            if ($r) {
                if ($my_perms) {
                    foreach ($my_perms as $k => $v) {
                        set_abconfig($importer['channel_id'], $xchan['xchan_hash'], 'my_perms', $k, $v);
                    }
                }
                if ($their_perms) {
                    foreach ($their_perms as $k => $v) {
                        set_abconfig($importer['channel_id'], $xchan['xchan_hash'], 'their_perms', $k, $v);
                    }
                }
                logger("New GNU-Social follower received for {$importer['channel_name']}");
                $new_connection = q("select * from abook left join xchan on abook_xchan = xchan_hash left join hubloc on hubloc_hash = xchan_hash where abook_channel = %d and abook_xchan = '%s' order by abook_created desc limit 1", intval($importer['channel_id']), dbesc($xchan['xchan_hash']));
                if ($new_connection) {
                    \Zotlabs\Lib\Enotify::submit(array('type' => NOTIFY_INTRO, 'from_xchan' => $xchan['xchan_hash'], 'to_xchan' => $importer['channel_hash'], 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id']));
                    if ($default_perms) {
                        // Send back a sharing notification to them
                        $deliver = gnusoc_remote_follow($importer, $new_connection[0]);
                        if ($deliver) {
                            Zotlabs\Daemon\Master::Summon(array('Deliver', $deliver));
                        }
                    }
                    $clone = array();
                    foreach ($new_connection[0] as $k => $v) {
                        if (strpos($k, 'abook_') === 0) {
                            $clone[$k] = $v;
                        }
                    }
                    unset($clone['abook_id']);
                    unset($clone['abook_account']);
                    unset($clone['abook_channel']);
                    $abconfig = load_abconfig($importer['channel_id'], $clone['abook_xchan']);
                    if ($abconfig) {
                        $clone['abconfig'] = $abconfig;
                    }
                    build_sync_packet($importer['channel_id'], array('abook' => array($clone)));
                }
            }
        }
        return;
    }
}
Exemplo n.º 4
0
/**
 * @brief Imports an author from Diaspora.
 *
 * @param array $x an associative array with
 *   * \e string \b address
 * @return boolean|string false on error, otherwise xchan_hash of the new entry
 */
function import_author_diaspora($x)
{
    if (!$x['address']) {
        return false;
    }
    $r = q("select * from xchan where xchan_addr = '%s' limit 1", dbesc($x['address']));
    if ($r) {
        logger('in_cache: ' . $x['address'], LOGGER_DATA);
        return $r[0]['xchan_hash'];
    }
    if (discover_by_webbie($x['address'])) {
        $r = q("select xchan_hash from xchan where xchan_addr = '%s' limit 1", dbesc($x['address']));
        if ($r) {
            return $r[0]['xchan_hash'];
        }
    }
    return false;
}
Exemplo n.º 5
0
function new_contact($uid, $url, $channel, $interactive = false, $confirm = false)
{
    $result = array('success' => false, 'message' => '');
    $is_red = false;
    $is_http = strpos($url, '://') !== false ? true : false;
    if ($is_http && substr($url, -1, 1) === '/') {
        $url = substr($url, 0, -1);
    }
    if (!allowed_url($url)) {
        $result['message'] = t('Channel is blocked on this site.');
        return $result;
    }
    if (!$url) {
        $result['message'] = t('Channel location missing.');
        return $result;
    }
    // check service class limits
    $r = q("select count(*) as total from abook where abook_channel = %d and abook_self = 0 ", intval($uid));
    if ($r) {
        $total_channels = $r[0]['total'];
    }
    if (!service_class_allows($uid, 'total_channels', $total_channels)) {
        $result['message'] = upgrade_message();
        return $result;
    }
    $arr = array('url' => $url, 'channel' => array());
    call_hooks('follow', $arr);
    if ($arr['channel']['success']) {
        $ret = $arr['channel'];
    } elseif (!$is_http) {
        $ret = Zotlabs\Zot\Finger::run($url, $channel);
    }
    if ($ret && is_array($ret) && $ret['success']) {
        $is_red = true;
        $j = $ret;
    }
    $my_perms = get_channel_default_perms($uid);
    $role = get_pconfig($uid, 'system', 'permissions_role');
    if ($role) {
        $x = \Zotlabs\Access\PermissionRoles::role_perms($role);
        if ($x['perms_connect']) {
            $my_perms = $x['perms_connect'];
        }
    }
    if ($is_red && $j) {
        logger('follow: ' . $url . ' ' . print_r($j, true), LOGGER_DEBUG);
        if (!($j['success'] && $j['guid'])) {
            $result['message'] = t('Response from remote channel was incomplete.');
            logger('mod_follow: ' . $result['message']);
            return $result;
        }
        // Premium channel, set confirm before callback to avoid recursion
        if (array_key_exists('connect_url', $j) && $interactive && !$confirm) {
            goaway(zid($j['connect_url']));
        }
        // do we have an xchan and hubloc?
        // If not, create them.
        $x = import_xchan($j);
        if (array_key_exists('deleted', $j) && intval($j['deleted'])) {
            $result['message'] = t('Channel was deleted and no longer exists.');
            return $result;
        }
        if (!$x['success']) {
            return $x;
        }
        $xchan_hash = $x['hash'];
        if (array_key_exists('permissions', $j) && array_key_exists('data', $j['permissions'])) {
            $permissions = crypto_unencapsulate(array('data' => $j['permissions']['data'], 'key' => $j['permissions']['key'], 'iv' => $j['permissions']['iv']), $channel['channel_prvkey']);
            if ($permissions) {
                $permissions = json_decode($permissions, true);
            }
            logger('decrypted permissions: ' . print_r($permissions, true), LOGGER_DATA);
        } else {
            $permissions = $j['permissions'];
        }
        if (is_array($permissions) && $permissions) {
            foreach ($permissions as $k => $v) {
                set_abconfig($channel['channel_uid'], $xchan_hash, 'their_perms', $k, intval($v));
            }
        }
    } else {
        $xchan_hash = '';
        $r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' limit 1", dbesc($url), dbesc($url));
        if (!$r) {
            // attempt network auto-discovery
            $d = discover_by_webbie($url);
            if (!$d && $is_http) {
                // try RSS discovery
                if (get_config('system', 'feed_contacts')) {
                    $d = discover_by_url($url);
                } else {
                    $result['message'] = t('Protocol disabled.');
                    return $result;
                }
            }
            if ($d) {
                $r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' limit 1", dbesc($url), dbesc($url));
            }
        }
        // if discovery was a success we should have an xchan record in $r
        if ($r) {
            $xchan = $r[0];
            $xchan_hash = $r[0]['xchan_hash'];
            $their_perms = 0;
        }
    }
    if (!$xchan_hash) {
        $result['message'] = t('Channel discovery failed.');
        logger('follow: ' . $result['message']);
        return $result;
    }
    $allowed = $is_red || $r[0]['xchan_network'] === 'rss' ? 1 : 0;
    $x = array('channel_id' => $uid, 'follow_address' => $url, 'xchan' => $r[0], 'allowed' => $allowed, 'singleton' => 0);
    call_hooks('follow_allow', $x);
    if (!$x['allowed']) {
        $result['message'] = t('Protocol disabled.');
        return $result;
    }
    $singleton = intval($x['singleton']);
    $aid = $channel['channel_account_id'];
    $hash = get_observer_hash();
    $default_group = $channel['channel_default_group'];
    if ($xchan['xchan_network'] === 'rss') {
        // check service class feed limits
        $r = q("select count(*) as total from abook where abook_account = %d and abook_feed = 1 ", intval($aid));
        if ($r) {
            $total_feeds = $r[0]['total'];
        }
        if (!service_class_allows($uid, 'total_feeds', $total_feeds)) {
            $result['message'] = upgrade_message();
            return $result;
        }
    }
    if ($hash == $xchan_hash) {
        $result['message'] = t('Cannot connect to yourself.');
        return $result;
    }
    $r = q("select abook_xchan, abook_instance from abook where abook_xchan = '%s' and abook_channel = %d limit 1", dbesc($xchan_hash), intval($uid));
    if ($is_http) {
        // Always set these "remote" permissions for feeds since we cannot interact with them
        // to negotiate a suitable permission response
        set_abconfig($uid, $xchan_hash, 'their_perms', 'view_stream', 1);
        set_abconfig($uid, $xchan_hash, 'their_perms', 'republish', 1);
    }
    if ($r) {
        $abook_instance = $r[0]['abook_instance'];
        if ($singleton && strpos($abook_instance, z_root()) === false) {
            if ($abook_instance) {
                $abook_instance .= ',';
            }
            $abook_instance .= z_root();
        }
        $x = q("update abook set abook_instance = '%s' where abook_id = %d", dbesc($abook_instance), intval($r[0]['abook_id']));
    } else {
        $closeness = get_pconfig($uid, 'system', 'new_abook_closeness');
        if ($closeness === false) {
            $closeness = 80;
        }
        $r = q("insert into abook ( abook_account, abook_channel, abook_closeness, abook_xchan, abook_feed, abook_created, abook_updated, abook_instance )\n\t\t\tvalues( %d, %d, %d, '%s', %d, '%s', '%s', '%s' ) ", intval($aid), intval($uid), intval($closeness), dbesc($xchan_hash), intval($is_http ? 1 : 0), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($singleton ? z_root() : ''));
    }
    if (!$r) {
        logger('mod_follow: abook creation failed');
    }
    $all_perms = \Zotlabs\Access\Permissions::Perms();
    if ($all_perms) {
        foreach ($all_perms as $k => $v) {
            if (in_array($k, $my_perms)) {
                set_abconfig($uid, $xchan_hash, 'my_perms', $k, 1);
            } else {
                set_abconfig($uid, $xchan_hash, 'my_perms', $k, 0);
            }
        }
    }
    $r = q("select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash \n\t\twhere abook_xchan = '%s' and abook_channel = %d limit 1", dbesc($xchan_hash), intval($uid));
    if ($r) {
        $result['abook'] = $r[0];
        Zotlabs\Daemon\Master::Summon(array('Notifier', 'permission_create', $result['abook']['abook_id']));
    }
    $arr = array('channel_id' => $uid, 'channel' => $channel, 'abook' => $result['abook']);
    call_hooks('follow', $arr);
    /** If there is a default group for this channel, add this connection to it */
    if ($default_group) {
        require_once 'include/group.php';
        $g = group_rec_byhash($uid, $default_group);
        if ($g) {
            group_add_member($uid, '', $xchan_hash, $g['id']);
        }
    }
    $result['success'] = true;
    return $result;
}
Exemplo n.º 6
0
function diaspora_permissions_update(&$a, &$b)
{
    if ($b['recipient']['xchan_network'] === 'diaspora' || $b['recipient']['xchan_network'] === 'friendica-over-diaspora') {
        discover_by_webbie($b['recipient']['xchan_hash']);
        $b['success'] = 1;
    }
}
Exemplo n.º 7
0
function find_diaspora_person_by_handle($handle)
{
    $person = false;
    if (diaspora_is_blacklisted($handle)) {
        return false;
    }
    $r = q("select * from xchan where xchan_addr = '%s' limit 1", dbesc($handle));
    if ($r) {
        $person = $r[0];
        logger('find_diaspora_person_by handle: in cache ' . print_r($r, true), LOGGER_DATA);
    }
    if (!$person) {
        // try webfinger. Make sure to distinguish between diaspora,
        // redmatrix w/diaspora protocol and friendica w/diaspora protocol.
        $result = discover_by_webbie($handle);
        if ($result) {
            $r = q("select * from xchan where xchan_addr = '%s' limit 1", dbesc($handle));
            if ($r) {
                $person = $r[0];
                logger('find_diaspora_person_by handle: discovered ' . print_r($r, true), LOGGER_DATA);
            }
        }
    }
    return $person;
}
Exemplo n.º 8
0
function new_contact($uid, $url, $channel, $interactive = false, $confirm = false)
{
    $result = array('success' => false, 'message' => '');
    $a = get_app();
    $is_red = false;
    $is_http = strpos($url, '://') !== false ? true : false;
    if ($is_http && substr($url, -1, 1) === '/') {
        $url = substr($url, 0, -1);
    }
    if (!allowed_url($url)) {
        $result['message'] = t('Channel is blocked on this site.');
        return $result;
    }
    if (!$url) {
        $result['message'] = t('Channel location missing.');
        return $result;
    }
    // check service class limits
    $r = q("select count(*) as total from abook where abook_channel = %d and abook_self = 0 ", intval($uid));
    if ($r) {
        $total_channels = $r[0]['total'];
    }
    if (!service_class_allows($uid, 'total_channels', $total_channels)) {
        $result['message'] = upgrade_message();
        return $result;
    }
    $arr = array('url' => $url, 'channel' => array());
    call_hooks('follow', $arr);
    if ($arr['channel']['success']) {
        $ret = $arr['channel'];
    } elseif (!$is_http) {
        $ret = zot_finger($url, $channel);
    }
    if ($ret && $ret['success']) {
        $is_red = true;
        $j = json_decode($ret['body'], true);
    }
    $my_perms = get_channel_default_perms($uid);
    $role = get_pconfig($uid, 'system', 'permissions_role');
    if ($role) {
        $x = get_role_perms($role);
        if ($x['perms_follow']) {
            $my_perms = $x['perms_follow'];
        }
    }
    if ($is_red && $j) {
        logger('follow: ' . $url . ' ' . print_r($j, true), LOGGER_DEBUG);
        if (!($j['success'] && $j['guid'])) {
            $result['message'] = t('Response from remote channel was incomplete.');
            logger('mod_follow: ' . $result['message']);
            return $result;
        }
        // Premium channel, set confirm before callback to avoid recursion
        if (array_key_exists('connect_url', $j) && $interactive && !$confirm) {
            goaway(zid($j['connect_url']));
        }
        // do we have an xchan and hubloc?
        // If not, create them.
        $x = import_xchan($j);
        if (array_key_exists('deleted', $j) && intval($j['deleted'])) {
            $result['message'] = t('Channel was deleted and no longer exists.');
            return $result;
        }
        if (!$x['success']) {
            return $x;
        }
        $xchan_hash = $x['hash'];
        $their_perms = 0;
        $global_perms = get_perms();
        if (array_key_exists('permissions', $j) && array_key_exists('data', $j['permissions'])) {
            $permissions = crypto_unencapsulate(array('data' => $j['permissions']['data'], 'key' => $j['permissions']['key'], 'iv' => $j['permissions']['iv']), $channel['channel_prvkey']);
            if ($permissions) {
                $permissions = json_decode($permissions, true);
            }
            logger('decrypted permissions: ' . print_r($permissions, true), LOGGER_DATA);
        } else {
            $permissions = $j['permissions'];
        }
        foreach ($permissions as $k => $v) {
            if ($v) {
                $their_perms = $their_perms | intval($global_perms[$k][1]);
            }
        }
    } else {
        $their_perms = 0;
        $xchan_hash = '';
        $r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' limit 1", dbesc($url), dbesc($url));
        if (!$r) {
            // attempt network auto-discovery
            if (strpos($url, '@') && !$is_http) {
                $r = discover_by_webbie($url);
            } elseif ($is_http) {
                $r = discover_by_url($url);
                $r['allowed'] = intval(get_config('system', 'feed_contacts'));
            }
            if ($r) {
                $r['channel_id'] = $uid;
                call_hooks('follow_allow', $r);
                if (!$r['allowed']) {
                    $result['message'] = t('Protocol disabled.');
                    return $result;
                }
                $r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' limit 1", dbesc($url), dbesc($url));
            }
        }
        if ($r) {
            $xchan_hash = $r[0]['xchan_hash'];
            $their_perms = 0;
        }
    }
    if (!$xchan_hash) {
        $result['message'] = t('Channel discovery failed.');
        logger('follow: ' . $result['message']);
        return $result;
    }
    if (local_channel() && $uid == local_channel()) {
        $aid = get_account_id();
        $hash = get_observer_hash();
        $ch = $a->get_channel();
        $default_group = $ch['channel_default_group'];
    } else {
        $r = q("select * from channel where channel_id = %d limit 1", intval($uid));
        if (!$r) {
            $result['message'] = t('local account not found.');
            return $result;
        }
        $aid = $r[0]['channel_account_id'];
        $hash = $r[0]['channel_hash'];
        $default_group = $r[0]['channel_default_group'];
    }
    if ($is_http) {
        $r = q("select count(*) as total from abook where abook_account = %d and abook_feed = 1 ", intval($aid));
        if ($r) {
            $total_feeds = $r[0]['total'];
        }
        if (!service_class_allows($uid, 'total_feeds', $total_feeds)) {
            $result['message'] = upgrade_message();
            return $result;
        }
    }
    if ($hash == $xchan_hash) {
        $result['message'] = t('Cannot connect to yourself.');
        return $result;
    }
    $r = q("select abook_xchan from abook where abook_xchan = '%s' and abook_channel = %d limit 1", dbesc($xchan_hash), intval($uid));
    if ($r) {
        $x = q("update abook set abook_their_perms = %d where abook_id = %d", intval($their_perms), intval($r[0]['abook_id']));
    } else {
        $closeness = get_pconfig($uid, 'system', 'new_abook_closeness');
        if ($closeness === false) {
            $closeness = 80;
        }
        $r = q("insert into abook ( abook_account, abook_channel, abook_closeness, abook_xchan, abook_feed, abook_their_perms, abook_my_perms, abook_created, abook_updated )\n\t\t\tvalues( %d, %d, %d, '%s', %d, %d, %d, '%s', '%s' ) ", intval($aid), intval($uid), intval($closeness), dbesc($xchan_hash), intval($is_http ? 1 : 0), intval($is_http ? $their_perms | PERMS_R_STREAM | PERMS_A_REPUBLISH : $their_perms), intval($my_perms), dbesc(datetime_convert()), dbesc(datetime_convert()));
    }
    if (!$r) {
        logger('mod_follow: abook creation failed');
    }
    $r = q("select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash \n\t\twhere abook_xchan = '%s' and abook_channel = %d limit 1", dbesc($xchan_hash), intval($uid));
    if ($r) {
        $result['abook'] = $r[0];
        proc_run('php', 'include/notifier.php', 'permission_update', $result['abook']['abook_id']);
    }
    $arr = array('channel_id' => $uid, 'abook' => $result['abook']);
    call_hooks('follow', $arr);
    /** If there is a default group for this channel, add this member to it */
    if ($default_group) {
        require_once 'include/group.php';
        $g = group_rec_byhash($uid, $default_group);
        if ($g) {
            group_add_member($uid, '', $xchan_hash, $g['id']);
        }
    }
    $result['success'] = true;
    return $result;
}
Exemplo n.º 9
0
function salmon_post(&$a)
{
    $sys_disabled = true;
    if (!get_config('system', 'disable_discover_tab')) {
        $sys_disabled = get_config('system', 'disable_diaspora_discover_tab');
    }
    $sys = $sys_disabled ? null : get_sys_channel();
    if (App::$data['salmon_test']) {
        $xml = file_get_contents('test.xml');
        App::$argv[1] = 'gnusoc';
    } else {
        $xml = file_get_contents('php://input');
    }
    logger('mod-salmon: new salmon ' . $xml, LOGGER_DATA);
    $nick = argc() > 1 ? trim(argv(1)) : '';
    //	$mentions   = ((App::$argc > 2 && App::$argv[2] === 'mention') ? true : false);
    $importer = channelx_by_nick($nick);
    if (!$importer) {
        http_status_exit(500);
    }
    // @fixme check that this channel has the GNU-Social protocol enabled
    // parse the xml
    $dom = simplexml_load_string($xml, 'SimpleXMLElement', 0, NAMESPACE_SALMON_ME);
    // figure out where in the DOM tree our data is hiding
    if ($dom->provenance->data) {
        $base = $dom->provenance;
    } elseif ($dom->env->data) {
        $base = $dom->env;
    } elseif ($dom->data) {
        $base = $dom;
    }
    if (!$base) {
        logger('mod-salmon: unable to locate salmon data in xml ');
        http_status_exit(400);
    }
    logger('data: ' . $xml, LOGGER_DATA);
    // Stash the signature away for now. We have to find their key or it won't be good for anything.
    logger('sig: ' . $base->sig);
    $signature = base64url_decode($base->sig);
    logger('sig: ' . $base->sig . ' decoded length: ' . strlen($signature));
    // unpack the  data
    // strip whitespace so our data element will return to one big base64 blob
    $data = str_replace(array(" ", "\t", "\r", "\n"), array("", "", "", ""), $base->data);
    // stash away some other stuff for later
    $type = $base->data[0]->attributes()->type[0];
    $keyhash = $base->sig[0]->attributes()->keyhash[0];
    $encoding = $base->encoding;
    $alg = $base->alg;
    // Salmon magic signatures have evolved and there is no way of knowing ahead of time which
    // flavour we have. We'll try and verify it regardless.
    $stnet_signed_data = $data;
    $signed_data = $data . '.' . base64url_encode($type, false) . '.' . base64url_encode($encoding, false) . '.' . base64url_encode($alg, false);
    $compliant_format = str_replace('=', '', $signed_data);
    // decode the data
    $data = base64url_decode($data);
    logger('decoded: ' . $data, LOGGER_DATA);
    // GNU-Social doesn't send a legal Atom feed over salmon, only an Atom entry. Unfortunately
    // our parser is a bit strict about compliance so we'll insert just enough of a feed
    // tag to trick it into believing it's a compliant feed.
    if (!strstr($data, '<feed')) {
        $data = str_replace('<entry ', '<feed xmlns="http://www.w3.org/2005/Atom"><entry ', $data);
        $data .= '</feed>';
    }
    $datarray = process_salmon_feed($data, $importer);
    $author_link = $datarray['author']['author_link'];
    $item = $datarray['item'];
    if (!$author_link) {
        logger('mod-salmon: Could not retrieve author URI.');
        http_status_exit(400);
    }
    $r = q("select xchan_pubkey from xchan where xchan_guid = '%s' limit 1", dbesc($author_link));
    if ($r) {
        $pubkey = $r[0]['xchan_pubkey'];
    } else {
        // Once we have the author URI, go to the web and try to find their public key
        logger('mod-salmon: Fetching key for ' . $author_link);
        $pubkey = get_salmon_key($author_link, $keyhash);
        if (!$pubkey) {
            logger('mod-salmon: Could not retrieve author key.');
            http_status_exit(400);
        }
        logger('mod-salmon: key details: ' . print_r($pubkey, true), LOGGER_DEBUG);
    }
    $pubkey = rtrim($pubkey);
    // We should have everything we need now. Let's see if it verifies.
    $verify = rsa_verify($signed_data, $signature, $pubkey);
    if (!$verify) {
        logger('mod-salmon: message did not verify using protocol. Trying padding hack.');
        $verify = rsa_verify($compliant_format, $signature, $pubkey);
    }
    if (!$verify) {
        logger('mod-salmon: message did not verify using padding. Trying old statusnet hack.');
        $verify = rsa_verify($stnet_signed_data, $signature, $pubkey);
    }
    if (!$verify) {
        logger('mod-salmon: Message did not verify. Discarding.');
        http_status_exit(400);
    }
    logger('mod-salmon: Message verified.');
    /* lookup the author */
    if (!$datarray['author']['author_link']) {
        logger('unable to probe - no author identifier');
        http_status_exit(400);
    }
    $r = q("select * from xchan where xchan_guid = '%s' limit 1", dbesc($datarray['author']['author_link']));
    if (!$r) {
        if (discover_by_webbie($datarray['author']['author_link'])) {
            $r = q("select * from xchan where xchan_guid = '%s' limit 1", dbesc($datarray['author']['author_link']));
            if (!$r) {
                logger('discovery failed');
                http_status_exit(400);
            }
        }
    }
    $xchan = $r[0];
    /*
     *
     * If we reached this point, the message is good. Now let's figure out if the author is allowed to send us stuff.
     *
     */
    // First check for and process follow activity
    if (activity_match($item['verb'], ACTIVITY_FOLLOW) && $item['obj_type'] === ACTIVITY_OBJ_PERSON) {
        $cb = array('item' => $item, 'channel' => $importer, 'xchan' => $xchan, 'author' => $datarray['author'], 'caught' => false);
        call_hooks('follow_from_feed', $cb);
        if ($cb['caught']) {
            http_status_exit(200);
        }
    }
    $m = parse_url($xchan['xchan_url']);
    if ($m) {
        $host = $m['scheme'] . '://' . $m['host'];
        q("update site set site_dead = 0, site_update = '%s' where site_type = %d and site_url = '%s'", dbesc(datetime_convert()), intval(SITE_TYPE_NOTZOT), dbesc($url));
        if (!check_siteallowed($host)) {
            logger('blacklisted site: ' . $host);
            http_status_exit(403, 'permission denied.');
        }
    }
    $importer_arr = array($importer);
    if (!$sys_disabled) {
        $sys['system'] = true;
        $importer_arr[] = $sys;
    }
    unset($datarray['author']);
    // we will only set and return the status code for operations
    // on an importer channel and not for the sys channel
    $status = 200;
    foreach ($importer_arr as $importer) {
        if (!$importer['system']) {
            $allowed = get_pconfig($importer['channel_id'], 'system', 'gnusoc_allowed');
            if (!intval($allowed)) {
                logger('mod-salmon: disallowed for channel ' . $importer['channel_name']);
                $status = 202;
                continue;
            }
        }
        // Otherwise check general permissions
        if (!perm_is_allowed($importer['channel_id'], $xchan['xchan_hash'], 'send_stream') && !$importer['system']) {
            // check for and process ostatus autofriend
            // ... fixme
            // otherwise
            logger('mod-salmon: Ignoring this author.');
            $status = 202;
            continue;
        }
        $parent_item = null;
        if ($item['parent_mid']) {
            $r = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc($item['parent_mid']), intval($importer['channel_id']));
            if (!$r) {
                logger('mod-salmon: parent item not found.');
                if (!$importer['system']) {
                    $status = 202;
                }
                continue;
            }
            $parent_item = $r[0];
        }
        if (!$item['author_xchan']) {
            $item['author_xchan'] = $xchan['xchan_hash'];
        }
        $item['owner_xchan'] = $parent_item ? $parent_item['owner_xchan'] : $xchan['xchan_hash'];
        $r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1", dbesc($item['mid']), intval($importer['channel_id']));
        // Update content if 'updated' changes
        // currently a no-op @fixme
        if ($r) {
            if (x($item, 'edited') !== false && datetime_convert('UTC', 'UTC', $item['edited']) !== $r[0]['edited']) {
                // do not accept (ignore) an earlier edit than one we currently have.
                if (datetime_convert('UTC', 'UTC', $item['edited']) > $r[0]['edited']) {
                    update_feed_item($importer['channel_id'], $item);
                }
            }
            if (!$importer['system']) {
                $status = 200;
            }
            continue;
        }
        if (!$item['parent_mid']) {
            $item['parent_mid'] = $item['mid'];
        }
        $item['aid'] = $importer['channel_account_id'];
        $item['uid'] = $importer['channel_id'];
        logger('consume_feed: ' . print_r($item, true), LOGGER_DATA);
        $xx = item_store($item);
        $r = $xx['item_id'];
        if (!$importer['system']) {
            $status = 200;
        }
        continue;
    }
    http_status_exit($status);
}