示例#1
0
function push_notifier_process(&$a, &$b)
{
    logger('push_notifier_process');
    if (!$b['normal_mode']) {
        return;
    }
    if ($b['private'] || $b['packet_type'] !== 'undefined' || $b['mail']) {
        return;
    }
    if (!$b['top_level_post']) {
        return;
    }
    // find push_subscribers following this $owner
    $channel = $b['channel'];
    // allow subscriptions either by http or https, as gnu-social has been known to subscribe
    // to the wrong one.
    $r = q("select * from push_subscriber where topic like '%s'", dbesc('%://' . App::get_hostname() . '/feed/' . $channel['channel_address']));
    if (!$r) {
        return;
    }
    foreach ($r as $rr) {
        $feed = get_feed_for($channel, '', array('begin' => $rr['last_update']));
        $hmac_sig = hash_hmac("sha1", $feed, $rr['secret']);
        $slap = array('sig' => $hmac_sig, 'topic' => $rr['topic'], 'body' => $feed);
        // Check for public post and create atom wrapper and stick in queue
        // also need queue driver for 'push' since we need to set some extra headers
        $hash = random_string();
        queue_insert(array('hash' => $hash, 'account_id' => $channel['channel_account_id'], 'channel_id' => $channel['channel_id'], 'driver' => 'push', 'posturl' => $rr['callback_url'], 'notify' => '', 'msg' => json_encode($slap)));
        $b['queued'][] = $hash;
    }
}
示例#2
0
/**
 * @brief
 *
 * @param array $argv
 * @param array $argc
 */
function directory_run($argv, $argc)
{
    cli_startup();
    if ($argc < 2) {
        return;
    }
    $force = false;
    $pushall = true;
    if ($argc > 2) {
        if ($argv[2] === 'force') {
            $force = true;
        }
        if ($argv[2] === 'nopush') {
            $pushall = false;
        }
    }
    logger('directory update', LOGGER_DEBUG);
    $dirmode = get_config('system', 'directory_mode');
    if ($dirmode === false) {
        $dirmode = DIRECTORY_MODE_NORMAL;
    }
    $x = q("select * from channel where channel_id = %d limit 1", intval($argv[1]));
    if (!$x) {
        return;
    }
    $channel = $x[0];
    if ($dirmode != DIRECTORY_MODE_NORMAL) {
        // this is an in-memory update and we don't need to send a network packet.
        local_dir_update($argv[1], $force);
        q("update channel set channel_dirdate = '%s' where channel_id = %d", dbesc(datetime_convert()), intval($channel['channel_id']));
        // Now update all the connections
        if ($pushall) {
            proc_run('php', 'include/notifier.php', 'refresh_all', $channel['channel_id']);
        }
        return;
    }
    // otherwise send the changes upstream
    $directory = find_upstream_directory($dirmode);
    $url = $directory['url'] . '/post';
    // ensure the upstream directory is updated
    $packet = zot_build_packet($channel, $force ? 'force_refresh' : 'refresh');
    $z = zot_zot($url, $packet);
    // re-queue if unsuccessful
    if (!$z['success']) {
        /** @FIXME we aren't updating channel_dirdate if we have to queue
         * the directory packet. That means we'll try again on the next poll run.
         */
        $hash = random_string();
        queue_insert(array('hash' => $hash, 'account_id' => $channel['channel_account_id'], 'channel_id' => $channel['channel_id'], 'posturl' => $url, 'notify' => $packet));
    } else {
        q("update channel set channel_dirdate = '%s' where channel_id = %d", dbesc(datetime_convert()), intval($channel['channel_id']));
    }
    // Now update all the connections
    if ($pushall) {
        proc_run('php', 'include/notifier.php', 'refresh_all', $channel['channel_id']);
    }
}
示例#3
0
function slapper($owner, $url, $slap)
{
    // does contact have a salmon endpoint?
    if (!strlen($url)) {
        return;
    }
    if (!$owner['channel_prvkey']) {
        logger(sprintf("channel '%s' (%d) does not have a salmon private key. Send failed.", $owner['channel_address'], $owner['channel_id']));
        return;
    }
    logger('slapper called for ' . $url . '. Data: ' . $slap, LOGGER_DATA, LOG_DEBUG);
    // create a magic envelope
    $data = base64url_encode($slap, false);
    // do not strip padding
    $data_type = 'application/atom+xml';
    $encoding = 'base64url';
    $algorithm = 'RSA-SHA256';
    $keyhash = base64url_encode(hash('sha256', salmon_key($owner['channel_pubkey'])), true);
    $data = str_replace(array(" ", "\t", "\r", "\n"), array("", "", "", ""), $data);
    // precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods
    $precomputed = '.YXBwbGljYXRpb24vYXRvbSt4bWw=.YmFzZTY0dXJs.UlNBLVNIQTI1Ng==';
    $signature = base64url_encode(rsa_sign($data . $precomputed, $owner['channel_prvkey']));
    $salmon_tpl = get_markup_template('magicsig.tpl', 'addon/gnusoc/');
    $salmon = replace_macros($salmon_tpl, array('$data' => $data, '$encoding' => $encoding, '$algorithm' => $algorithm, '$keyhash' => $keyhash, '$signature' => $signature));
    logger('salmon: ' . $salmon, LOGGER_DATA);
    $hash = random_string();
    queue_insert(array('hash' => $hash, 'account_id' => $owner['channel_account_id'], 'channel_id' => $owner['channel_id'], 'driver' => 'slap', 'posturl' => $url, 'notify' => '', 'msg' => $salmon));
    return $hash;
}
示例#4
0
function diaspora_queue($owner, $contact, $slap, $public_batch, $message_id = '')
{
    $allowed = get_pconfig($owner['channel_id'], 'system', 'diaspora_allowed');
    if ($allowed === false) {
        $allowed = 1;
    }
    if (!intval($allowed)) {
        return false;
    }
    if ($public_batch) {
        $dest_url = $contact['hubloc_callback'] . '/public';
    } else {
        $dest_url = $contact['hubloc_callback'] . '/users/' . $contact['hubloc_guid'];
    }
    logger('diaspora_queue: URL: ' . $dest_url, LOGGER_DEBUG);
    if (intval(get_config('system', 'diaspora_test')) || intval(get_pconfig($owner['channel_id'], 'system', 'diaspora_test'))) {
        return false;
    }
    $a = get_app();
    $hash = random_string();
    logger('diaspora_queue: ' . $hash . ' ' . $dest_url, LOGGER_DEBUG);
    queue_insert(array('hash' => $hash, 'account_id' => $owner['channel_account_id'], 'channel_id' => $owner['channel_id'], 'driver' => 'post', 'posturl' => $dest_url, 'notify' => '', 'msg' => $slap));
    if ($message_id && !get_config('system', 'disable_dreport')) {
        q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan, dreport_queue ) values ( '%s','%s','%s','%s','%s','%s','%s' ) ", dbesc($message_id), dbesc($dest_url), dbesc($dest_url), dbesc('queued'), dbesc(datetime_convert()), dbesc($owner['channel_hash']), dbesc($hash));
    }
    return $hash;
}
示例#5
0
function notifier_run($argv, $argc)
{
    cli_startup();
    $a = get_app();
    if ($argc < 3) {
        return;
    }
    logger('notifier: invoked: ' . print_r($argv, true), LOGGER_DEBUG);
    $cmd = $argv[1];
    $item_id = $argv[2];
    $extra = $argc > 3 ? $argv[3] : null;
    if (!$item_id) {
        return;
    }
    $sys = get_sys_channel();
    $deliveries = array();
    $dead_hubs = array();
    $dh = q("select site_url from site where site_dead = 1");
    if ($dh) {
        foreach ($dh as $dead) {
            $dead_hubs[] = $dead['site_url'];
        }
    }
    $request = false;
    $mail = false;
    $top_level = false;
    $location = false;
    $recipients = array();
    $url_recipients = array();
    $normal_mode = true;
    $packet_type = 'undefined';
    if ($cmd === 'mail') {
        $normal_mode = false;
        $mail = true;
        $private = true;
        $message = q("SELECT * FROM `mail` WHERE `id` = %d LIMIT 1", intval($item_id));
        if (!$message) {
            return;
        }
        xchan_mail_query($message[0]);
        $uid = $message[0]['channel_id'];
        $recipients[] = $message[0]['from_xchan'];
        // include clones
        $recipients[] = $message[0]['to_xchan'];
        $item = $message[0];
        $encoded_item = encode_mail($item);
        $s = q("select * from channel where channel_id = %d limit 1", intval($item['channel_id']));
        if ($s) {
            $channel = $s[0];
        }
    } elseif ($cmd === 'request') {
        $channel_id = $item_id;
        $xchan = $argv[3];
        $request_message_id = $argv[4];
        $s = q("select * from channel where channel_id = %d limit 1", intval($channel_id));
        if ($s) {
            $channel = $s[0];
        }
        $private = true;
        $recipients[] = $xchan;
        $packet_type = 'request';
        $normal_mode = false;
    } elseif ($cmd == 'permission_update' || $cmd == 'permission_create') {
        // Get the (single) recipient
        $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_self = 0", intval($item_id));
        if ($r) {
            $uid = $r[0]['abook_channel'];
            // Get the sender
            $channel = channelx_by_n($uid);
            if ($channel) {
                $perm_update = array('sender' => $channel, 'recipient' => $r[0], 'success' => false, 'deliveries' => '');
                if ($cmd == 'permission_create') {
                    call_hooks('permissions_create', $perm_update);
                } else {
                    call_hooks('permissions_update', $perm_update);
                }
                if ($perm_update['success']) {
                    if ($perm_update['deliveries']) {
                        $deliveries[] = $perm_update['deliveries'];
                        do_delivery($deliveries);
                    }
                    return;
                } else {
                    $recipients[] = $r[0]['abook_xchan'];
                    $private = false;
                    $packet_type = 'refresh';
                    $packet_recips = array(array('guid' => $r[0]['xchan_guid'], 'guid_sig' => $r[0]['xchan_guid_sig'], 'hash' => $r[0]['xchan_hash']));
                }
            }
        }
    } elseif ($cmd === 'refresh_all') {
        logger('notifier: refresh_all: ' . $item_id);
        $uid = $item_id;
        $channel = channelx_by_n($item_id);
        $r = q("select abook_xchan from abook where abook_channel = %d", intval($item_id));
        if ($r) {
            foreach ($r as $rr) {
                $recipients[] = $rr['abook_xchan'];
            }
        }
        $private = false;
        $packet_type = 'refresh';
    } elseif ($cmd === 'location') {
        logger('notifier: location: ' . $item_id);
        $s = q("select * from channel where channel_id = %d limit 1", intval($item_id));
        if ($s) {
            $channel = $s[0];
        }
        $uid = $item_id;
        $recipients = array();
        $r = q("select abook_xchan from abook where abook_channel = %d", intval($item_id));
        if ($r) {
            foreach ($r as $rr) {
                $recipients[] = $rr['abook_xchan'];
            }
        }
        $encoded_item = array('locations' => zot_encode_locations($channel), 'type' => 'location', 'encoding' => 'zot');
        $target_item = array('aid' => $channel['channel_account_id'], 'uid' => $channel['channel_id']);
        $private = false;
        $packet_type = 'location';
        $location = true;
    } elseif ($cmd === 'purge_all') {
        logger('notifier: purge_all: ' . $item_id);
        $s = q("select * from channel where channel_id = %d limit 1", intval($item_id));
        if ($s) {
            $channel = $s[0];
        }
        $uid = $item_id;
        $recipients = array();
        $r = q("select abook_xchan from abook where abook_channel = %d", intval($item_id));
        if ($r) {
            foreach ($r as $rr) {
                $recipients[] = $rr['abook_xchan'];
            }
        }
        $private = false;
        $packet_type = 'purge';
    } else {
        // Normal items
        // Fetch the target item
        $r = q("SELECT * FROM item WHERE id = %d and parent != 0 LIMIT 1", intval($item_id));
        if (!$r) {
            return;
        }
        xchan_query($r);
        $r = fetch_post_tags($r);
        $target_item = $r[0];
        $deleted_item = false;
        if (intval($target_item['item_deleted'])) {
            logger('notifier: target item ITEM_DELETED', LOGGER_DEBUG);
            $deleted_item = true;
        }
        if (intval($target_item['item_type']) != ITEM_TYPE_POST) {
            logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
            return;
        }
        if (intval($target_item['item_unpublished']) || intval($target_item['item_delayed'])) {
            logger('notifier: target item not published, so not forwardable', LOGGER_DEBUG);
            return;
        }
        if (strpos($target_item['postopts'], 'nodeliver') !== false) {
            logger('notifier: target item is undeliverable', LOGGER_DEBUG);
            return;
        }
        $s = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1", intval($target_item['uid']));
        if ($s) {
            $channel = $s[0];
        }
        if ($channel['channel_hash'] !== $target_item['author_xchan'] && $channel['channel_hash'] !== $target_item['owner_xchan']) {
            logger("notifier: Sending channel {$channel['channel_hash']} is not owner {$target_item['owner_xchan']} or author {$target_item['author_xchan']}", LOGGER_NORMAL, LOG_WARNING);
            return;
        }
        if ($target_item['id'] == $target_item['parent']) {
            $parent_item = $target_item;
            $top_level_post = true;
        } else {
            // fetch the parent item
            $r = q("SELECT * from item where id = %d order by id asc", intval($target_item['parent']));
            if (!$r) {
                return;
            }
            if (strpos($r[0]['postopts'], 'nodeliver') !== false) {
                logger('notifier: target item is undeliverable', LOGGER_DEBUG, LOG_NOTICE);
                return;
            }
            xchan_query($r);
            $r = fetch_post_tags($r);
            $parent_item = $r[0];
            $top_level_post = false;
        }
        // avoid looping of discover items 12/4/2014
        if ($sys && $parent_item['uid'] == $sys['channel_id']) {
            return;
        }
        $encoded_item = encode_item($target_item);
        // Send comments to the owner to re-deliver to everybody in the conversation
        // We only do this if the item in question originated on this site. This prevents looping.
        // To clarify, a site accepting a new comment is responsible for sending it to the owner for relay.
        // Relaying should never be initiated on a post that arrived from elsewhere.
        // We should normally be able to rely on ITEM_ORIGIN, but start_delivery_chain() incorrectly set this
        // flag on comments for an extended period. So we'll also call comment_local_origin() which looks at
        // the hostname in the message_id and provides a second (fallback) opinion.
        $relay_to_owner = !$top_level_post && intval($target_item['item_origin']) && comment_local_origin($target_item) ? true : false;
        $uplink = false;
        // $cmd === 'relay' indicates the owner is sending it to the original recipients
        // don't allow the item in the relay command to relay to owner under any circumstances, it will loop
        logger('notifier: relay_to_owner: ' . ($relay_to_owner ? 'true' : 'false'), LOGGER_DATA, LOG_DEBUG);
        logger('notifier: top_level_post: ' . ($top_level_post ? 'true' : 'false'), LOGGER_DATA, LOG_DEBUG);
        // tag_deliver'd post which needs to be sent back to the original author
        if ($cmd === 'uplink' && intval($parent_item['item_uplink']) && !$top_level_post) {
            logger('notifier: uplink');
            $uplink = true;
        }
        if (($relay_to_owner || $uplink) && $cmd !== 'relay') {
            logger('notifier: followup relay', LOGGER_DEBUG);
            $recipients = array($uplink ? $parent_item['source_xchan'] : $parent_item['owner_xchan']);
            $private = true;
            if (!$encoded_item['flags']) {
                $encoded_item['flags'] = array();
            }
            $encoded_item['flags'][] = 'relay';
        } else {
            logger('notifier: normal distribution', LOGGER_DEBUG);
            if ($cmd === 'relay') {
                logger('notifier: owner relay');
            }
            // if our parent is a tag_delivery recipient, uplink to the original author causing
            // a delivery fork.
            if ($parent_item && intval($parent_item['item_uplink']) && !$top_level_post && $cmd !== 'uplink') {
                // don't uplink a relayed post to the relay owner
                if ($parent_item['source_xchan'] !== $parent_item['owner_xchan']) {
                    logger('notifier: uplinking this item');
                    proc_run('php', 'include/notifier.php', 'uplink', $item_id);
                }
            }
            $private = false;
            $recipients = collect_recipients($parent_item, $private);
            // FIXME add any additional recipients such as mentions, etc.
            // don't send deletions onward for other people's stuff
            // TODO verify this is needed - copied logic from same place in old code
            if (intval($target_item['item_deleted']) && !intval($target_item['item_wall'])) {
                logger('notifier: ignoring delete notification for non-wall item', LOGGER_NORMAL, LOG_NOTICE);
                return;
            }
        }
    }
    $walltowall = $top_level_post && $channel['xchan_hash'] === $target_item['author_xchan'] ? true : false;
    // Generic delivery section, we have an encoded item and recipients
    // Now start the delivery process
    $x = $encoded_item;
    $x['title'] = 'private';
    $x['body'] = 'private';
    logger('notifier: encoded item: ' . print_r($x, true), LOGGER_DATA, LOG_DEBUG);
    stringify_array_elms($recipients);
    if (!$recipients) {
        return;
    }
    //	logger('notifier: recipients: ' . print_r($recipients,true), LOGGER_NORMAL, LOG_DEBUG);
    $env_recips = $private ? array() : null;
    $details = q("select xchan_hash, xchan_instance_url, xchan_network, xchan_addr, xchan_guid, xchan_guid_sig from xchan where xchan_hash in (" . implode(',', $recipients) . ")");
    $recip_list = array();
    if ($details) {
        foreach ($details as $d) {
            $recip_list[] = $d['xchan_addr'] . ' (' . $d['xchan_hash'] . ')';
            if ($private) {
                $env_recips[] = array('guid' => $d['xchan_guid'], 'guid_sig' => $d['xchan_guid_sig'], 'hash' => $d['xchan_hash']);
            }
            if ($d['xchan_network'] === 'mail' && $normal_mode) {
                $delivery_options = get_xconfig($d['xchan_hash'], 'system', 'delivery_mode');
                if (!$delivery_options) {
                    format_and_send_email($channel, $d, $target_item);
                }
            }
        }
    }
    $narr = array('channel' => $channel, 'env_recips' => $env_recips, 'packet_recips' => $packet_recips, 'recipients' => $recipients, 'item' => $item, 'target_item' => $target_item, 'top_level_post' => $top_level_post, 'private' => $private, 'followup' => $followup, 'relay_to_owner' => $relay_to_owner, 'uplink' => $uplink, 'cmd' => $cmd, 'mail' => $mail, 'location' => $location, 'request' => $request, 'normal_mode' => $normal_mode, 'packet_type' => $packet_type, 'walltowall' => $walltowall, 'queued' => array());
    call_hooks('notifier_process', $narr);
    if ($narr['queued']) {
        foreach ($narr['queued'] as $pq) {
            $deliveries[] = $pq;
        }
    }
    if ($private && !$env_recips) {
        // shouldn't happen
        logger('notifier: private message with no envelope recipients.' . print_r($argv, true), LOGGER_NORMAL, LOG_NOTICE);
    }
    logger('notifier: recipients (may be delivered to more if public): ' . print_r($recip_list, true), LOGGER_DEBUG);
    // Now we have collected recipients (except for external mentions, FIXME)
    // Let's reduce this to a set of hubs.
    $r = q("select * from hubloc where hubloc_hash in (" . implode(',', $recipients) . ") \n\t\tand hubloc_error = 0 and hubloc_deleted = 0");
    if (!$r) {
        logger('notifier: no hubs', LOGGER_NORMAL, LOG_NOTICE);
        return;
    }
    $hubs = $r;
    /**
     * Reduce the hubs to those that are unique. For zot hubs, we need to verify uniqueness by the sitekey, since it may have been 
     * a re-install which has not yet been detected and pruned.
     * For other networks which don't have or require sitekeys, we'll have to use the URL
     */
    $hublist = array();
    // this provides an easily printable list for the logs
    $dhubs = array();
    // delivery hubs where we store our resulting unique array
    $keys = array();
    // array of keys to check uniquness for zot hubs
    $urls = array();
    // array of urls to check uniqueness of hubs from other networks
    foreach ($hubs as $hub) {
        if (in_array($hub['hubloc_url'], $dead_hubs)) {
            logger('skipping dead hub: ' . $hub['hubloc_url'], LOGGER_DEBUG, LOG_INFO);
            continue;
        }
        if ($hub['hubloc_network'] == 'zot') {
            if (!in_array($hub['hubloc_sitekey'], $keys)) {
                $hublist[] = $hub['hubloc_host'];
                $dhubs[] = $hub;
                $keys[] = $hub['hubloc_sitekey'];
            }
        } else {
            if (!in_array($hub['hubloc_url'], $urls)) {
                $hublist[] = $hub['hubloc_host'];
                $dhubs[] = $hub;
                $urls[] = $hub['hubloc_url'];
            }
        }
    }
    logger('notifier: will notify/deliver to these hubs: ' . print_r($hublist, true), LOGGER_DEBUG, LOG_DEBUG);
    foreach ($dhubs as $hub) {
        if ($hub['hubloc_network'] !== 'zot') {
            $narr = array('channel' => $channel, 'env_recips' => $env_recips, 'packet_recips' => $packet_recips, 'recipients' => $recipients, 'item' => $item, 'target_item' => $target_item, 'hub' => $hub, 'top_level_post' => $top_level_post, 'private' => $private, 'followup' => $followup, 'relay_to_owner' => $relay_to_owner, 'uplink' => $uplink, 'cmd' => $cmd, 'mail' => $mail, 'location' => $location, 'request' => $request, 'normal_mode' => $normal_mode, 'packet_type' => $packet_type, 'walltowall' => $walltowall, 'queued' => array());
            call_hooks('notifier_hub', $narr);
            if ($narr['queued']) {
                foreach ($narr['queued'] as $pq) {
                    $deliveries[] = $pq;
                }
            }
            continue;
        }
        // default: zot protocol
        $hash = random_string();
        $packet = null;
        if ($packet_type === 'refresh' || $packet_type === 'purge') {
            $packet = zot_build_packet($channel, $packet_type, $packet_recips ? $packet_recips : null);
        } elseif ($packet_type === 'request') {
            $packet = zot_build_packet($channel, $packet_type, $env_recips, $hub['hubloc_sitekey'], $hash, array('message_id' => $request_message_id));
        }
        if ($packet) {
            queue_insert(array('hash' => $hash, 'account_id' => $channel['channel_account_id'], 'channel_id' => $channel['channel_id'], 'posturl' => $hub['hubloc_callback'], 'notify' => $packet));
        } else {
            $packet = zot_build_packet($channel, 'notify', $env_recips, $private ? $hub['hubloc_sitekey'] : null, $hash);
            queue_insert(array('hash' => $hash, 'account_id' => $target_item['aid'], 'channel_id' => $target_item['uid'], 'posturl' => $hub['hubloc_callback'], 'notify' => $packet, 'msg' => json_encode($encoded_item)));
            // only create delivery reports for normal undeleted items
            if (is_array($target_item) && array_key_exists('postopts', $target_item) && !$target_item['item_deleted'] && !get_config('system', 'disable_dreport')) {
                q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan, dreport_queue ) values ( '%s','%s','%s','%s','%s','%s','%s' ) ", dbesc($target_item['mid']), dbesc($hub['hubloc_host']), dbesc($hub['hubloc_host']), dbesc('queued'), dbesc(datetime_convert()), dbesc($channel['channel_hash']), dbesc($hash));
            }
        }
        $deliveries[] = $hash;
    }
    if ($normal_mode) {
        $x = q("select * from hook where hook = 'notifier_normal'");
        if ($x) {
            proc_run('php', 'include/deliver_hooks.php', $target_item['id']);
        }
    }
    if ($deliveries) {
        do_delivery($deliveries);
    }
    logger('notifier: basic loop complete.', LOGGER_DEBUG);
    call_hooks('notifier_end', $target_item);
    logger('notifer: complete.');
    return;
}
示例#6
0
/**
 * @brief Process a message request.
 *
 * If a site receives a comment to a post but finds they have no parent to attach it with, they
 * may send a 'request' packet containing the message_id of the missing parent. This is the handler
 * for that packet. We will create a message_list array of the entire conversation starting with
 * the missing parent and invoke delivery to the sender of the packet.
 *
 * include/deliver.php (for local delivery) and mod/post.php (for web delivery) detect the existence of
 * this 'message_list' at the destination and split it into individual messages which are
 * processed/delivered in order.
 *
 * Called from mod/post.php
 *
 * @param array $data
 * @return array
 */
function zot_reply_message_request($data)
{
    $ret = array('success' => false);
    if (!$data['message_id']) {
        $ret['message'] = 'no message_id';
        logger('no message_id');
        json_return_and_die($ret);
    }
    $sender = $data['sender'];
    $sender_hash = make_xchan_hash($sender['guid'], $sender['guid_sig']);
    /*
     * Find the local channel in charge of this post (the first and only recipient of the request packet)
     */
    $arr = $data['recipients'][0];
    $recip_hash = make_xchan_hash($arr['guid'], $arr['guid_sig']);
    $c = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_hash = '%s' limit 1", dbesc($recip_hash));
    if (!$c) {
        logger('recipient channel not found.');
        $ret['message'] .= 'recipient not found.' . EOL;
        json_return_and_die($ret);
    }
    /*
     * fetch the requested conversation
     */
    $messages = zot_feed($c[0]['channel_id'], $sender_hash, array('message_id' => $data['message_id']));
    if ($messages) {
        $env_recips = null;
        $r = q("select * from hubloc where hubloc_hash = '%s' and hubloc_error = 0 and hubloc_deleted = 0 \n\t\t\tgroup by hubloc_sitekey", dbesc($sender_hash));
        if (!$r) {
            logger('no hubs');
            json_return_and_die($ret);
        }
        $hubs = $r;
        $private = array_key_exists('flags', $messages[0]) && in_array('private', $messages[0]['flags']) ? true : false;
        if ($private) {
            $env_recips = array('guid' => $sender['guid'], 'guid_sig' => $sender['guid_sig'], 'hash' => $sender_hash);
        }
        $data_packet = json_encode(array('message_list' => $messages));
        foreach ($hubs as $hub) {
            $hash = random_string();
            /*
             * create a notify packet and drop the actual message packet in the queue for pickup
             */
            $n = zot_build_packet($c[0], 'notify', $env_recips, $private ? $hub['hubloc_sitekey'] : null, $hash, array('message_id' => $data['message_id']));
            queue_insert(array('hash' => $hash, 'account_id' => $c[0]['channel_account_id'], 'channel_id' => $c[0]['channel_id'], 'posturl' => $hub['hubloc_callback'], 'notify' => $n, 'msg' => $data_packet));
            /*
             * invoke delivery to send out the notify packet
             */
            proc_run('php', 'include/deliver.php', $hash);
        }
    }
    $ret['success'] = true;
    json_return_and_die($ret);
}
示例#7
0
function statusnet_post_hook(&$a, &$b)
{
    /**
     * Post to statusnet
     */
    if (!strstr($b['postopts'], 'statusnet')) {
        logger('crosspost not enabled.');
        return;
    }
    if (!is_item_normal($b) || $b['item_private'] || $b['created'] !== $b['edited']) {
        logger('not a usable post. ' . print_r($b, true), LOGGER_DEBUG);
        return;
    }
    if (!perm_is_allowed($b['uid'], '', 'view_stream')) {
        logger('permissions prevent crossposting.', LOGGER_DEBUG);
        return;
    }
    if ($b['parent'] != $b['id']) {
        logger('not a top level post.', LOGGER_DEBUG);
        return;
    }
    // if posts comes from statusnet don't send it back
    if ($b['app'] == "StatusNet") {
        logger('potential recursion. Crosspost ignored.');
        return;
    }
    logger('statusnet post invoked');
    load_pconfig($b['uid'], 'statusnet');
    $api = get_pconfig($b['uid'], 'statusnet', 'baseapi');
    $ckey = get_pconfig($b['uid'], 'statusnet', 'consumerkey');
    $csecret = get_pconfig($b['uid'], 'statusnet', 'consumersecret');
    $otoken = get_pconfig($b['uid'], 'statusnet', 'oauthtoken');
    $osecret = get_pconfig($b['uid'], 'statusnet', 'oauthsecret');
    $intelligent_shortening = get_pconfig($b['uid'], 'statusnet', 'intelligent_shortening');
    // Global setting overrides this
    if (get_config('statusnet', 'intelligent_shortening')) {
        $intelligent_shortening = get_config('statusnet', 'intelligent_shortening');
    }
    if ($ckey && $csecret && $otoken && $osecret) {
        require_once 'include/bbcode.php';
        $dent = new StatusNetOAuth($api, $ckey, $csecret, $otoken, $osecret);
        $max_char = $dent->get_maxlength();
        // max. length for a dent
        // we will only work with up to two times the length of the dent
        // we can later send to GNU social. This way we can "gain" some
        // information during shortening of potential links but do not
        // shorten all the links in a 200000 character long essay.
        $tempfile = "";
        $intelligent_shortening = get_config('statusnet', 'intelligent_shortening');
        if (!$intelligent_shortening) {
            if (!$b['title'] == '') {
                $tmp = $b['title'] . ": \n" . $b['body'];
                //					$tmp = substr($tmp, 0, 4*$max_char);
            } else {
                $tmp = $b['body'];
                // substr($b['body'], 0, 3*$max_char);
            }
            // if [url=bla][img]blub.png[/img][/url] get blub.png
            $tmp = preg_replace('/\\[url\\=(https?\\:\\/\\/[a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\\$\\!\\+\\,]+)\\]\\[img\\](\\w+.*?)\\[\\/img\\]\\[\\/url\\]/i', '$2', $tmp);
            $tmp = preg_replace('/\\[zrl\\=(https?\\:\\/\\/[a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\\$\\!\\+\\,]+)\\]\\[zmg\\](\\w+.*?)\\[\\/zmg\\]\\[\\/zrl\\]/i', '$2', $tmp);
            // preserve links to images, videos and audios
            $tmp = preg_replace('/\\[img\\=([0-9]*)x([0-9]*)\\](.*?)\\[\\/img\\]/ism', '$3', $tmp);
            $tmp = preg_replace('/\\[\\/?img(\\s+.*?\\]|\\])/i', '', $tmp);
            $tmp = preg_replace('/\\[zmg\\=([0-9]*)x([0-9]*)\\](.*?)\\[\\/zmg\\]/ism', '$3', $tmp);
            $tmp = preg_replace('/\\[\\/?zmg(\\s+.*?\\]|\\])/i', '', $tmp);
            $tmp = preg_replace('/\\[\\/?video(\\s+.*?\\]|\\])/i', '', $tmp);
            $tmp = preg_replace('/\\[\\/?audio(\\s+.*?\\]|\\])/i', '', $tmp);
            $linksenabled = get_pconfig($b['uid'], 'statusnet', 'post_taglinks');
            // if a #tag is linked, don't send the [url] over to SN
            // that is, don't send if the option is not set in the
            // connector settings
            if ($linksenabled == '0') {
                // #-tags
                $tmp = preg_replace('/#\\[url\\=(\\w+.*?)\\](\\w+.*?)\\[\\/url\\]/i', '#$2', $tmp);
                // @-mentions
                $tmp = preg_replace('/@\\[url\\=(\\w+.*?)\\](\\w+.*?)\\[\\/url\\]/i', '@$2', $tmp);
                // #-tags
                $tmp = preg_replace('/#\\[zrl\\=(\\w+.*?)\\](\\w+.*?)\\[\\/zrl\\]/i', '#$2', $tmp);
                // @-mentions
                $tmp = preg_replace('/@\\[zrl\\=(\\w+.*?)\\](\\w+.*?)\\[\\/zrl\\]/i', '@$2', $tmp);
                // recycle 1
                $recycle = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8');
                $tmp = preg_replace('/' . $recycle . '\\[url\\=(\\w+.*?)\\](\\w+.*?)\\[\\/url\\]/i', $recycle . '$2', $tmp);
                // recycle 2 (test)
                $recycle = html_entity_decode("&#x25CC; ", ENT_QUOTES, 'UTF-8');
                $tmp = preg_replace('/' . $recycle . '\\[url\\=(\\w+.*?)\\](\\w+.*?)\\[\\/url\\]/i', $recycle . '$2', $tmp);
            }
            // preserve links to webpages
            $tmp = preg_replace('/\\[url\\=(https?\\:\\/\\/[a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\\$\\!\\+\\,]+)\\](\\w+.*?)\\[\\/url\\]/i', '$2 $1', $tmp);
            $tmp = preg_replace('/\\[zrl\\=(https?\\:\\/\\/[a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\\$\\!\\+\\,]+)\\](\\w+.*?)\\[\\/zrl\\]/i', '$2 $1', $tmp);
            // find all http or https links in the body of the entry and
            // apply the shortener if the link is longer then 20 characters
            if (strlen($tmp) > $max_char && $max_char > 0) {
                preg_match_all('/(https?\\:\\/\\/[a-zA-Z0-9\\:\\/\\-\\?\\&\\;\\.\\=\\_\\~\\#\\%\\$\\!\\+\\,]+)/i', $tmp, $allurls);
                foreach ($allurls as $url) {
                    foreach ($url as $u) {
                        if (strlen($u) > 20) {
                            $sl = short_link($u);
                            $tmp = str_replace($u, $sl, $tmp);
                        }
                    }
                }
            }
            // ok, all the links we want to send out are save, now strip
            // away the remaining bbcode
            $msg = bbcode($tmp, false, false, true);
            $msg = str_replace(array('<br>', '<br />'), "\n", $msg);
            $msg = strip_tags($msg);
            // quotes not working - let's try this
            $msg = html_entity_decode($msg);
            if (strlen($msg) > $max_char && $max_char > 0) {
                $shortlink = short_link($b['plink']);
                // the new message will be shortened such that "... $shortlink"
                // will fit into the character limit
                $msg = nl2br(substr($msg, 0, $max_char - strlen($shortlink) - 4));
                $msg = str_replace(array('<br>', '<br />'), ' ', $msg);
                $e = explode(' ', $msg);
                //  remove the last word from the cut down message to
                //  avoid sending cut words to the MicroBlog
                array_pop($e);
                $msg = implode(' ', $e);
                $msg .= '... ' . $shortlink;
            }
            $msg = trim($msg);
            $postdata = array('status' => $msg);
        } else {
            $msgarr = statusnet_shortenmsg($b, $max_char);
            $msg = $msgarr["msg"];
            $image = $msgarr["image"];
            if ($image != "") {
                $x = z_fetch_url($image, true, 0, array('novalidate' => true));
                if ($x['success']) {
                    $imagedata = $x['body'];
                    $tempfile = tempnam(get_config("system", "temppath"), "upload");
                    file_put_contents($tempfile, $imagedata);
                    $postdata = array("status" => $msg, "media" => "@" . $tempfile);
                }
            } else {
                $postdata = array("status" => $msg);
            }
        }
        // and now dent it :-)
        if (strlen($msg)) {
            $result = $dent->post('statuses/update', $postdata);
            logger('statusnet_post send, result: ' . print_r($result, true) . "\nmessage: " . $msg, LOGGER_DEBUG);
            logger("Original post: " . print_r($b, true) . "\nPost Data: " . print_r($postdata, true), LOGGER_DEBUG);
            if ($result->error) {
                logger('Send to GNU social failed: queued."' . $result->error . '"');
                // @fixme - unable to queue media uploads
                if (!$image) {
                    queue_insert(array('hash' => random_string(), 'account_id' => $b['aid'], 'channel_id' => $b['uid'], 'driver' => 'statusnet', 'posturl' => $api, 'msg' => $msg));
                }
            }
        }
        if ($tempfile != "") {
            unlink($tempfile);
        }
    }
}
示例#8
0
function ratenotif_run($argv, $argc)
{
    cli_startup();
    $a = get_app();
    require_once "session.php";
    require_once "datetime.php";
    require_once 'include/items.php';
    require_once 'include/Contact.php';
    if ($argc < 3) {
        return;
    }
    logger('ratenotif: invoked: ' . print_r($argv, true), LOGGER_DEBUG);
    $cmd = $argv[1];
    $item_id = $argv[2];
    if ($cmd === 'rating') {
        $r = q("select * from xlink where xlink_id = %d and xlink_static = 1 limit 1", intval($item_id));
        if (!$r) {
            logger('rating not found');
            return;
        }
        $encoded_item = array('type' => 'rating', 'encoding' => 'zot', 'target' => $r[0]['xlink_link'], 'rating' => intval($r[0]['xlink_rating']), 'rating_text' => $r[0]['xlink_rating_text'], 'signature' => $r[0]['xlink_sig'], 'edited' => $r[0]['xlink_updated']);
    }
    $channel = channelx_by_hash($r[0]['xlink_xchan']);
    if (!$channel) {
        logger('no channel');
        return;
    }
    $primary = get_directory_primary();
    if (!$primary) {
        return;
    }
    $interval = get_config('system', 'delivery_interval') !== false ? intval(get_config('system', 'delivery_interval')) : 2;
    $deliveries_per_process = intval(get_config('system', 'delivery_batch_count'));
    if ($deliveries_per_process <= 0) {
        $deliveries_per_process = 1;
    }
    $deliver = array();
    $x = z_fetch_url($primary . '/regdir');
    if ($x['success']) {
        $j = json_decode($x['body'], true);
        if ($j && $j['success'] && is_array($j['directories'])) {
            foreach ($j['directories'] as $h) {
                if ($h == z_root()) {
                    continue;
                }
                $hash = random_string();
                $n = zot_build_packet($channel, 'notify', null, null, $hash);
                queue_insert(array('hash' => $hash, 'account_id' => $channel['channel_account_id'], 'channel_id' => $channel['channel_id'], 'posturl' => $h . '/post', 'notify' => $n, 'msg' => json_encode($encoded_item)));
                $deliver[] = $hash;
                if (count($deliver) >= $deliveries_per_process) {
                    proc_run('php', 'include/deliver.php', $deliver);
                    $deliver = array();
                    if ($interval) {
                        @time_sleep_until(microtime(true) + (double) $interval);
                    }
                }
            }
            // catch any stragglers
            if (count($deliver)) {
                proc_run('php', 'include/deliver.php', $deliver);
            }
        }
    }
    logger('ratenotif: complete.');
    return;
}