コード例 #1
0
ファイル: pumpio.php プロジェクト: royalterra/hubzilla-addons
function pumpio_registerclient($a, $host)
{
    $url = 'https://' . $host . '/api/client/register';
    $params = array();
    $application_name = get_config('pumpio', 'application_name');
    if (!$application_name) {
        $application_name = $a->get_hostname();
    }
    $params['type'] = 'client_associate';
    $params['contacts'] = get_config('system', 'admin_email');
    $params['application_type'] = 'native';
    $params['application_name'] = $application_name;
    $params['logo_uri'] = z_root() . '/images/rhash-32.png';
    $params['redirect_uris'] = z_root() . '/pumpio/connect';
    $res = z_post_url($url, $params);
    if ($res['success']) {
        logger('pumpio: registerclient: ' . $res['body'], LOGGER_DATA);
        $values = json_decode($res['body'], true);
        $pumpio = array();
        $pumpio["client_id"] = $values['client_id'];
        $pumpio["client_secret"] = $values['client_secret'];
        //print_r($values);
        return $values;
    }
    return false;
}
コード例 #2
0
ファイル: share.php プロジェクト: redmatrix/red
function share_init(&$a)
{
    $post_id = argc() > 1 ? intval(argv(1)) : 0;
    if (!$post_id) {
        killme();
    }
    if (!(local_channel() || remote_channel())) {
        killme();
    }
    $r = q("SELECT * from item left join xchan on author_xchan = xchan_hash WHERE id = %d  LIMIT 1", intval($post_id));
    if (!$r) {
        killme();
    }
    if ($r[0]['item_private'] && $r[0]['xchan_network'] !== 'rss') {
        killme();
    }
    $sql_extra = item_permissions_sql($r[0]['uid']);
    $r = q("select * from item where id = %d {$sql_extra}", intval($post_id));
    if (!$r) {
        killme();
    }
    /** @FIXME we only share bbcode */
    if ($r[0]['mimetype'] !== 'text/bbcode') {
        killme();
    }
    /** @FIXME eventually we want to post remotely via rpost on your home site */
    // When that works remove this next bit:
    if (!local_channel()) {
        killme();
    }
    xchan_query($r);
    if (strpos($r[0]['body'], "[/share]") !== false) {
        $pos = strpos($r[0]['body'], "[share");
        $o = substr($r[0]['body'], $pos);
    } else {
        $o = "[share author='" . urlencode($r[0]['author']['xchan_name']) . "' profile='" . $r[0]['author']['xchan_url'] . "' avatar='" . $r[0]['author']['xchan_photo_s'] . "' link='" . $r[0]['plink'] . "' posted='" . $r[0]['created'] . "' message_id='" . $r[0]['mid'] . "']";
        if ($r[0]['title']) {
            $o .= '[b]' . $r[0]['title'] . '[/b]' . "\n";
        }
        $o .= $r[0]['body'];
        $o .= "[/share]";
    }
    if (local_channel()) {
        echo $o;
        killme();
    }
    $observer = $a->get_observer();
    $parsed = $observer['xchan_url'];
    if ($parsed) {
        $post_url = $parsed['scheme'] . ':' . $parsed['host'] . ($parsed['port'] ? ':' . $parsed['port'] : '') . '/rpost';
        /**
         * @FIXME we were probably called from JS so we don't know the return page.
         * In fact we won't be able to load the remote page.
         * we might need an iframe
         */
        $x = z_post_url($post_url, array('f' => '', 'body' => $o));
        killme();
    }
}
コード例 #3
0
ファイル: queue.php プロジェクト: Mauru/red
function queue_run($argv, $argc)
{
    cli_startup();
    global $a;
    require_once 'include/items.php';
    require_once 'include/bbcode.php';
    if (argc() > 1) {
        $queue_id = argv(1);
    } else {
        $queue_id = 0;
    }
    $deadguys = array();
    logger('queue: start');
    $r = q("DELETE FROM outq WHERE outq_created < UTC_TIMESTAMP() - INTERVAL 3 DAY");
    if ($queue_id) {
        $r = q("SELECT * FROM outq WHERE outq_hash = '%s' LIMIT 1", dbesc($queue_id));
    } else {
        // For the first 12 hours we'll try to deliver every 15 minutes
        // After that, we'll only attempt delivery once per hour.
        // This currently only handles the default queue drivers ('zot' or '') which we will group by posturl
        // so that we don't start off a thousand deliveries for a couple of dead hubs.
        // The zot driver will deliver everything destined for a single hub once contact is made (*if* contact is made).
        // Other drivers will have to do something different here and may need their own query.
        $r = q("SELECT * FROM outq WHERE outq_delivered = 0 and (( outq_created > UTC_TIMESTAMP() - INTERVAL 12 HOUR and outq_updated < UTC_TIMESTAMP() - INTERVAL 15 MINUTE ) OR ( outq_updated < UTC_TIMESTAMP() - INTERVAL 1 HOUR )) group by outq_posturl");
    }
    if (!$r) {
        return;
    }
    foreach ($r as $rr) {
        if (in_array($rr['outq_posturl'], $deadguys)) {
            continue;
        }
        if ($rr['outq_driver'] === 'post') {
            $result = z_post_url($rr['outq_posturl'], $rr['outq_msg']);
            if ($result['success'] && $result['return_code'] < 300) {
                logger('queue: queue post success to ' . $rr['outq_posturl'], LOGGER_DEBUG);
                $y = q("delete from outq where outq_hash = '%s' limit 1", dbesc($rr['ouq_hash']));
            } else {
                logger('queue: queue post returned ' . $result['return_code'] . ' from ' . $rr['outq_posturl'], LOGGER_DEBUG);
                $y = q("update outq set outq_updated = '%s' where outq_hash = '%s' limit 1", dbesc(datetime_convert()), dbesc($rr['outq_hash']));
            }
            continue;
        }
        $result = zot_zot($rr['outq_posturl'], $rr['outq_notify']);
        if ($result['success']) {
            zot_process_response($rr['outq_posturl'], $result, $rr);
        } else {
            $deadguys[] = $rr['outq_posturl'];
            $y = q("update outq set outq_updated = '%s' where outq_hash = '%s' limit 1", dbesc(datetime_convert()), dbesc($rr['outq_hash']));
        }
    }
}
コード例 #4
0
ファイル: deliver.php プロジェクト: Mauru/red
function deliver_run($argv, $argc)
{
    cli_startup();
    $a = get_app();
    if ($argc < 2) {
        return;
    }
    logger('deliver: invoked: ' . print_r($argv, true), LOGGER_DATA);
    for ($x = 1; $x < $argc; $x++) {
        $r = q("select * from outq where outq_hash = '%s' limit 1", dbesc($argv[$x]));
        if ($r) {
            if ($r[0]['outq_driver'] === 'post') {
                $result = z_post_url($r[0]['outq_posturl'], $r[0]['outq_msg']);
                if ($result['success'] && $result['return_code'] < 300) {
                    logger('deliver: queue post success to ' . $r[0]['outq_posturl'], LOGGER_DEBUG);
                    $y = q("delete from outq where outq_hash = '%s' limit 1", dbesc($argv[$x]));
                } else {
                    logger('deliver: queue post returned ' . $result['return_code'] . ' from ' . $r[0]['outq_posturl'], LOGGER_DEBUG);
                    $y = q("update outq set outq_updated = '%s' where outq_hash = '%s' limit 1", dbesc(datetime_convert()), dbesc($argv[$x]));
                }
                continue;
            }
            if ($r[0]['outq_posturl'] === z_root() . '/post') {
                logger('deliver: local delivery', LOGGER_DEBUG);
                // local delivery
                // we should probably batch these and save a few delivery processes
                // If there is no outq_msg, this is a refresh_all message which does not require local handling
                if ($r[0]['outq_msg']) {
                    $msg = array('body' => json_encode(array('pickup' => array(array('notify' => json_decode($r[0]['outq_notify'], true), 'message' => json_decode($r[0]['outq_msg'], true))))));
                    zot_import($msg, z_root());
                    $r = q("delete from outq where outq_hash = '%s' limit 1", dbesc($argv[$x]));
                }
            } else {
                logger('deliver: dest: ' . $r[0]['outq_posturl'], LOGGER_DEBUG);
                $result = zot_zot($r[0]['outq_posturl'], $r[0]['outq_notify']);
                if ($result['success']) {
                    zot_process_response($r[0]['outq_posturl'], $result, $r[0]);
                } else {
                    $y = q("update outq set outq_updated = '%s' where outq_hash = '%s' limit 1", dbesc(datetime_convert()), dbesc($argv[$x]));
                }
            }
        }
    }
}
コード例 #5
0
ファイル: oexchange.php プロジェクト: TamirAl/hubzilla
function oexchange_content(&$a)
{
    if (!local_channel()) {
        if (remote_channel()) {
            $observer = $a->get_observer();
            if ($observer && $observer['xchan_url']) {
                $parsed = @parse_url($observer['xchan_url']);
                if (!$parsed) {
                    notice(t('Unable to find your hub.') . EOL);
                    return;
                }
                $url = $parsed['scheme'] . '://' . $parsed['host'] . ($parsed['port'] ? ':' . $parsed['port'] : '');
                $url .= '/oexchange';
                $result = z_post_url($url, $_REQUEST);
                json_return_and_die($result);
            }
        }
        return login(false);
    }
    if (argc() > 1 && argv(1) === 'done') {
        info(t('Post successful.') . EOL);
        return;
    }
    $url = x($_REQUEST, 'url') && strlen($_REQUEST['url']) ? urlencode(notags(trim($_REQUEST['url']))) : '';
    $title = x($_REQUEST, 'title') && strlen($_REQUEST['title']) ? '&title=' . urlencode(notags(trim($_REQUEST['title']))) : '';
    $description = x($_REQUEST, 'description') && strlen($_REQUEST['description']) ? '&description=' . urlencode(notags(trim($_REQUEST['description']))) : '';
    $tags = x($_REQUEST, 'tags') && strlen($_REQUEST['tags']) ? '&tags=' . urlencode(notags(trim($_REQUEST['tags']))) : '';
    $ret = z_fetch_url($a->get_baseurl() . '/urlinfo?f=&url=' . $url . $title . $description . $tags);
    if ($ret['success']) {
        $s = $ret['body'];
    }
    if (!strlen($s)) {
        return;
    }
    $post = array();
    $post['profile_uid'] = local_channel();
    $post['return'] = '/oexchange/done';
    $post['body'] = $s;
    $post['type'] = 'wall';
    $_REQUEST = $post;
    require_once 'mod/item.php';
    item_post($a);
}
コード例 #6
0
ファイル: import.php プロジェクト: einervonvielen/hubzilla
function sync_files($channel, $files)
{
    require_once 'include/attach.php';
    if ($channel && $files) {
        foreach ($files as $f) {
            if (!$f) {
                continue;
            }
            $fetch_url = $f['fetch_url'];
            $oldbase = dirname($fetch_url);
            $original_channel = $f['original_channel'];
            if (!($fetch_url && $original_channel)) {
                continue;
            }
            if ($f['attach']) {
                $attachment_stored = false;
                foreach ($f['attach'] as $att) {
                    convert_oldfields($att, 'data', 'content');
                    if ($att['deleted']) {
                        attach_delete($channel, $att['hash']);
                        continue;
                    }
                    $attach_exists = false;
                    $x = attach_by_hash($att['hash']);
                    logger('sync_files duplicate check: attach_exists=' . $attach_exists, LOGGER_DEBUG);
                    logger('sync_files duplicate check: att=' . print_r($att, true), LOGGER_DEBUG);
                    logger('sync_files duplicate check: attach_by_hash() returned ' . print_r($x, true), LOGGER_DEBUG);
                    if ($x['success']) {
                        $attach_exists = true;
                        $attach_id = $x[0]['id'];
                    }
                    $newfname = 'store/' . $channel['channel_address'] . '/' . get_attach_binname($att['content']);
                    unset($att['id']);
                    $att['aid'] = $channel['channel_account_id'];
                    $att['uid'] = $channel['channel_id'];
                    // check for duplicate folder names with the same parent.
                    // If we have a duplicate that doesn't match this hash value
                    // change the name so that the contents won't be "covered over"
                    // by the existing directory. Use the same logic we use for
                    // duplicate files.
                    if (strpos($att['filename'], '.') !== false) {
                        $basename = substr($att['filename'], 0, strrpos($att['filename'], '.'));
                        $ext = substr($att['filename'], strrpos($att['filename'], '.'));
                    } else {
                        $basename = $att['filename'];
                        $ext = '';
                    }
                    $r = q("select filename from attach where ( filename = '%s' OR filename like '%s' ) and folder = '%s' and hash != '%s' ", dbesc($basename . $ext), dbesc($basename . '(%)' . $ext), dbesc($att['folder']), dbesc($att['hash']));
                    if ($r) {
                        $x = 1;
                        do {
                            $found = false;
                            foreach ($r as $rr) {
                                if ($rr['filename'] === $basename . '(' . $x . ')' . $ext) {
                                    $found = true;
                                    break;
                                }
                            }
                            if ($found) {
                                $x++;
                            }
                        } while ($found);
                        $att['filename'] = $basename . '(' . $x . ')' . $ext;
                    } else {
                        $att['filename'] = $basename . $ext;
                    }
                    // end duplicate detection
                    // @fixme - update attachment structures if they are modified rather than created
                    $att['content'] = $newfname;
                    // Note: we use $att['hash'] below after it has been escaped to
                    // fetch the file contents.
                    // If the hash ever contains any escapable chars this could cause
                    // problems. Currently it does not.
                    dbesc_array($att);
                    if ($attach_exists) {
                        logger('sync_files attach exists: ' . print_r($att, true), LOGGER_DEBUG);
                        $str = '';
                        foreach ($att as $k => $v) {
                            if ($str) {
                                $str .= ",";
                            }
                            $str .= " `" . $k . "` = '" . $v . "' ";
                        }
                        $r = dbq("update `attach` set " . $str . " where id = " . intval($attach_id));
                    } else {
                        logger('sync_files attach does not exists: ' . print_r($att, true), LOGGER_DEBUG);
                        $r = dbq("INSERT INTO attach (`" . implode("`, `", array_keys($att)) . "`) VALUES ('" . implode("', '", array_values($att)) . "')");
                    }
                    // is this a directory?
                    if ($att['filetype'] === 'multipart/mixed' && $att['is_dir']) {
                        os_mkdir($newfname, STORAGE_DEFAULT_PERMISSIONS, true);
                        $attachment_stored = true;
                        continue;
                    } else {
                        // it's a file
                        // for the sync version of this algorithm (as opposed to 'offline import')
                        // we will fetch the actual file from the source server so it can be
                        // streamed directly to disk and avoid consuming PHP memory if it's a huge
                        // audio/video file or something.
                        $time = datetime_convert();
                        $parr = array('hash' => $channel['channel_hash'], 'time' => $time, 'resource' => $att['hash'], 'revision' => 0, 'signature' => base64url_encode(rsa_sign($channel['channel_hash'] . '.' . $time, $channel['channel_prvkey'])));
                        $store_path = $newfname;
                        $fp = fopen($newfname, 'w');
                        if (!$fp) {
                            logger('failed to open storage file.', LOGGER_NORMAL, LOG_ERR);
                            continue;
                        }
                        $redirects = 0;
                        $x = z_post_url($fetch_url, $parr, $redirects, array('filep' => $fp));
                        fclose($fp);
                        if ($x['success']) {
                            $attachment_stored = true;
                        }
                        continue;
                    }
                }
            }
            if (!$attachment_stored) {
                // @TODO should we queue this and retry or delete everything or what?
                logger('attachment store failed', LOGGER_NORMAL, LOG_ERR);
            }
            if ($f['photo']) {
                foreach ($f['photo'] as $p) {
                    unset($p['id']);
                    $p['aid'] = $channel['channel_account_id'];
                    $p['uid'] = $channel['channel_id'];
                    convert_oldfields($p, 'data', 'content');
                    convert_oldfields($p, 'scale', 'imgscale');
                    convert_oldfields($p, 'size', 'filesize');
                    convert_oldfields($p, 'type', 'mimetype');
                    // if this is a profile photo, undo the profile photo bit
                    // for any other photo which previously held it.
                    if ($p['photo_usage'] == PHOTO_PROFILE) {
                        $e = q("update photo set photo_usage = %d where photo_usage = %d\n\t\t\t\t\t\t\tand resource_id != '%s' and uid = %d ", intval(PHOTO_NORMAL), intval(PHOTO_PROFILE), dbesc($p['resource_id']), intval($channel['channel_id']));
                    }
                    // same for cover photos
                    if ($p['photo_usage'] == PHOTO_COVER) {
                        $e = q("update photo set photo_usage = %d where photo_usage = %d\n\t\t\t\t\t\t\tand resource_id != '%s' and uid = %d ", intval(PHOTO_NORMAL), intval(PHOTO_COVER), dbesc($p['resource_id']), intval($channel['channel_id']));
                    }
                    if ($p['imgscale'] === 0 && $p['os_storage']) {
                        $p['content'] = $store_path;
                    } else {
                        $p['content'] = base64_decode($p['content']);
                    }
                    $exists = q("select * from photo where resource_id = '%s' and imgscale = %d and uid = %d limit 1", dbesc($p['resource_id']), intval($p['imgscale']), intval($channel['channel_id']));
                    dbesc_array($p);
                    if ($exists) {
                        $str = '';
                        foreach ($p as $k => $v) {
                            if ($str) {
                                $str .= ",";
                            }
                            $str .= " `" . $k . "` = '" . $v . "' ";
                        }
                        $r = dbq("update `photo` set " . $str . " where id = " . intval($exists[0]['id']));
                    } else {
                        $r = dbq("INSERT INTO photo (`" . implode("`, `", array_keys($p)) . "`) VALUES ('" . implode("', '", array_values($p)) . "')");
                    }
                }
            }
            if ($f['item']) {
                sync_items($channel, $f['item'], ['channel_address' => $original_channel, 'url' => $oldbase]);
            }
        }
    }
}
コード例 #7
0
function pubsubhubbub_subscribe($url, $channel, $xchan, $feed, $hubmode = 'subscribe')
{
    $push_url = z_root() . '/pubsub/' . $channel['channel_address'] . '/' . $xchan['abook_id'];
    $verify = get_abconfig($channel['channel_id'], $xchan['xchan_hash'], 'pubsubhubbub', 'verify_token');
    if (!$verify) {
        $verify = set_abconfig($channel['channel_id'], $xchan['xchan_hash'], 'pubsubhubbub', 'verify_token', random_string(16));
    }
    if ($feed) {
        set_xconfig($xchan['xchan_hash'], 'system', 'feed_url', $feed);
    } else {
        $feed = get_xconfig($xchan['xchan_hash'], 'system', 'feed_url');
    }
    $params = 'hub.mode=' . $hubmode . '&hub.callback=' . urlencode($push_url) . '&hub.topic=' . urlencode($feed) . '&hub.verify=async&hub.verify_token=' . $verify;
    logger('subscribe_to_hub: ' . $hubmode . ' ' . $xchan['xchan_name'] . ' to hub ' . $url . ' endpoint: ' . $push_url . ' with verifier ' . $verify);
    $x = z_post_url($url, $params);
    logger('subscribe_to_hub: returns: ' . $x['return_code'], LOGGER_DEBUG);
    return;
}
コード例 #8
0
ファイル: Finger.php プロジェクト: anmol26s/hubzilla-yunohost
 /**
  * @brief Look up information about channel.
  *
  * @param string $webbie
  *   does not have to be host qualified e.g. 'foo' is treated as 'foo\@thishub'
  * @param array $channel
  *   (optional), if supplied permissions will be enumerated specifically for $channel
  * @param boolean $autofallback
  *   fallback/failover to http if https connection cannot be established. Default is true.
  *
  * @return zotinfo array (with 'success' => true) or array('success' => false);
  */
 public static function run($webbie, $channel = null, $autofallback = true)
 {
     $ret = array('success' => false);
     self::$token = random_string();
     if (strpos($webbie, '@') === false) {
         $address = $webbie;
         $host = App::get_hostname();
     } else {
         $address = substr($webbie, 0, strpos($webbie, '@'));
         $host = substr($webbie, strpos($webbie, '@') + 1);
     }
     $xchan_addr = $address . '@' . $host;
     if (!$address || !$xchan_addr) {
         logger('zot_finger: no address :' . $webbie);
         return $ret;
     }
     logger('using xchan_addr: ' . $xchan_addr, LOGGER_DATA, LOG_DEBUG);
     // potential issue here; the xchan_addr points to the primary hub.
     // The webbie we were called with may not, so it might not be found
     // unless we query for hubloc_addr instead of xchan_addr
     $r = q("select xchan.*, hubloc.* from xchan\n\t\t\tleft join hubloc on xchan_hash = hubloc_hash\n\t\t\twhere xchan_addr = '%s' and hubloc_primary = 1 limit 1", dbesc($xchan_addr));
     if ($r) {
         $url = $r[0]['hubloc_url'];
         if ($r[0]['hubloc_network'] && $r[0]['hubloc_network'] !== 'zot') {
             logger('zot_finger: alternate network: ' . $webbie);
             logger('url: ' . $url . ', net: ' . var_export($r[0]['hubloc_network'], true), LOGGER_DATA, LOG_DEBUG);
             return $ret;
         }
     } else {
         $url = 'https://' . $host;
     }
     $rhs = '/.well-known/zot-info';
     $https = strpos($url, 'https://') === 0 ? true : false;
     logger('zot_finger: ' . $address . ' at ' . $url, LOGGER_DEBUG);
     if ($channel) {
         $postvars = array('address' => $address, 'target' => $channel['channel_guid'], 'target_sig' => $channel['channel_guid_sig'], 'key' => $channel['channel_pubkey'], 'token' => self::$token);
         $result = z_post_url($url . $rhs, $postvars);
         if (!$result['success'] && $autofallback) {
             if ($https) {
                 logger('zot_finger: https failed. falling back to http');
                 $result = z_post_url('http://' . $host . $rhs, $postvars);
             }
         }
     } else {
         $rhs .= '?f=&address=' . urlencode($address) . '&token=' . self::$token;
         $result = z_fetch_url($url . $rhs);
         if (!$result['success'] && $autofallback) {
             if ($https) {
                 logger('zot_finger: https failed. falling back to http');
                 $result = z_fetch_url('http://' . $host . $rhs);
             }
         }
     }
     if (!$result['success']) {
         logger('zot_finger: no results');
         return $ret;
     }
     $x = json_decode($result['body'], true);
     if ($x) {
         $signed_token = is_array($x) && array_key_exists('signed_token', $x) ? $x['signed_token'] : null;
         if ($signed_token) {
             $valid = rsa_verify('token.' . self::$token, base64url_decode($signed_token), $x['key']);
             if (!$valid) {
                 logger('invalid signed token: ' . $url . $rhs, LOGGER_NORMAL, LOG_ERR);
                 return $ret;
             }
         } else {
             logger('No signed token from ' . $url . $rhs, LOGGER_NORMAL, LOG_WARNING);
             // after 2017-01-01 this will be a hard error unless you over-ride it.
             if (time() > 1483228800 && !get_config('system', 'allow_unsigned_zotfinger')) {
                 return $ret;
             }
         }
     }
     return $x;
 }
コード例 #9
0
ファイル: zot.php プロジェクト: 23n/hubzilla
/**
 * @brief Refreshes after permission changed or friending, etc.
 *
 * zot_refresh is typically invoked when somebody has changed permissions of a channel and they are notified
 * to fetch new permissions via a finger/discovery operation. This may result in a new connection
 * (abook entry) being added to a local channel and it may result in auto-permissions being granted.
 *
 * Friending in zot is accomplished by sending a refresh packet to a specific channel which indicates a
 * permission change has been made by the sender which affects the target channel. The hub controlling
 * the target channel does targetted discovery (a zot-finger request requesting permissions for the local
 * channel). These are decoded here, and if necessary and abook structure (addressbook) is created to store
 * the permissions assigned to this channel.
 *
 * Initially these abook structures are created with a 'pending' flag, so that no reverse permissions are
 * implied until this is approved by the owner channel. A channel can also auto-populate permissions in
 * return and send back a refresh packet of its own. This is used by forum and group communication channels
 * so that friending and membership in the channel's "club" is automatic.
 *
 * @param array $them => xchan structure of sender
 * @param array $channel => local channel structure of target recipient, required for "friending" operations
 * @param array $force default false
 *
 * @returns boolean true if successful, else false
 */
function zot_refresh($them, $channel = null, $force = false)
{
    if (array_key_exists('xchan_network', $them) && $them['xchan_network'] !== 'zot') {
        logger('zot_refresh: not got zot. ' . $them['xchan_name']);
        return true;
    }
    logger('zot_refresh: them: ' . print_r($them, true), LOGGER_DATA);
    if ($channel) {
        logger('zot_refresh: channel: ' . print_r($channel, true), LOGGER_DATA);
    }
    $url = null;
    if ($them['hubloc_url']) {
        $url = $them['hubloc_url'];
    } else {
        $r = null;
        // if they re-installed the server we could end up with the wrong record - pointing to the old install.
        // We'll order by reverse id to try and pick off the newest one first and hopefully end up with the
        // correct hubloc. If this doesn't work we may have to re-write this section to try them all.
        if (array_key_exists('xchan_addr', $them) && $them['xchan_addr']) {
            $r = q("select hubloc_url, hubloc_primary from hubloc where hubloc_addr = '%s' order by hubloc_id desc", dbesc($them['xchan_addr']));
        }
        if (!$r) {
            $r = q("select hubloc_url, hubloc_primary from hubloc where hubloc_hash = '%s' order by hubloc_id desc", dbesc($them['xchan_hash']));
        }
        if ($r) {
            foreach ($r as $rr) {
                if (intval($rr['hubloc_primary'])) {
                    $url = $rr['hubloc_url'];
                    break;
                }
            }
            if (!$url) {
                $url = $r[0]['hubloc_url'];
            }
        }
    }
    if (!$url) {
        logger('zot_refresh: no url');
        return false;
    }
    $postvars = array();
    if ($channel) {
        $postvars['target'] = $channel['channel_guid'];
        $postvars['target_sig'] = $channel['channel_guid_sig'];
        $postvars['key'] = $channel['channel_pubkey'];
    }
    if (array_key_exists('xchan_addr', $them) && $them['xchan_addr']) {
        $postvars['address'] = $them['xchan_addr'];
    }
    if (array_key_exists('xchan_hash', $them) && $them['xchan_hash']) {
        $postvars['guid_hash'] = $them['xchan_hash'];
    }
    if (array_key_exists('xchan_guid', $them) && $them['xchan_guid'] && array_key_exists('xchan_guid_sig', $them) && $them['xchan_guid_sig']) {
        $postvars['guid'] = $them['xchan_guid'];
        $postvars['guid_sig'] = $them['xchan_guid_sig'];
    }
    $rhs = '/.well-known/zot-info';
    $result = z_post_url($url . $rhs, $postvars);
    logger('zot_refresh: zot-info: ' . print_r($result, true), LOGGER_DATA);
    if ($result['success']) {
        $j = json_decode($result['body'], true);
        if (!($j && $j['success'])) {
            logger('zot_refresh: result not decodable');
            return false;
        }
        $x = import_xchan($j, $force ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED);
        if (!$x['success']) {
            return false;
        }
        $their_perms = 0;
        if ($channel) {
            $global_perms = get_perms();
            if ($j['permissions']['data']) {
                $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'];
            }
            $connected_set = false;
            if ($permissions && is_array($permissions)) {
                foreach ($permissions as $k => $v) {
                    // The connected permission means you are in their address book
                    if ($k === 'connected') {
                        $connected_set = intval($v);
                        continue;
                    }
                    if ($v && array_key_exists($k, $global_perms)) {
                        $their_perms = $their_perms | intval($global_perms[$k][1]);
                    }
                }
            }
            if (array_key_exists('profile', $j) && array_key_exists('next_birthday', $j['profile'])) {
                $next_birthday = datetime_convert('UTC', 'UTC', $j['profile']['next_birthday']);
            } else {
                $next_birthday = NULL_DATE;
            }
            $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1", dbesc($x['hash']), intval($channel['channel_id']));
            if ($r) {
                // connection exists
                // if the dob is the same as what we have stored (disregarding the year), keep the one
                // we have as we may have updated the year after sending a notification; and resetting
                // to the one we just received would cause us to create duplicated events.
                if (substr($r[0]['abook_dob'], 5) == substr($next_birthday, 5)) {
                    $next_birthday = $r[0]['abook_dob'];
                }
                $current_abook_connected = intval($r[0]['abook_unconnected']) ? 0 : 1;
                $y = q("update abook set abook_their_perms = %d, abook_dob = '%s'\n\t\t\t\t\twhere abook_xchan = '%s' and abook_channel = %d\n\t\t\t\t\tand abook_self = 0 ", intval($their_perms), dbescdate($next_birthday), dbesc($x['hash']), intval($channel['channel_id']));
                //				if(($connected_set === 0 || $connected_set === 1) && ($connected_set !== $current_abook_unconnected)) {
                // if they are in your address book but you aren't in theirs, and/or this does not
                // match your current connected state setting, toggle it.
                /** @FIXME uncoverted to postgres */
                /** @FIXME when this was enabled, all contacts became unconnected. Currently disabled intentionally */
                //					$y1 = q("update abook set abook_unconnected = 1
                //						where abook_xchan = '%s' and abook_channel = %d
                //						and abook_self = 0 limit 1",
                //						dbesc($x['hash']),
                //						intval($channel['channel_id'])
                //					);
                //				}
                if (!$y) {
                    logger('abook update failed');
                } else {
                    // if we were just granted read stream permission and didn't have it before, try to pull in some posts
                    if (!($r[0]['abook_their_perms'] & PERMS_R_STREAM) && $their_perms & PERMS_R_STREAM) {
                        proc_run('php', 'include/onepoll.php', $r[0]['abook_id']);
                    }
                }
            } else {
                // new connection
                $role = get_pconfig($channel['channel_id'], 'system', 'permissions_role');
                if ($role) {
                    $xx = get_role_perms($role);
                    if ($xx['perms_auto']) {
                        $default_perms = $xx['perms_accept'];
                    }
                }
                if (!$default_perms) {
                    $default_perms = intval(get_pconfig($channel['channel_id'], 'system', 'autoperms'));
                }
                // Keep original perms to check if we need to notify them
                $previous_perms = get_all_perms($channel['channel_id'], $x['hash']);
                $closeness = get_pconfig($channel['channel_id'], 'system', 'new_abook_closeness');
                if ($closeness === false) {
                    $closeness = 80;
                }
                $y = q("insert into abook ( abook_account, abook_channel, abook_closeness, abook_xchan, abook_their_perms, abook_my_perms, abook_created, abook_updated, abook_dob, abook_pending ) values ( %d, %d, %d, '%s', %d, %d, '%s', '%s', '%s', %d )", intval($channel['channel_account_id']), intval($channel['channel_id']), intval($closeness), dbesc($x['hash']), intval($their_perms), intval($default_perms), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($next_birthday), intval($default_perms ? 0 : 1));
                if ($y) {
                    logger("New introduction received for {$channel['channel_name']}");
                    $new_perms = get_all_perms($channel['channel_id'], $x['hash']);
                    // Send a clone sync packet and a permissions update if permissions have changed
                    $new_connection = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 order by abook_created desc limit 1", dbesc($x['hash']), intval($channel['channel_id']));
                    if ($new_connection) {
                        if ($new_perms != $previous_perms) {
                            proc_run('php', 'include/notifier.php', 'permission_create', $new_connection[0]['abook_id']);
                        }
                        require_once 'include/enotify.php';
                        notification(array('type' => NOTIFY_INTRO, 'from_xchan' => $x['hash'], 'to_xchan' => $channel['channel_hash'], 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id']));
                        if ($their_perms & PERMS_R_STREAM) {
                            if ($channel['channel_w_stream'] & PERMS_PENDING || !intval($new_connection[0]['abook_pending'])) {
                                proc_run('php', 'include/onepoll.php', $new_connection[0]['abook_id']);
                            }
                        }
                        unset($new_connection[0]['abook_id']);
                        unset($new_connection[0]['abook_account']);
                        unset($new_connection[0]['abook_channel']);
                        build_sync_packet($channel['channel_id'], array('abook' => $new_connection));
                    }
                }
            }
        }
        return true;
    }
    return false;
}
コード例 #10
0
ファイル: network.php プロジェクト: bashrc/hubzilla
/**
 * @brief Like z_post_url() but with an application/json HTTP header.
 *
 * Add a "Content-Type: application/json" HTTP-header to $opts and call z_post_url().
 *
 * @see z_post_url()
 *
 * @param string $url
 * @param array $params
 * @param number $redirects default 0
 * @param array $opts (optional) curl options
 * @return z_post_url()
 */
function z_post_url_json($url, $params, $redirects = 0, $opts = array())
{
    $opts = array_merge($opts, array('headers' => array('Content-Type: application/json')));
    return z_post_url($url, json_encode($params), $redirects, $opts);
}
コード例 #11
0
ファイル: deliver.php プロジェクト: HaakonME/redmatrix
function deliver_run($argv, $argc)
{
    cli_startup();
    $a = get_app();
    if ($argc < 2) {
        return;
    }
    logger('deliver: invoked: ' . print_r($argv, true), LOGGER_DATA);
    for ($x = 1; $x < $argc; $x++) {
        $r = q("select * from outq where outq_hash = '%s' limit 1", dbesc($argv[$x]));
        if ($r) {
            /**
             * Check to see if we have any recent communications with this hub (in the last month).
             * If not, reduce the outq_priority.
             */
            $h = parse_url($r[0]['outq_posturl']);
            if ($h) {
                $base = $h['scheme'] . '://' . $h['host'] . ($h['port'] ? ':' . $h['port'] : '');
                if ($base !== z_root()) {
                    $y = q("select site_update, site_dead from site where site_url = '%s' ", dbesc($base));
                    if ($y) {
                        if (intval($y[0]['site_dead'])) {
                            q("delete from outq where outq_posturl = '%s'", dbesc($r[0]['outq_posturl']));
                            logger('dead site ignored ' . $base);
                            continue;
                        }
                        if ($y[0]['site_update'] < datetime_convert('UTC', 'UTC', 'now - 1 month')) {
                            q("update outq set outq_priority = %d where outq_hash = '%s'", intval($r[0]['outq_priority'] + 10), dbesc($r[0]['outq_hash']));
                            logger('immediate delivery deferred for site ' . $base);
                            continue;
                        }
                    }
                }
            }
            // "post" queue driver - used for diaspora and friendica-over-diaspora communications.
            if ($r[0]['outq_driver'] === 'post') {
                $result = z_post_url($r[0]['outq_posturl'], $r[0]['outq_msg']);
                if ($result['success'] && $result['return_code'] < 300) {
                    logger('deliver: queue post success to ' . $r[0]['outq_posturl'], LOGGER_DEBUG);
                    $y = q("delete from outq where outq_hash = '%s'", dbesc($argv[$x]));
                } else {
                    logger('deliver: queue post returned ' . $result['return_code'] . ' from ' . $r[0]['outq_posturl'], LOGGER_DEBUG);
                    $y = q("update outq set outq_updated = '%s' where outq_hash = '%s'", dbesc(datetime_convert()), dbesc($argv[$x]));
                }
                continue;
            }
            $notify = json_decode($r[0]['outq_notify'], true);
            // Check if this is a conversation request packet. It won't have outq_msg
            // but will be an encrypted packet - so will need to be handed off to
            // web delivery rather than processed inline.
            $sendtoweb = false;
            if (array_key_exists('iv', $notify) && !$r[0]['outq_msg']) {
                $sendtoweb = true;
            }
            if ($r[0]['outq_posturl'] === z_root() . '/post' && !$sendtoweb) {
                logger('deliver: local delivery', LOGGER_DEBUG);
                // local delivery
                // we should probably batch these and save a few delivery processes
                if ($r[0]['outq_msg']) {
                    $m = json_decode($r[0]['outq_msg'], true);
                    if (array_key_exists('message_list', $m)) {
                        foreach ($m['message_list'] as $mm) {
                            $msg = array('body' => json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify, 'message' => $mm)))));
                            zot_import($msg, z_root());
                        }
                    } else {
                        $msg = array('body' => json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify, 'message' => $m)))));
                        zot_import($msg, z_root());
                    }
                    $r = q("delete from outq where outq_hash = '%s'", dbesc($argv[$x]));
                }
            } else {
                logger('deliver: dest: ' . $r[0]['outq_posturl'], LOGGER_DEBUG);
                $result = zot_zot($r[0]['outq_posturl'], $r[0]['outq_notify']);
                if ($result['success']) {
                    logger('deliver: remote zot delivery succeeded to ' . $r[0]['outq_posturl']);
                    zot_process_response($r[0]['outq_posturl'], $result, $r[0]);
                } else {
                    logger('deliver: remote zot delivery failed to ' . $r[0]['outq_posturl']);
                    $y = q("update outq set outq_updated = '%s' where outq_hash = '%s'", dbesc(datetime_convert()), dbesc($argv[$x]));
                }
            }
        }
    }
}
コード例 #12
0
ファイル: zot.php プロジェクト: BlaBlaNet/hubzilla
/**
 * @brief Refreshes after permission changed or friending, etc.
 *
 * zot_refresh is typically invoked when somebody has changed permissions of a channel and they are notified
 * to fetch new permissions via a finger/discovery operation. This may result in a new connection
 * (abook entry) being added to a local channel and it may result in auto-permissions being granted.
 *
 * Friending in zot is accomplished by sending a refresh packet to a specific channel which indicates a
 * permission change has been made by the sender which affects the target channel. The hub controlling
 * the target channel does targetted discovery (a zot-finger request requesting permissions for the local
 * channel). These are decoded here, and if necessary and abook structure (addressbook) is created to store
 * the permissions assigned to this channel.
 *
 * Initially these abook structures are created with a 'pending' flag, so that no reverse permissions are
 * implied until this is approved by the owner channel. A channel can also auto-populate permissions in
 * return and send back a refresh packet of its own. This is used by forum and group communication channels
 * so that friending and membership in the channel's "club" is automatic.
 *
 * @param array $them => xchan structure of sender
 * @param array $channel => local channel structure of target recipient, required for "friending" operations
 * @param array $force default false
 *
 * @returns boolean true if successful, else false
 */
function zot_refresh($them, $channel = null, $force = false)
{
    if (array_key_exists('xchan_network', $them) && $them['xchan_network'] !== 'zot') {
        logger('zot_refresh: not got zot. ' . $them['xchan_name']);
        return true;
    }
    logger('zot_refresh: them: ' . print_r($them, true), LOGGER_DATA, LOG_DEBUG);
    if ($channel) {
        logger('zot_refresh: channel: ' . print_r($channel, true), LOGGER_DATA, LOG_DEBUG);
    }
    $url = null;
    if ($them['hubloc_url']) {
        $url = $them['hubloc_url'];
    } else {
        $r = null;
        // if they re-installed the server we could end up with the wrong record - pointing to the old install.
        // We'll order by reverse id to try and pick off the newest one first and hopefully end up with the
        // correct hubloc. If this doesn't work we may have to re-write this section to try them all.
        if (array_key_exists('xchan_addr', $them) && $them['xchan_addr']) {
            $r = q("select hubloc_url, hubloc_primary from hubloc where hubloc_addr = '%s' order by hubloc_id desc", dbesc($them['xchan_addr']));
        }
        if (!$r) {
            $r = q("select hubloc_url, hubloc_primary from hubloc where hubloc_hash = '%s' order by hubloc_id desc", dbesc($them['xchan_hash']));
        }
        if ($r) {
            foreach ($r as $rr) {
                if (intval($rr['hubloc_primary'])) {
                    $url = $rr['hubloc_url'];
                    break;
                }
            }
            if (!$url) {
                $url = $r[0]['hubloc_url'];
            }
        }
    }
    if (!$url) {
        logger('zot_refresh: no url');
        return false;
    }
    $token = random_string();
    $postvars = array();
    $postvars['token'] = $token;
    if ($channel) {
        $postvars['target'] = $channel['channel_guid'];
        $postvars['target_sig'] = $channel['channel_guid_sig'];
        $postvars['key'] = $channel['channel_pubkey'];
    }
    if (array_key_exists('xchan_addr', $them) && $them['xchan_addr']) {
        $postvars['address'] = $them['xchan_addr'];
    }
    if (array_key_exists('xchan_hash', $them) && $them['xchan_hash']) {
        $postvars['guid_hash'] = $them['xchan_hash'];
    }
    if (array_key_exists('xchan_guid', $them) && $them['xchan_guid'] && array_key_exists('xchan_guid_sig', $them) && $them['xchan_guid_sig']) {
        $postvars['guid'] = $them['xchan_guid'];
        $postvars['guid_sig'] = $them['xchan_guid_sig'];
    }
    $rhs = '/.well-known/zot-info';
    $result = z_post_url($url . $rhs, $postvars);
    logger('zot_refresh: zot-info: ' . print_r($result, true), LOGGER_DATA, LOG_DEBUG);
    if ($result['success']) {
        $j = json_decode($result['body'], true);
        if (!($j && $j['success'])) {
            logger('zot_refresh: result not decodable');
            return false;
        }
        $signed_token = is_array($j) && array_key_exists('signed_token', $j) ? $j['signed_token'] : null;
        if ($signed_token) {
            $valid = rsa_verify('token.' . $token, base64url_decode($signed_token), $j['key']);
            if (!$valid) {
                logger('invalid signed token: ' . $url . $rhs, LOGGER_NORMAL, LOG_ERR);
                return false;
            }
        } else {
            logger('No signed token from ' . $url . $rhs, LOGGER_NORMAL, LOG_WARNING);
            // after 2017-01-01 this will be a hard error unless you over-ride it.
            if (time() > 1483228800 && !get_config('system', 'allow_unsigned_zotfinger')) {
                return false;
            }
        }
        $x = import_xchan($j, $force ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED);
        if (!$x['success']) {
            return false;
        }
        if ($channel) {
            if ($j['permissions']['data']) {
                $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, LOG_DEBUG);
            } else {
                $permissions = $j['permissions'];
            }
            $connected_set = false;
            if ($permissions && is_array($permissions)) {
                $old_read_stream_perm = get_abconfig($channel['channel_id'], $x['hash'], 'their_perms', 'view_stream');
                foreach ($permissions as $k => $v) {
                    set_abconfig($channel['channel_id'], $x['hash'], 'their_perms', $k, $v);
                }
            }
            if (array_key_exists('profile', $j) && array_key_exists('next_birthday', $j['profile'])) {
                $next_birthday = datetime_convert('UTC', 'UTC', $j['profile']['next_birthday']);
            } else {
                $next_birthday = NULL_DATE;
            }
            $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1", dbesc($x['hash']), intval($channel['channel_id']));
            if ($r) {
                // connection exists
                // if the dob is the same as what we have stored (disregarding the year), keep the one
                // we have as we may have updated the year after sending a notification; and resetting
                // to the one we just received would cause us to create duplicated events.
                if (substr($r[0]['abook_dob'], 5) == substr($next_birthday, 5)) {
                    $next_birthday = $r[0]['abook_dob'];
                }
                $y = q("update abook set abook_dob = '%s'\n\t\t\t\t\twhere abook_xchan = '%s' and abook_channel = %d\n\t\t\t\t\tand abook_self = 0 ", dbescdate($next_birthday), dbesc($x['hash']), intval($channel['channel_id']));
                if (!$y) {
                    logger('abook update failed');
                } else {
                    // if we were just granted read stream permission and didn't have it before, try to pull in some posts
                    if (!$old_read_stream_perm && intval($permissions['view_stream'])) {
                        Zotlabs\Daemon\Master::Summon(array('Onepoll', $r[0]['abook_id']));
                    }
                }
            } else {
                // new connection
                $my_perms = null;
                $automatic = false;
                $role = get_pconfig($channel['channel_id'], 'system', 'permissions_role');
                if ($role) {
                    $xx = \Zotlabs\Access\PermissionRoles::role_perms($role);
                    if ($xx['perms_auto']) {
                        $automatic = true;
                        $default_perms = $xx['perms_connect'];
                        $my_perms = \Zotlabs\Access\Permissions::FilledPerms($default_perms);
                    }
                }
                if (!$my_perms) {
                    $m = \Zotlabs\Access\Permissions::FilledAutoperms($channel['channel_id']);
                    if ($m) {
                        $automatic = true;
                        $my_perms = $m;
                    }
                }
                if ($my_perms) {
                    foreach ($my_perms as $k => $v) {
                        set_abconfig($channel['channel_id'], $x['hash'], 'my_perms', $k, $v);
                    }
                }
                // Keep original perms to check if we need to notify them
                $previous_perms = get_all_perms($channel['channel_id'], $x['hash']);
                $closeness = get_pconfig($channel['channel_id'], 'system', 'new_abook_closeness');
                if ($closeness === false) {
                    $closeness = 80;
                }
                $y = q("insert into abook ( abook_account, abook_channel, abook_closeness, abook_xchan, abook_created, abook_updated, abook_dob, abook_pending ) values ( %d, %d, %d, '%s', '%s', '%s', '%s', %d )", intval($channel['channel_account_id']), intval($channel['channel_id']), intval($closeness), dbesc($x['hash']), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($next_birthday), intval($automatic ? 0 : 1));
                if ($y) {
                    logger("New introduction received for {$channel['channel_name']}");
                    $new_perms = get_all_perms($channel['channel_id'], $x['hash']);
                    // Send a clone sync packet and a permissions update if permissions have changed
                    $new_connection = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 order by abook_created desc limit 1", dbesc($x['hash']), intval($channel['channel_id']));
                    if ($new_connection) {
                        if (!\Zotlabs\Access\Permissions::PermsCompare($new_perms, $previous_perms)) {
                            Zotlabs\Daemon\Master::Summon(array('Notifier', 'permission_create', $new_connection[0]['abook_id']));
                        }
                        Zotlabs\Lib\Enotify::submit(array('type' => NOTIFY_INTRO, 'from_xchan' => $x['hash'], 'to_xchan' => $channel['channel_hash'], 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id']));
                        if (intval($permissions['view_stream'])) {
                            if (intval(get_pconfig($channel['channel_id'], 'perm_limits', 'send_stream') & PERMS_PENDING) || !intval($new_connection[0]['abook_pending'])) {
                                Zotlabs\Daemon\Master::Summon(array('Onepoll', $new_connection[0]['abook_id']));
                            }
                        }
                        /** If there is a default group for this channel, add this connection to it */
                        $default_group = $channel['channel_default_group'];
                        if ($default_group) {
                            require_once 'include/group.php';
                            $g = group_rec_byhash($channel['channel_id'], $default_group);
                            if ($g) {
                                group_add_member($channel['channel_id'], '', $x['hash'], $g['id']);
                            }
                        }
                        unset($new_connection[0]['abook_id']);
                        unset($new_connection[0]['abook_account']);
                        unset($new_connection[0]['abook_channel']);
                        $abconfig = load_abconfig($channel['channel_id'], $new_connection['abook_xchan']);
                        if ($abconfig) {
                            $new_connection['abconfig'] = $abconfig;
                        }
                        build_sync_packet($channel['channel_id'], array('abook' => $new_connection));
                    }
                }
            }
        }
        return true;
    }
    return false;
}
コード例 #13
0
ファイル: deliver.php プロジェクト: kenrestivo/hubzilla
function deliver_run($argv, $argc)
{
    cli_startup();
    $a = get_app();
    if ($argc < 2) {
        return;
    }
    logger('deliver: invoked: ' . print_r($argv, true), LOGGER_DATA);
    for ($x = 1; $x < $argc; $x++) {
        $dresult = null;
        $r = q("select * from outq where outq_hash = '%s' limit 1", dbesc($argv[$x]));
        if ($r) {
            /**
             * Check to see if we have any recent communications with this hub (in the last month).
             * If not, reduce the outq_priority.
             */
            $h = parse_url($r[0]['outq_posturl']);
            if ($h) {
                $base = $h['scheme'] . '://' . $h['host'] . ($h['port'] ? ':' . $h['port'] : '');
                if ($base !== z_root()) {
                    $y = q("select site_update, site_dead from site where site_url = '%s' ", dbesc($base));
                    if ($y) {
                        if (intval($y[0]['site_dead'])) {
                            q("delete from outq where outq_posturl = '%s'", dbesc($r[0]['outq_posturl']));
                            logger('dead site ignored ' . $base);
                            continue;
                        }
                        if ($y[0]['site_update'] < datetime_convert('UTC', 'UTC', 'now - 1 month')) {
                            q("update outq set outq_priority = %d where outq_hash = '%s'", intval($r[0]['outq_priority'] + 10), dbesc($r[0]['outq_hash']));
                            logger('immediate delivery deferred for site ' . $base);
                            continue;
                        }
                    } else {
                        // zot sites should all have a site record, unless they've been dead for as long as
                        // your site has existed. Since we don't know for sure what these sites are,
                        // call them unknown
                        q("insert into site (site_url, site_update, site_dead, site_type) values ('%s','%s',0,%d) ", dbesc($base), dbesc(datetime_convert()), intval($r[0]['outq_driver'] === 'post' ? SITE_TYPE_NOTZOT : SITE_TYPE_UNKNOWN));
                    }
                }
            }
            // "post" queue driver - used for diaspora and friendica-over-diaspora communications.
            if ($r[0]['outq_driver'] === 'post') {
                $result = z_post_url($r[0]['outq_posturl'], $r[0]['outq_msg']);
                if ($result['success'] && $result['return_code'] < 300) {
                    logger('deliver: queue post success to ' . $r[0]['outq_posturl'], LOGGER_DEBUG);
                    q("update site set site_update = '%s', site_dead = 0 where site_url = '%s' ", dbesc(datetime_convert()), dbesc($site_url));
                    q("update dreport set status = '%s', dreport_time = '%s' where dreport_queue = '%s' limit 1", dbesc('accepted for delivery'), dbesc(datetime_convert()), dbesc($argv[$x]));
                    $y = q("delete from outq where outq_hash = '%s'", dbesc($argv[$x]));
                } else {
                    logger('deliver: queue post returned ' . $result['return_code'] . ' from ' . $r[0]['outq_posturl'], LOGGER_DEBUG);
                    $y = q("update outq set outq_updated = '%s' where outq_hash = '%s'", dbesc(datetime_convert()), dbesc($argv[$x]));
                }
                continue;
            }
            $notify = json_decode($r[0]['outq_notify'], true);
            // Check if this is a conversation request packet. It won't have outq_msg
            // but will be an encrypted packet - so will need to be handed off to
            // web delivery rather than processed inline.
            $sendtoweb = false;
            if (array_key_exists('iv', $notify) && !$r[0]['outq_msg']) {
                $sendtoweb = true;
            }
            if ($r[0]['outq_posturl'] === z_root() . '/post' && !$sendtoweb) {
                logger('deliver: local delivery', LOGGER_DEBUG);
                // local delivery
                // we should probably batch these and save a few delivery processes
                if ($r[0]['outq_msg']) {
                    $m = json_decode($r[0]['outq_msg'], true);
                    if (array_key_exists('message_list', $m)) {
                        foreach ($m['message_list'] as $mm) {
                            $msg = array('body' => json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify, 'message' => $mm)))));
                            zot_import($msg, z_root());
                        }
                    } else {
                        $msg = array('body' => json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify, 'message' => $m)))));
                        $dresult = zot_import($msg, z_root());
                    }
                    $r = q("delete from outq where outq_hash = '%s'", dbesc($argv[$x]));
                    if ($dresult && is_array($dresult)) {
                        foreach ($dresult as $xx) {
                            if (is_array($xx) && array_key_exists('message_id', $xx)) {
                                q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s','%s','%s','%s','%s' ) ", dbesc($xx['message_id']), dbesc($xx['location']), dbesc($xx['recipient']), dbesc($xx['status']), dbesc(datetime_convert($xx['date'])), dbesc($xx['sender']));
                            }
                        }
                    }
                    q("delete from dreport where dreport_queue = '%s' limit 1", dbesc($argv[$x]));
                }
            } else {
                logger('deliver: dest: ' . $r[0]['outq_posturl'], LOGGER_DEBUG);
                $result = zot_zot($r[0]['outq_posturl'], $r[0]['outq_notify']);
                if ($result['success']) {
                    logger('deliver: remote zot delivery succeeded to ' . $r[0]['outq_posturl']);
                    zot_process_response($r[0]['outq_posturl'], $result, $r[0]);
                } else {
                    logger('deliver: remote zot delivery failed to ' . $r[0]['outq_posturl']);
                    $y = q("update outq set outq_updated = '%s' where outq_hash = '%s'", dbesc(datetime_convert()), dbesc($argv[$x]));
                }
            }
        }
    }
}
コード例 #14
0
ファイル: network.php プロジェクト: Mauru/red
/**
 * @function z_post_url
 * @param string $url
 *    URL to post
 * @param mixed $params
 *   The full data to post in a HTTP "POST" operation. This parameter can 
 *   either be passed as a urlencoded string like 'para1=val1&para2=val2&...' 
 *   or as an array with the field name as key and field data as value. If value 
 *   is an array, the Content-Type header will be set to multipart/form-data. 
 * @param int $redirects = 0
 *    internal use, recursion counter
 * @param array $opts (optional parameters)
 *    'accept_content' => supply Accept: header with 'accept_content' as the value
 *    'timeout' => int seconds, default system config value or 60 seconds
 *    'http_auth' => username:password
 *    'novalidate' => do not validate SSL certs, default is to validate using our CA list
 *    
 * @returns array
 *    'return_code' => HTTP return code or 0 if timeout or failure
 *    'success' => boolean true (if HTTP 2xx result) or false
 *    'header' => HTTP headers
 *    'body' => fetched content
 */
function z_post_url($url, $params, $redirects = 0, $opts = array())
{
    $ret = array('return_code' => 0, 'success' => false, 'header' => "", 'body' => "");
    $ch = curl_init($url);
    if ($redirects > 8 || !$ch) {
        return ret;
    }
    @curl_setopt($ch, CURLOPT_HEADER, true);
    @curl_setopt($ch, CURLOPT_CAINFO, get_capath());
    @curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    @curl_setopt($ch, CURLOPT_POST, 1);
    @curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
    @curl_setopt($ch, CURLOPT_USERAGENT, "Red");
    $ciphers = @get_config('system', 'curl_ssl_ciphers');
    if ($ciphers) {
        @curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, $ciphers);
    }
    if (x($opts, 'accept_content')) {
        @curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept: " . $opts['accept_content']));
    }
    if (x($opts, 'headers')) {
        @curl_setopt($ch, CURLOPT_HTTPHEADER, $opts['headers']);
    }
    if (x($opts, 'timeout') && intval($opts['timeout'])) {
        @curl_setopt($ch, CURLOPT_TIMEOUT, $opts['timeout']);
    } else {
        $curl_time = intval(get_config('system', 'curl_timeout'));
        @curl_setopt($ch, CURLOPT_TIMEOUT, $curl_time !== false ? $curl_time : 60);
    }
    if (x($opts, 'http_auth')) {
        // "username" . ':' . "password"
        @curl_setopt($ch, CURLOPT_USERPWD, $opts['http_auth']);
    }
    @curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, x($opts, 'novalidate') && intval($opts['novalidate']) ? false : true);
    $prx = get_config('system', 'proxy');
    if (strlen($prx)) {
        @curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
        @curl_setopt($ch, CURLOPT_PROXY, $prx);
        $prxusr = get_config('system', 'proxyuser');
        if (strlen($prxusr)) {
            @curl_setopt($ch, CURLOPT_PROXYUSERPWD, $prxusr);
        }
    }
    // don't let curl abort the entire application
    // if it throws any errors.
    $s = @curl_exec($ch);
    $base = $s;
    $curl_info = @curl_getinfo($ch);
    $http_code = $curl_info['http_code'];
    $header = '';
    // Pull out multiple headers, e.g. proxy and continuation headers
    // allow for HTTP/2.x without fixing code
    while (preg_match('/^HTTP\\/[1-2].+? [1-5][0-9][0-9]/', $base)) {
        $chunk = substr($base, 0, strpos($base, "\r\n\r\n") + 4);
        $header .= $chunk;
        $base = substr($base, strlen($chunk));
    }
    if ($http_code == 301 || $http_code == 302 || $http_code == 303 || $http_code == 307 || $http_code == 308) {
        $matches = array();
        preg_match('/(Location:|URI:)(.*?)\\n/', $header, $matches);
        $newurl = trim(array_pop($matches));
        if (strpos($newurl, '/') === 0) {
            $newurl = $url . $newurl;
        }
        $url_parsed = @parse_url($newurl);
        if (isset($url_parsed)) {
            curl_close($ch);
            if ($http_code == 303) {
                return z_fetch_url($newurl, false, $redirects++, $opts);
            } else {
                return z_post_url($newurl, $params, $redirects++, $opts);
            }
        }
    }
    $rc = intval($http_code);
    $ret['return_code'] = $rc;
    $ret['success'] = $rc >= 200 && $rc <= 299 ? true : false;
    if (!$ret['success']) {
        $ret['error'] = curl_error($ch);
        $ret['debug'] = $curl_info;
        logger('z_post_url: error: ' . $url . ': ' . $ret['error'], LOGGER_DEBUG);
        logger('z_post_url: debug: ' . print_r($curl_info, true), LOGGER_DATA);
    }
    $ret['body'] = substr($s, strlen($header));
    $ret['header'] = $header;
    curl_close($ch);
    return $ret;
}
コード例 #15
0
function jappixmini_cron(&$a, $d)
{
    require_once 'include/Contact.php';
    // For autosubscribe/autoapprove, we need to maintain a list of jabber addresses of our contacts.
    set_config("jappixmini", "last_cron_execution", $d);
    // go through list of users with jabber enabled
    $users = q("SELECT uid FROM pconfig WHERE cat = 'jappixmini' AND ( k = 'autosubscribe' OR k = 'autoapprove') AND v = '1' group by uid ");
    logger("jappixmini: Update list of contacts' jabber accounts for " . count($users) . " users.");
    if (!count($users)) {
        return;
    }
    foreach ($users as $row) {
        $uid = $row["uid"];
        // for each user, go through list of contacts
        $rand = db_getfunc('rand');
        $contacts = q("SELECT * FROM `abook` left join xchan on abook_xchan = xchan_hash WHERE `abook_channel`=%d AND not (abook_flags & %d) > 0 order by {$rand}", intval($uid), intval(ABOOK_FLAG_SELF));
        $channel = channelx_by_n($uid);
        if (!$channel || !$contacts) {
            continue;
        }
        foreach ($contacts as $contact_row) {
            $xchan_hash = $contact_row["abook_xchan"];
            $pubkey = $contact_row["xchan_pubkey"];
            // check if jabber address already present
            $present = get_pconfig($uid, "jappixmini", "id:" . $xchan_hash);
            $now = intval(time());
            if ($present) {
                // $present has format "timestamp:jabber_address"
                $p = strpos($present, ":");
                $timestamp = intval(substr($present, 0, $p));
                // do not re-retrieve jabber address if last retrieval
                // is not older than a week
                if ($now - $timestamp < 3600 * 24 * 7) {
                    continue;
                }
            }
            logger('jappixmini: checking ' . $contact_row['xchan_name'] . ' for channel ' . $channel['channel_name']);
            // construct base retrieval address
            $pos = strpos($contact_row['xchan_connurl'], "/poco/");
            if ($pos === false) {
                continue;
            }
            $url = substr($contact_row['xchan_connurl'], 0, $pos) . "/jappixmini?f=";
            // construct own address
            $username = get_pconfig($uid, 'jappixmini', 'username');
            if (!$username) {
                continue;
            }
            $server = get_pconfig($uid, 'jappixmini', 'server');
            if (!$server) {
                continue;
            }
            $address = $username . "@" . $server;
            // sign address
            $signed_address = "";
            openssl_private_encrypt($address, $signed_address, $channel['channel_prvkey']);
            // construct request url
            $signed_address_hex = base64url_encode($signed_address);
            $postvars = array('address' => $signed_address, 'requestor' => $channel['xchan_hash'], 'requestee' => $contact_row['xchan_hash']);
            try {
                // send request
                $answer_json = z_post_url($url, $postvars);
                logger('jappixmini: url response: ' . print_r($answer_json, true));
                if (!$answer_json['success']) {
                    logger('jappixmini: failed z_post_url ' . $url);
                    throw new Exception();
                }
                if ($answer_json['return_code'] == 404) {
                    logger('jappixmini: failed z_post_url (404)' . $url);
                    throw new Exception();
                }
                // parse answer
                $answer = json_decode($answer_json['body'], true);
                if ($answer['status'] != "ok") {
                    throw new Exception();
                }
                $address = base64url_decode($answer['address']);
                if (!$address) {
                    throw new Exception();
                }
                // decrypt address
                $decrypted_address = "";
                openssl_public_decrypt($address, $decrypted_address, $pubkey);
                if (!$decrypted_address) {
                    throw new Exception();
                }
            } catch (Exception $e) {
                $decrypted_address = "";
            }
            // save address
            set_pconfig($uid, "jappixmini", "id:" . $xchan_hash, "{$now}:{$decrypted_address}");
        }
    }
}
コード例 #16
0
ファイル: salmon.php プロジェクト: anmol26s/hubzilla-yunohost
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);
    $data_type = 'application/atom+xml';
    $encoding = 'base64url';
    $algorithm = 'RSA-SHA256';
    $keyhash = base64url_encode(hash('sha256', salmon_key($owner['channel_pubkey'])), true);
    // precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods
    $precomputed = '.YXBwbGljYXRpb24vYXRvbSt4bWw=.YmFzZTY0dXJs.UlNBLVNIQTI1Ng==';
    $signature = base64url_encode(rsa_sign(str_replace('=', '', $data . $precomputed), $owner['channel_prvkey']));
    $signature2 = base64url_encode(rsa_sign($data . $precomputed, $owner['channel_prvkey']));
    $signature3 = base64url_encode(rsa_sign($data, $owner['channel_prvkey']));
    $salmon_tpl = get_markup_template('magicsig.tpl');
    $salmon = replace_macros($salmon_tpl, array('$data' => $data, '$encoding' => $encoding, '$algorithm' => $algorithm, '$keyhash' => $keyhash, '$signature' => $signature));
    // slap them
    $redirects = 0;
    $ret = z_post_url($url, $salmon, $redirects, array('headers' => array('Content-type: application/magic-envelope+xml', 'Content-length: ' . strlen($salmon))));
    $return_code = $ret['return_code'];
    // check for success, e.g. 2xx
    if ($return_code > 299) {
        logger('compliant salmon failed. Falling back to status.net hack2');
        // Entirely likely that their salmon implementation is
        // non-compliant. Let's try once more, this time only signing
        // the data, without stripping '=' chars
        $salmon = replace_macros($salmon_tpl, array('$data' => $data, '$encoding' => $encoding, '$algorithm' => $algorithm, '$keyhash' => $keyhash, '$signature' => $signature2));
        $redirects = 0;
        $ret = z_post_url($url, $salmon, $redirects, array('headers' => array('Content-type: application/magic-envelope+xml', 'Content-length: ' . strlen($salmon))));
        $return_code = $ret['return_code'];
        if ($return_code > 299) {
            logger('compliant salmon failed. Falling back to status.net hack3');
            // Entirely likely that their salmon implementation is
            // non-compliant. Let's try once more, this time only signing
            // the data, without the precomputed blob
            $salmon = replace_macros($salmon_tpl, array('$data' => $data, '$encoding' => $encoding, '$algorithm' => $algorithm, '$keyhash' => $keyhash, '$signature' => $signature3));
            $redirects = 0;
            $ret = z_post_url($url, $salmon, $redirects, array('headers' => array('Content-type: application/magic-envelope+xml', 'Content-length: ' . strlen($salmon))));
            $return_code = $ret['return_code'];
        }
    }
    logger('slapper for ' . $url . ' returned ' . $return_code);
    if (!$return_code) {
        return -1;
    }
    if ($return_code == 503 && stristr($ret['header'], 'retry-after')) {
        return -1;
    }
    return $return_code >= 200 && $return_code < 300 ? 0 : 1;
}
コード例 #17
0
function libertree_send(&$a, &$b)
{
    if (!is_item_normal($b) || $b['item_private'] || $b['created'] !== $b['edited']) {
        return;
    }
    if (!perm_is_allowed($b['uid'], '', 'view_stream')) {
        return;
    }
    if (!strstr($b['postopts'], 'libertree')) {
        return;
    }
    if ($b['parent'] != $b['id']) {
        return;
    }
    logger('libertree xpost invoked');
    $ltree_api_token = get_pconfig($b['uid'], 'libertree', 'libertree_api_token');
    $ltree_url = get_pconfig($b['uid'], 'libertree', 'libertree_url');
    $ltree_blog = "{$ltree_url}/api/v1/posts/create/?token={$ltree_api_token}";
    $ltree_source = "[" . $a->config['system']['sitename'] . "](" . $a->get_baseurl() . ")";
    // $ltree_source = "RedMatrix";
    logger('sitename: ' . print_r($ltree_source, true));
    if ($ltree_url && $ltree_api_token && $ltree_blog && $ltree_source) {
        require_once 'include/bb2diaspora.php';
        $tag_arr = array();
        $tags = '';
        $x = preg_match_all('/\\#\\[(.*?)\\](.*?)\\[/', $b['tag'], $matches, PREG_SET_ORDER);
        if ($x) {
            foreach ($matches as $mtch) {
                $tag_arr[] = $mtch[2];
            }
        }
        if (count($tag_arr)) {
            $tags = implode(',', $tag_arr);
        }
        $title = $b['title'];
        $body = $b['body'];
        // Insert a newline before and after a quote
        $body = str_ireplace("[quote", "\n\n[quote", $body);
        $body = str_ireplace("[/quote]", "[/quote]\n\n", $body);
        // Removal of tags and mentions
        // #-tags
        $body = preg_replace('/#\\[url\\=(\\w+.*?)\\](\\w+.*?)\\[\\/url\\]/i', '#$2', $body);
        // @-mentions
        $body = preg_replace('/@\\[url\\=(\\w+.*?)\\](\\w+.*?)\\[\\/url\\]/i', '@$2', $body);
        // remove multiple newlines
        do {
            $oldbody = $body;
            $body = str_replace("\n\n\n", "\n\n", $body);
        } while ($oldbody != $body);
        // convert to markdown
        $body = bb2diaspora($body, false, false);
        // Adding the title
        if (strlen($title)) {
            $body = "## " . html_entity_decode($title) . "\n\n" . $body;
        }
        $params = array('text' => $body, 'source' => $ltree_source);
        $level = 0;
        $result = z_post_url($ltree_blog, $params, $level, array('novalidate' => true));
        logger('libertree: ' . print_r($result, true));
    }
}
コード例 #18
0
function rtof_post_hook(&$a, &$b)
{
    /**
     * Post to Friendica
     */
    // for now, just top level posts.
    if ($b['mid'] != $b['parent_mid']) {
        return;
    }
    if (!is_item_normal($b) || $b['item_private'] || $b['created'] !== $b['edited']) {
        return;
    }
    if (!perm_is_allowed($b['uid'], '', 'view_stream')) {
        return;
    }
    if (!strstr($b['postopts'], 'rtof')) {
        return;
    }
    logger('Red-to-Friendica post invoked');
    load_pconfig($b['uid'], 'rtof');
    $api = get_pconfig($b['uid'], 'rtof', 'baseapi');
    if (substr($api, -1, 1) != '/') {
        $api .= '/';
    }
    $username = get_pconfig($b['uid'], 'rtof', 'username');
    $password = z_unobscure(get_pconfig($b['uid'], 'rtof', 'password'));
    $msg = $b['body'];
    $postdata = array('status' => $b['body'], 'title' => $b['title'], 'message_id' => $b['mid'], 'source' => 'Red Matrix');
    if (strlen($b['body'])) {
        $ret = z_post_url($api . 'statuses/update', $postdata, 0, array('http_auth' => $username . ':' . $password, 'novalidate' => 1));
        if ($ret['success']) {
            logger('rtof: returns: ' . print_r($ret['body'], true));
        } else {
            logger('rtof: z_post_url failed: ' . print_r($ret['debug'], true));
        }
    }
}
コード例 #19
0
ファイル: queue.php プロジェクト: kenrestivo/hubzilla
function queue_run($argv, $argc)
{
    cli_startup();
    global $a;
    require_once 'include/items.php';
    require_once 'include/bbcode.php';
    if (argc() > 1) {
        $queue_id = argv(1);
    } else {
        $queue_id = 0;
    }
    $deadguys = array();
    logger('queue: start');
    $r = q("select outq_posturl from outq where outq_created < %s - INTERVAL %s", db_utcnow(), db_quoteinterval('3 DAY'));
    if ($r) {
        foreach ($r as $rr) {
            $site_url = '';
            $h = parse_url($rr['outq_posturl']);
            $desturl = $h['scheme'] . '://' . $h['host'] . ($h['port'] ? ':' . $h['port'] : '');
            q("update site set site_dead = 1 where site_dead = 0 and site_url = '%s' and site_update < %s - INTERVAL %s", dbesc($desturl), db_utcnow(), db_quoteinterval('1 MONTH'));
        }
    }
    $r = q("DELETE FROM outq WHERE outq_created < %s - INTERVAL %s", db_utcnow(), db_quoteinterval('3 DAY'));
    if ($queue_id) {
        $r = q("SELECT * FROM outq WHERE outq_hash = '%s' LIMIT 1", dbesc($queue_id));
    } else {
        // For the first 12 hours we'll try to deliver every 15 minutes
        // After that, we'll only attempt delivery once per hour.
        // This currently only handles the default queue drivers ('zot' or '') which we will group by posturl
        // so that we don't start off a thousand deliveries for a couple of dead hubs.
        // The zot driver will deliver everything destined for a single hub once contact is made (*if* contact is made).
        // Other drivers will have to do something different here and may need their own query.
        // Note: this requires some tweaking as new posts to long dead hubs once a day will keep them in the
        // "every 15 minutes" category. We probably need to prioritise them when inserted into the queue
        // or just prior to this query based on recent and long-term delivery history. If we have good reason to believe
        // the site is permanently down, there's no reason to attempt delivery at all, or at most not more than once
        // or twice a day.
        // FIXME: can we sort postgres on outq_priority and maintain the 'distinct' ?
        // The order by max(outq_priority) might be a dodgy query because of the group by.
        // The desired result is to return a sequence in the order most likely to be delivered in this run.
        // If a hub has already been sitting in the queue for a few days, they should be delivered last;
        // hence every failure should drop them further down the priority list.
        if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
            $prefix = 'DISTINCT ON (outq_posturl)';
            $suffix = 'ORDER BY outq_posturl';
        } else {
            $prefix = '';
            $suffix = 'GROUP BY outq_posturl ORDER BY max(outq_priority)';
        }
        $r = q("SELECT {$prefix} * FROM outq WHERE outq_delivered = 0 and (( outq_created > %s - INTERVAL %s and outq_updated < %s - INTERVAL %s ) OR ( outq_updated < %s - INTERVAL %s )) {$suffix}", db_utcnow(), db_quoteinterval('12 HOUR'), db_utcnow(), db_quoteinterval('15 MINUTE'), db_utcnow(), db_quoteinterval('1 HOUR'));
    }
    if (!$r) {
        return;
    }
    foreach ($r as $rr) {
        if (in_array($rr['outq_posturl'], $deadguys)) {
            continue;
        }
        if ($rr['outq_driver'] === 'post') {
            $result = z_post_url($rr['outq_posturl'], $rr['outq_msg']);
            if ($result['success'] && $result['return_code'] < 300) {
                logger('queue: queue post success to ' . $rr['outq_posturl'], LOGGER_DEBUG);
                $y = q("delete from outq where outq_hash = '%s'", dbesc($rr['ouq_hash']));
            } else {
                logger('queue: queue post returned ' . $result['return_code'] . ' from ' . $rr['outq_posturl'], LOGGER_DEBUG);
                $y = q("update outq set outq_updated = '%s', outq_priority = outq_priority + 10 where outq_hash = '%s'", dbesc(datetime_convert()), dbesc($rr['outq_hash']));
            }
            continue;
        }
        $result = zot_zot($rr['outq_posturl'], $rr['outq_notify']);
        if ($result['success']) {
            logger('queue: deliver zot success to ' . $rr['outq_posturl'], LOGGER_DEBUG);
            zot_process_response($rr['outq_posturl'], $result, $rr);
        } else {
            $deadguys[] = $rr['outq_posturl'];
            logger('queue: deliver zot returned ' . $result['return_code'] . ' from ' . $rr['outq_posturl'], LOGGER_DEBUG);
            $y = q("update outq set outq_updated = '%s', outq_priority = outq_priority + 10 where outq_hash = '%s'", dbesc(datetime_convert()), dbesc($rr['outq_hash']));
        }
    }
}
コード例 #20
0
ファイル: dwpost.php プロジェクト: phellmes/hubzilla-addons
function dwpost_send(&$a, &$b)
{
    if (!is_item_normal($b) || $b['item_private'] || $b['created'] !== $b['edited']) {
        return;
    }
    if (!perm_is_allowed($b['uid'], '', 'view_stream')) {
        return;
    }
    if (!strstr($b['postopts'], 'dwpost')) {
        return;
    }
    if ($b['parent'] != $b['id']) {
        return;
    }
    // dreamwidth post in the LJ user's timezone.
    // Hopefully the person's Friendica account
    // will be set to the same thing.
    $tz = 'UTC';
    $x = q("select channel_timezone from channel where channel_id = %d limit 1", intval($b['uid']));
    if ($x && strlen($x[0]['channel_timezone'])) {
        $tz = $x[0]['channel_timezone'];
    }
    $dw_username = get_pconfig($b['uid'], 'dwpost', 'dw_username');
    $dw_password = z_unobscure(get_pconfig($b['uid'], 'dwpost', 'dw_password'));
    $dw_blog = 'http://www.dreamwidth.org/interface/xmlrpc';
    if ($dw_username && $dw_password && $dw_blog) {
        require_once 'include/bbcode.php';
        require_once 'include/datetime.php';
        $title = $b['title'];
        $post = bbcode($b['body']);
        $post = xmlify($post);
        $tags = dwpost_get_tags($b['tag']);
        $date = datetime_convert('UTC', $tz, $b['created'], 'Y-m-d H:i:s');
        $year = intval(substr($date, 0, 4));
        $mon = intval(substr($date, 5, 2));
        $day = intval(substr($date, 8, 2));
        $hour = intval(substr($date, 11, 2));
        $min = intval(substr($date, 14, 2));
        $xml = <<<EOT
<?xml version="1.0" encoding="utf-8"?>
<methodCall><methodName>LJ.XMLRPC.postevent</methodName>
<params><param>
<value><struct>
<member><name>year</name><value><int>{$year}</int></value></member>
<member><name>mon</name><value><int>{$mon}</int></value></member>
<member><name>day</name><value><int>{$day}</int></value></member>
<member><name>hour</name><value><int>{$hour}</int></value></member>
<member><name>min</name><value><int>{$min}</int></value></member>
<member><name>event</name><value><string>{$post}</string></value></member>
<member><name>username</name><value><string>{$dw_username}</string></value></member>
<member><name>password</name><value><string>{$dw_password}</string></value></member>
<member><name>subject</name><value><string>{$title}</string></value></member>
<member><name>lineendings</name><value><string>unix</string></value></member>
<member><name>ver</name><value><int>1</int></value></member>
<member><name>props</name>
<value><struct>
<member><name>useragent</name><value><string>Friendica</string></value></member>
<member><name>taglist</name><value><string>{$tags}</string></value></member>
</struct></value></member>
</struct></value>
</param></params>
</methodCall>

EOT;
        logger('dwpost: data: ' . $xml, LOGGER_DATA);
        if ($dw_blog !== 'test') {
            $x = z_post_url($dw_blog, $xml, array('headers' => array("Content-Type: text/xml")));
        }
        logger('posted to dreamwidth: ' . print_r($x, true), LOGGER_DEBUG);
    }
}
コード例 #21
0
ファイル: queue_fn.php プロジェクト: royalterra/hubzilla
function queue_deliver($outq, $immediate = false)
{
    $base = null;
    $h = parse_url($outq['outq_posturl']);
    if ($h) {
        $base = $h['scheme'] . '://' . $h['host'] . ($h['port'] ? ':' . $h['port'] : '');
    }
    if ($base && $base !== z_root() && $immediate) {
        $y = q("select site_update, site_dead from site where site_url = '%s' ", dbesc($base));
        if ($y) {
            if (intval($y[0]['site_dead'])) {
                remove_queue_by_posturl($outq['outq_posturl']);
                logger('dead site ignored ' . $base);
                return;
            }
            if ($y[0]['site_update'] < datetime_convert('UTC', 'UTC', 'now - 1 month')) {
                update_queue_item($outq['outq_hash'], 10);
                logger('immediate delivery deferred for site ' . $base);
                return;
            }
        } else {
            // zot sites should all have a site record, unless they've been dead for as long as
            // your site has existed. Since we don't know for sure what these sites are,
            // call them unknown
            q("insert into site (site_url, site_update, site_dead, site_type) values ('%s','%s',0,%d) ", dbesc($base), dbesc(datetime_convert()), intval($outq['outq_driver'] === 'post' ? SITE_TYPE_NOTZOT : SITE_TYPE_UNKNOWN));
        }
    }
    $arr = array('outq' => $outq, 'base' => $base, 'handled' => false, 'immediate' => $immediate);
    call_hooks('queue_deliver', $arr);
    if ($arr['handled']) {
        return;
    }
    // "post" queue driver - used for diaspora and friendica-over-diaspora communications.
    if ($outq['outq_driver'] === 'post') {
        $result = z_post_url($outq['outq_posturl'], $outq['outq_msg']);
        if ($result['success'] && $result['return_code'] < 300) {
            logger('deliver: queue post success to ' . $outq['outq_posturl'], LOGGER_DEBUG);
            if ($base) {
                q("update site set site_update = '%s', site_dead = 0 where site_url = '%s' ", dbesc(datetime_convert()), dbesc($base));
            }
            q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s' limit 1", dbesc('accepted for delivery'), dbesc(datetime_convert()), dbesc($outq['outq_hash']));
            remove_queue_item($outq['outq_hash']);
            // server is responding - see if anything else is going to this destination and is piled up
            // and try to send some more. We're relying on the fact that delivery_loop() results in an
            // immediate delivery otherwise we could get into a queue loop.
            if (!$immediate) {
                $x = q("select outq_hash from outq where outq_posturl = '%s' and outq_delivered = 0", dbesc($outq['outq_posturl']));
                $piled_up = array();
                if ($x) {
                    foreach ($x as $xx) {
                        $piled_up[] = $xx['outq_hash'];
                    }
                }
                if ($piled_up) {
                    delivery_loop($piled_up);
                }
            }
        } else {
            logger('deliver: queue post returned ' . $result['return_code'] . ' from ' . $outq['outq_posturl'], LOGGER_DEBUG);
            update_queue_item($outq['outq_posturl']);
        }
        return;
    }
    // normal zot delivery
    logger('deliver: dest: ' . $outq['outq_posturl'], LOGGER_DEBUG);
    $result = zot_zot($outq['outq_posturl'], $outq['outq_notify']);
    if ($result['success']) {
        logger('deliver: remote zot delivery succeeded to ' . $outq['outq_posturl']);
        zot_process_response($outq['outq_posturl'], $result, $outq);
    } else {
        logger('deliver: remote zot delivery failed to ' . $outq['outq_posturl']);
        logger('deliver: remote zot delivery fail data: ' . print_r($result, true), LOGGER_DATA);
        update_queue_item($outq['outq_hash'], 10);
    }
    return;
}
コード例 #22
0
ファイル: gnusoc.php プロジェクト: phellmes/hubzilla-addons
function gnusoc_queue_deliver(&$a, &$b)
{
    $outq = $b['outq'];
    if ($outq['outq_driver'] !== 'slap') {
        return;
    }
    $b['handled'] = true;
    $headers = array('Content-type: application/magic-envelope+xml', 'Content-length: ' . strlen($outq['outq_msg']));
    $counter = 0;
    $result = z_post_url($outq['outq_posturl'], $outq['outq_msg'], $counter, array('headers' => $headers, 'novalidate' => true));
    if ($result['success'] && $result['return_code'] < 300) {
        logger('slap_deliver: queue post success to ' . $outq['outq_posturl'], LOGGER_DEBUG);
        if ($b['base']) {
            q("update site set site_update = '%s', site_dead = 0 where site_url = '%s' ", dbesc(datetime_convert()), dbesc($b['base']));
        }
        q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s' limit 1", dbesc('accepted for delivery'), dbesc(datetime_convert()), dbesc($outq['outq_hash']));
        remove_queue_item($outq['outq_hash']);
    } else {
        logger('slap_deliver: queue post returned ' . $result['return_code'] . ' from ' . $outq['outq_posturl'], LOGGER_DEBUG);
        update_queue_item($outq['outq_hash']);
    }
    return;
}
コード例 #23
0
ファイル: zot.php プロジェクト: Mauru/red
/**
 * @function: zot_refresh($them, $channel = null, $force = false)
 *
 *   zot_refresh is typically invoked when somebody has changed permissions of a channel and they are notified
 *   to fetch new permissions via a finger/discovery operation. This may result in a new connection 
 *   (abook entry) being added to a local channel and it may result in auto-permissions being granted. 
 * 
 *   Friending in zot is accomplished by sending a refresh packet to a specific channel which indicates a
 *   permission change has been made by the sender which affects the target channel. The hub controlling
 *   the target channel does targetted discovery (a zot-finger request requesting permissions for the local
 *   channel). These are decoded here, and if necessary and abook structure (addressbook) is created to store
 *   the permissions assigned to this channel. 
 *   
 *   Initially these abook structures are created with a 'pending' flag, so that no reverse permissions are 
 *   implied until this is approved by the owner channel. A channel can also auto-populate permissions in 
 *   return and send back a refresh packet of its own. This is used by forum and group communication channels
 *   so that friending and membership in the channel's "club" is automatic. 
 * 
 * @param array $them => xchan structure of sender
 * @param array $channel => local channel structure of target recipient, required for "friending" operations
 *
 * @returns boolean true if successful, else false 
 */
function zot_refresh($them, $channel = null, $force = false)
{
    if (array_key_exists('xchan_network', $them) && $them['xchan_network'] !== 'zot') {
        logger('zot_refresh: not got zot. ' . $them['xchan_name']);
        return true;
    }
    logger('zot_refresh: them: ' . print_r($them, true), LOGGER_DATA);
    if ($channel) {
        logger('zot_refresh: channel: ' . print_r($channel, true), LOGGER_DATA);
    }
    if ($them['hubloc_url']) {
        $url = $them['hubloc_url'];
    } else {
        $r = q("select hubloc_url from hubloc where hubloc_hash = '%s' and ( hubloc_flags & %d ) limit 1", dbesc($them['xchan_hash']), intval(HUBLOC_FLAGS_PRIMARY));
        if ($r) {
            $url = $r[0]['hubloc_url'];
        }
    }
    if (!$url) {
        logger('zot_refresh: no url');
        return false;
    }
    $postvars = array();
    if ($channel) {
        $postvars['target'] = $channel['channel_guid'];
        $postvars['target_sig'] = $channel['channel_guid_sig'];
        $postvars['key'] = $channel['channel_pubkey'];
    }
    if (array_key_exists('xchan_addr', $them) && $them['xchan_addr']) {
        $postvars['address'] = $them['xchan_addr'];
    }
    if (array_key_exists('xchan_hash', $them) && $them['xchan_hash']) {
        $postvars['guid_hash'] = $them['xchan_hash'];
    }
    if (array_key_exists('xchan_guid', $them) && $them['xchan_guid'] && array_key_exists('xchan_guid_sig', $them) && $them['xchan_guid_sig']) {
        $postvars['guid'] = $them['xchan_guid'];
        $postvars['guid_sig'] = $them['xchan_guid_sig'];
    }
    $rhs = '/.well-known/zot-info';
    $result = z_post_url($url . $rhs, $postvars);
    logger('zot_refresh: zot-info: ' . print_r($result, true), LOGGER_DATA);
    if ($result['success']) {
        $j = json_decode($result['body'], true);
        if (!($j && $j['success'])) {
            logger('zot_refresh: result not decodable');
            return false;
        }
        $x = import_xchan($j, $force ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED);
        if (!$x['success']) {
            return false;
        }
        $their_perms = 0;
        if ($channel) {
            $global_perms = get_perms();
            if ($j['permissions']['data']) {
                $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'];
            }
            $connected_set = false;
            if ($permissions && is_array($permissions)) {
                foreach ($permissions as $k => $v) {
                    // The connected permission means you are in their address book
                    if ($k === 'connected') {
                        $connected_set = intval($v);
                        continue;
                    }
                    if ($v && array_key_exists($k, $global_perms)) {
                        $their_perms = $their_perms | intval($global_perms[$k][1]);
                    }
                }
            }
            $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d and not (abook_flags & %d) limit 1", dbesc($x['hash']), intval($channel['channel_id']), intval(ABOOK_FLAG_SELF));
            if (array_key_exists('profile', $j) && array_key_exists('next_birthday', $j['profile'])) {
                $next_birthday = datetime_convert('UTC', 'UTC', $j['profile']['next_birthday']);
            } else {
                $next_birthday = NULL_DATE;
            }
            if ($r) {
                // if the dob is the same as what we have stored (disregarding the year), keep the one
                // we have as we may have updated the year after sending a notification; and resetting
                // to the one we just received would cause us to create duplicated events.
                if (substr($r[0]['abook_dob'], 5) == substr($next_birthday, 5)) {
                    $next_birthday = $r[0]['abook_dob'];
                }
                $current_abook_connected = $r[0]['abook_flags'] & ABOOK_FLAG_UNCONNECTED ? 0 : 1;
                $y = q("update abook set abook_their_perms = %d, abook_dob = '%s'\n\t\t\t\t\twhere abook_xchan = '%s' and abook_channel = %d \n\t\t\t\t\tand not (abook_flags & %d) limit 1", intval($their_perms), dbesc($next_birthday), dbesc($x['hash']), intval($channel['channel_id']), intval(ABOOK_FLAG_SELF));
                //				if(($connected_set === 0 || $connected_set === 1) && ($connected_set !== $current_abook_unconnected)) {
                // if they are in your address book but you aren't in theirs, and/or this does not
                // match your current connected state setting, toggle it.
                //					$y1 = q("update abook set abook_flags = (abook_flags ^ %d)
                //						where abook_xchan = '%s' and abook_channel = %d
                //						and not (abook_flags & %d) limit 1",
                //						intval(ABOOK_FLAG_UNCONNECTED),
                //						dbesc($x['hash']),
                //						intval($channel['channel_id']),
                //						intval(ABOOK_FLAG_SELF)
                //					);
                //				}
                if (!$y) {
                    logger('abook update failed');
                } else {
                    // if we were just granted read stream permission and didn't have it before, try to pull in some posts
                    if (!($r[0]['abook_their_perms'] & PERMS_R_STREAM) && $their_perms & PERMS_R_STREAM) {
                        proc_run('php', 'include/onepoll.php', $r[0]['abook_id']);
                    }
                }
            } else {
                $default_perms = 0;
                // look for default permissions to apply in return - e.g. auto-friend
                $z = q("select * from abook where abook_channel = %d and (abook_flags & %d) limit 1", intval($channel['channel_id']), intval(ABOOK_FLAG_SELF));
                if ($z) {
                    $default_perms = intval($z[0]['abook_my_perms']);
                }
                // Keep original perms to check if we need to notify them
                $previous_perms = get_all_perms($channel['channel_id'], $x['hash']);
                $y = q("insert into abook ( abook_account, abook_channel, abook_xchan, abook_their_perms, abook_my_perms, abook_created, abook_updated, abook_dob, abook_flags ) values ( %d, %d, '%s', %d, %d, '%s', '%s', '%s', %d )", intval($channel['channel_account_id']), intval($channel['channel_id']), dbesc($x['hash']), intval($their_perms), intval($default_perms), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($next_birthday), intval($default_perms ? 0 : ABOOK_FLAG_PENDING));
                if ($y) {
                    logger("New introduction received for {$channel['channel_name']}");
                    $new_perms = get_all_perms($channel['channel_id'], $x['hash']);
                    if ($new_perms != $previous_perms) {
                        // Send back a permissions update if permissions have changed
                        $z = q("select * from abook where abook_xchan = '%s' and abook_channel = %d and not (abook_flags & %d) limit 1", dbesc($x['hash']), intval($channel['channel_id']), intval(ABOOK_FLAG_SELF));
                        if ($z) {
                            proc_run('php', 'include/notifier.php', 'permission_update', $z[0]['abook_id']);
                        }
                    }
                    $new_connection = q("select abook_id, abook_flags from abook where abook_channel = %d and abook_xchan = '%s' order by abook_created desc limit 1", intval($channel['channel_id']), dbesc($x['hash']));
                    if ($new_connection) {
                        require_once 'include/enotify.php';
                        notification(array('type' => NOTIFY_INTRO, 'from_xchan' => $x['hash'], 'to_xchan' => $channel['channel_hash'], 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id']));
                    }
                    if ($new_connection && $their_perms & PERMS_R_STREAM) {
                        if ($channel['channel_w_stream'] & PERMS_PENDING || !($new_connection[0]['abook_flags'] & ABOOK_FLAG_PENDING)) {
                            proc_run('php', 'include/onepoll.php', $new_connection[0]['abook_id']);
                        }
                    }
                }
            }
        }
        return true;
    }
    return false;
}