示例#1
1
 /**
  * Send a multipart/alternative message with Text and HTML versions
  *
  * @param fromName			name of the sender
  * @param fromEmail			email fo the sender
  * @param replyTo			replyTo address to direct responses
  * @param toEmail			destination email address
  * @param messageSubject	subject of the message
  * @param htmlVersion		html version of the message
  * @param textVersion		text only version of the message
  * @param additionalMailHeader	additions to the smtp mail header
  * @param optional uid      user id of the destination user
  */
 public static function send($params)
 {
     call_hooks('emailer_send_prepare', $params);
     $email_textonly = False;
     if (x($params, "uid")) {
         $email_textonly = get_pconfig($params['uid'], "system", "email_textonly");
     }
     $fromName = email_header_encode(html_entity_decode($params['fromName'], ENT_QUOTES, 'UTF-8'), 'UTF-8');
     $messageSubject = email_header_encode(html_entity_decode($params['messageSubject'], ENT_QUOTES, 'UTF-8'), 'UTF-8');
     // generate a mime boundary
     $mimeBoundary = rand(0, 9) . "-" . rand(10000000000, 99999999999) . "-" . rand(10000000000, 99999999999) . "=:" . rand(10000, 99999);
     // generate a multipart/alternative message header
     $messageHeader = $params['additionalMailHeader'] . "From: {$fromName} <{$params['fromEmail']}>\n" . "Reply-To: {$fromName} <{$params['replyTo']}>\n" . "MIME-Version: 1.0\n" . "Content-Type: multipart/alternative; boundary=\"{$mimeBoundary}\"";
     // assemble the final multipart message body with the text and html types included
     $textBody = chunk_split(base64_encode($params['textVersion']));
     $htmlBody = chunk_split(base64_encode($params['htmlVersion']));
     $multipartMessageBody = "--" . $mimeBoundary . "\n" . "Content-Type: text/plain; charset=UTF-8\n" . "Content-Transfer-Encoding: base64\n\n" . $textBody . "\n";
     if (!$email_textonly && !is_null($params['htmlVersion'])) {
         $multipartMessageBody .= "--" . $mimeBoundary . "\n" . "Content-Type: text/html; charset=UTF-8\n" . "Content-Transfer-Encoding: base64\n\n" . $htmlBody . "\n";
     }
     $multipartMessageBody .= "--" . $mimeBoundary . "--\n";
     // message ending
     // send the message
     $hookdata = array('to' => $params['toEmail'], 'subject' => $messageSubject, 'body' => $multipartMessageBody, 'headers' => $messageHeader);
     //echo "<pre>"; var_dump($hookdata); killme();
     call_hooks("emailer_send", $hookdata);
     $res = mail($hookdata['to'], $hookdata['subject'], $hookdata['body'], $hookdata['headers']);
     logger("header " . 'To: ' . $params['toEmail'] . "\n" . $messageHeader, LOGGER_DEBUG);
     logger("return value " . ($res ? "true" : "false"), LOGGER_DEBUG);
     return $res;
 }
示例#2
0
function lostpass_content(&$a)
{
    if (x($_GET, 'verify')) {
        $verify = $_GET['verify'];
        $r = q("SELECT * FROM account WHERE account_reset = '%s' LIMIT 1", dbesc($verify));
        if (!$r) {
            notice(t("Request could not be verified. (You may have previously submitted it.) Password reset failed.") . EOL);
            goaway(z_root());
            return;
        }
        $aid = $r[0]['account_id'];
        $email = $r[0]['account_email'];
        $new_password = autoname(6) . mt_rand(100, 9999);
        $salt = random_string(32);
        $password_encoded = hash('whirlpool', $salt . $new_password);
        $r = q("UPDATE account SET account_salt = '%s', account_password = '******', account_reset = '', account_flags = (account_flags & ~%d) where account_id = %d", dbesc($salt), dbesc($password_encoded), intval(ACCOUNT_UNVERIFIED), intval($aid));
        if ($r) {
            $tpl = get_markup_template('pwdreset.tpl');
            $o .= replace_macros($tpl, array('$lbl1' => t('Password Reset'), '$lbl2' => t('Your password has been reset as requested.'), '$lbl3' => t('Your new password is'), '$lbl4' => t('Save or copy your new password - and then'), '$lbl5' => '<a href="' . $a->get_baseurl() . '">' . t('click here to login') . '</a>.', '$lbl6' => t('Your password may be changed from the <em>Settings</em> page after successful login.'), '$newpass' => $new_password, '$baseurl' => $a->get_baseurl()));
            info("Your password has been reset." . EOL);
            $email_tpl = get_intltext_template("passchanged_eml.tpl");
            $message = replace_macros($email_tpl, array('$sitename' => $a->config['sitename'], '$siteurl' => $a->get_baseurl(), '$username' => sprintf(t('Site Member (%s)'), $email), '$email' => $email, '$new_password' => $new_password, '$uid' => $newuid));
            $subject = email_header_encode(sprintf(t('Your password has changed at %s'), get_config('system', 'sitename')), 'UTF-8');
            $res = mail($email, $subject, $message, 'From: ' . 'Administrator@' . $_SERVER['SERVER_NAME'] . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit');
            return $o;
        }
    } else {
        $tpl = get_markup_template('lostpass.tpl');
        $o .= replace_macros($tpl, array('$title' => t('Forgot your Password?'), '$desc' => t('Enter your email address and submit to have your password reset. Then check your email for further instructions.'), '$name' => t('Email Address'), '$submit' => t('Reset')));
        return $o;
    }
}
示例#3
0
function user_allow($hash)
{
    $a = get_app();
    $register = q("SELECT * FROM `register` WHERE `hash` = '%s' LIMIT 1", dbesc($hash));
    if (!count($register)) {
        return false;
    }
    $user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($register[0]['uid']));
    if (!count($user)) {
        killme();
    }
    $r = q("DELETE FROM `register` WHERE `hash` = '%s' LIMIT 1", dbesc($register[0]['hash']));
    $r = q("UPDATE `user` SET `blocked` = 0, `verified` = 1 WHERE `uid` = %d LIMIT 1", intval($register[0]['uid']));
    $r = q("SELECT * FROM `profile` WHERE `uid` = %d AND `is-default` = 1", intval($user[0]['uid']));
    if (count($r) && $r[0]['net-publish']) {
        $url = $a->get_baseurl() . '/profile/' . $user[0]['nickname'];
        if ($url && strlen(get_config('system', 'directory_submit_url'))) {
            proc_run('php', "include/directory.php", "{$url}");
        }
    }
    push_lang($register[0]['language']);
    $email_tpl = get_intltext_template("register_open_eml.tpl");
    $email_tpl = replace_macros($email_tpl, array('$sitename' => $a->config['sitename'], '$siteurl' => $a->get_baseurl(), '$username' => $user[0]['username'], '$email' => $user[0]['email'], '$password' => $register[0]['password'], '$uid' => $user[0]['uid']));
    $res = mail($user[0]['email'], email_header_encode(sprintf(t('Registration details for %s'), $a->config['sitename']), 'UTF-8'), $email_tpl, 'From: ' . 'Administrator' . '@' . $_SERVER['SERVER_NAME'] . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit');
    pop_lang();
    if ($res) {
        info(t('Account approved.') . EOL);
        return true;
    }
}
示例#4
0
function lostpass_content(&$a)
{
    if (x($_GET, 'verify')) {
        $verify = $_GET['verify'];
        $hash = hash('whirlpool', $verify);
        $r = q("SELECT * FROM `user` WHERE `pwdreset` = '%s' LIMIT 1", dbesc($hash));
        if (!count($r)) {
            notice(t("Request could not be verified. (You may have previously submitted it.) Password reset failed.") . EOL);
            goaway(z_root());
            return;
        }
        $uid = $r[0]['uid'];
        $username = $r[0]['username'];
        $email = $r[0]['email'];
        $new_password = autoname(6) . mt_rand(100, 9999);
        $new_password_encoded = hash('whirlpool', $new_password);
        $r = q("UPDATE `user` SET `password` = '%s', `pwdreset` = ''  WHERE `uid` = %d LIMIT 1", dbesc($new_password_encoded), intval($uid));
        if ($r) {
            $tpl = get_markup_template('pwdreset.tpl');
            $o .= replace_macros($tpl, array('$lbl1' => t('Password Reset'), '$lbl2' => t('Your password has been reset as requested.'), '$lbl3' => t('Your new password is'), '$lbl4' => t('Save or copy your new password - and then'), '$lbl5' => '<a href="' . $a->get_baseurl() . '">' . t('click here to login') . '</a>.', '$lbl6' => t('Your password may be changed from the <em>Settings</em> page after successful login.'), '$newpass' => $new_password, '$baseurl' => $a->get_baseurl()));
            info("Your password has been reset." . EOL);
            $email_tpl = get_intltext_template("passchanged_eml.tpl");
            $email_tpl = replace_macros($email_tpl, array('$sitename' => $a->config['sitename'], '$siteurl' => $a->get_baseurl(), '$username' => $username, '$email' => $email, '$new_password' => $new_password, '$uid' => $newuid));
            $subject = sprintf(t('Your password has been changed at %s'), $a->config['sitename']);
            $res = mail($email, email_header_encode($subject, 'UTF-8'), $email_tpl, 'From: ' . 'Administrator' . '@' . $_SERVER['SERVER_NAME'] . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit');
            return $o;
        }
    } else {
        $tpl = get_markup_template('lostpass.tpl');
        $o .= replace_macros($tpl, array('$title' => t('Forgot your Password?'), '$desc' => t('Enter your email address and submit to have your password reset. Then check your email for further instructions.'), '$name' => t('Nickname or Email: '), '$submit' => t('Reset')));
        return $o;
    }
}
示例#5
0
 /**
  * Send a multipart/alternative message with Text and HTML versions
  *
  * @param fromName			name of the sender
  * @param fromEmail			email fo the sender
  * @param replyTo			replyTo address to direct responses
  * @param toEmail			destination email address
  * @param messageSubject	subject of the message
  * @param htmlVersion		html version of the message
  * @param textVersion		text only version of the message
  */
 public static function sendTextHtmlEmail($fromName, $fromEmail, $replyTo, $toEmail, $messageSubject, $htmlVersion, $textVersion)
 {
     $fromName = email_header_encode($fromName, 'UTF-8');
     $messageSubject = email_header_encode($messageSubject, 'UTF-8');
     // generate a mime boundary
     $mimeBoundary = rand(0, 9) . "-" . rand(10000000000.0, 9999999999.0) . "-" . rand(10000000000.0, 9999999999.0) . "=:" . rand(10000, 99999);
     // generate a multipart/alternative message header
     $messageHeader = "From: {$fromName} <{$fromEmail}>\n" . "Reply-To: {$replyTo}\n" . "MIME-Version: 1.0\n" . "Content-Type: multipart/alternative; boundary=\"{$mimeBoundary}\"";
     // assemble the final multipart message body with the text and html types included
     $textBody = chunk_split(base64_encode($textVersion));
     $htmlBody = chunk_split(base64_encode($htmlVersion));
     $multipartMessageBody = "--" . $mimeBoundary . "\n" . "Content-Type: text/plain; charset=UTF-8\n" . "Content-Transfer-Encoding: base64\n\n" . $textBody . "\n" . "--" . $mimeBoundary . "\n" . "Content-Type: text/html; charset=UTF-8\n" . "Content-Transfer-Encoding: base64\n\n" . $htmlBody . "\n" . "--" . $mimeBoundary . "--\n";
     // message ending
     // send the message
     $res = mail($toEmail, $messageSubject, $multipartMessageBody, $messageHeader);
     logger("sendTextHtmlEmail: END");
 }
示例#6
0
 /**
  * Send a multipart/alternative message with Text and HTML versions
  *
  * @param fromName			name of the sender
  * @param fromEmail			email fo the sender
  * @param replyTo			replyTo address to direct responses
  * @param toEmail			destination email address
  * @param messageSubject	subject of the message
  * @param htmlVersion		html version of the message
  * @param textVersion		text only version of the message
  * @param additionalMailHeader	additions to the smtp mail header
  */
 public static function send($params)
 {
     $fromName = email_header_encode(html_entity_decode($params['fromName'], ENT_QUOTES, 'UTF-8'), 'UTF-8');
     $messageSubject = email_header_encode(html_entity_decode($params['messageSubject'], ENT_QUOTES, 'UTF-8'), 'UTF-8');
     // generate a mime boundary
     $mimeBoundary = rand(0, 9) . "-" . rand(10000000000, 9999999999) . "-" . rand(10000000000, 9999999999) . "=:" . rand(10000, 99999);
     // generate a multipart/alternative message header
     $messageHeader = $params['additionalMailHeader'] . "From: {$fromName} <{$params['fromEmail']}>\n" . "Reply-To: {$fromName} <{$params['replyTo']}>\n" . "MIME-Version: 1.0\n" . "Content-Type: multipart/alternative; boundary=\"{$mimeBoundary}\"";
     // assemble the final multipart message body with the text and html types included
     $textBody = chunk_split(base64_encode($params['textVersion']));
     $htmlBody = chunk_split(base64_encode($params['htmlVersion']));
     $multipartMessageBody = "--" . $mimeBoundary . "\n" . "Content-Type: text/plain; charset=UTF-8\n" . "Content-Transfer-Encoding: base64\n\n" . $textBody . "\n" . "--" . $mimeBoundary . "\n" . "Content-Type: text/html; charset=UTF-8\n" . "Content-Transfer-Encoding: base64\n\n" . $htmlBody . "\n" . "--" . $mimeBoundary . "--\n";
     // message ending
     // send the message
     $res = mail($params['toEmail'], $messageSubject, $multipartMessageBody, $messageHeader);
     logger("header " . 'To: ' . $params['toEmail'] . "\n" . $messageHeader, LOGGER_DEBUG);
     logger("return value " . ($res ? "true" : "false"), LOGGER_DEBUG);
     return $res;
 }
示例#7
0
 function post()
 {
     $loginame = notags(trim($_POST['login-name']));
     if (!$loginame) {
         goaway(z_root());
     }
     $r = q("SELECT * FROM account WHERE account_email = '%s' LIMIT 1", dbesc($loginame));
     if (!$r) {
         notice(t('No valid account found.') . EOL);
         goaway(z_root());
     }
     $aid = $r[0]['account_id'];
     $email = $r[0]['account_email'];
     $hash = random_string();
     $r = q("UPDATE account SET account_reset = '%s' WHERE account_id = %d", dbesc($hash), intval($aid));
     if ($r) {
         info(t('Password reset request issued. Check your email.') . EOL);
     }
     $email_tpl = get_intltext_template("lostpass_eml.tpl");
     $message = replace_macros($email_tpl, array('$sitename' => get_config('system', 'sitename'), '$siteurl' => z_root(), '$username' => sprintf(t('Site Member (%s)'), $email), '$email' => $email, '$reset_link' => z_root() . '/lostpass?verify=' . $hash));
     $subject = email_header_encode(sprintf(t('Password reset requested at %s'), get_config('system', 'sitename')), 'UTF-8');
     $res = z_mail(['toEmail' => $email, 'messageSubject' => sprintf(t('Password reset requested at %s'), get_config('system', 'sitename')), 'textVersion' => $message]);
     goaway(z_root());
 }
示例#8
0
 function update_db(&$a)
 {
     $build = get_config('system', 'build');
     if (!x($build)) {
         $build = set_config('system', 'build', DB_UPDATE_VERSION);
     }
     if ($build != DB_UPDATE_VERSION) {
         $stored = intval($build);
         $current = intval(DB_UPDATE_VERSION);
         if ($stored < $current && file_exists('update.php')) {
             load_config('database');
             // We're reporting a different version than what is currently installed.
             // Run any existing update scripts to bring the database up to current.
             require_once 'update.php';
             // make sure that boot.php and update.php are the same release, we might be
             // updating right this very second and the correct version of the update.php
             // file may not be here yet. This can happen on a very busy site.
             if (DB_UPDATE_VERSION == UPDATE_VERSION) {
                 for ($x = $stored; $x < $current; $x++) {
                     if (function_exists('update_' . $x)) {
                         // There could be a lot of processes running or about to run.
                         // We want exactly one process to run the update command.
                         // So store the fact that we're taking responsibility
                         // after first checking to see if somebody else already has.
                         // If the update fails or times-out completely you may need to
                         // delete the config entry to try again.
                         $t = get_config('database', 'update_' . $x);
                         if ($t !== false) {
                             break;
                         }
                         set_config('database', 'update_' . $x, time());
                         // call the specific update
                         $func = 'update_' . $x;
                         $retval = $func();
                         if ($retval) {
                             //send the administrator an e-mail
                             $email_tpl = get_intltext_template("update_fail_eml.tpl");
                             $email_msg = replace_macros($email_tpl, array('$sitename' => $a->config['sitename'], '$siteurl' => $a->get_baseurl(), '$update' => $x, '$error' => sprintf(t('Update %s failed. See error logs.'), $x)));
                             $subject = sprintf(t('Update Error at %s'), $a->get_baseurl());
                             require_once 'include/email.php';
                             $subject = email_header_encode($subject, 'UTF-8');
                             mail($a->config['admin_email'], $subject, $email_msg, 'From: ' . 'Administrator' . '@' . $_SERVER['SERVER_NAME'] . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit');
                             //try the logger
                             logger('CRITICAL: Update Failed: ' . $x);
                             break;
                         } else {
                             set_config('database', 'update_' . $x, 'success');
                             set_config('system', 'build', $x + 1);
                         }
                     }
                 }
             }
         }
     }
     return;
 }
示例#9
0
function notifier_run(&$argv, &$argc)
{
    global $a, $db;
    if (is_null($a)) {
        $a = new App();
    }
    if (is_null($db)) {
        @(include ".htconfig.php");
        require_once "include/dba.php";
        $db = new dba($db_host, $db_user, $db_pass, $db_data);
        unset($db_host, $db_user, $db_pass, $db_data);
    }
    require_once "include/session.php";
    require_once "include/datetime.php";
    require_once 'include/items.php';
    require_once 'include/bbcode.php';
    require_once 'include/email.php';
    load_config('config');
    load_config('system');
    load_hooks();
    if ($argc < 3) {
        return;
    }
    $a->set_baseurl(get_config('system', 'url'));
    logger('notifier: invoked: ' . print_r($argv, true), LOGGER_DEBUG);
    $cmd = $argv[1];
    switch ($cmd) {
        case 'mail':
        default:
            $item_id = intval($argv[2]);
            if (!$item_id) {
                return;
            }
            break;
    }
    $expire = false;
    $mail = false;
    $fsuggest = false;
    $relocate = false;
    $top_level = false;
    $recipients = array();
    $url_recipients = array();
    $normal_mode = true;
    if ($cmd === 'mail') {
        $normal_mode = false;
        $mail = true;
        $message = q("SELECT * FROM `mail` WHERE `id` = %d LIMIT 1", intval($item_id));
        if (!count($message)) {
            return;
        }
        $uid = $message[0]['uid'];
        $recipients[] = $message[0]['contact-id'];
        $item = $message[0];
    } elseif ($cmd === 'expire') {
        $normal_mode = false;
        $expire = true;
        $items = q("SELECT * FROM `item` WHERE `uid` = %d AND `wall` = 1\n\t\t\tAND `deleted` = 1 AND `changed` > UTC_TIMESTAMP() - INTERVAL 10 MINUTE", intval($item_id));
        $uid = $item_id;
        $item_id = 0;
        if (!count($items)) {
            return;
        }
    } elseif ($cmd === 'suggest') {
        $normal_mode = false;
        $fsuggest = true;
        $suggest = q("SELECT * FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item_id));
        if (!count($suggest)) {
            return;
        }
        $uid = $suggest[0]['uid'];
        $recipients[] = $suggest[0]['cid'];
        $item = $suggest[0];
    } elseif ($cmd === 'removeme') {
        $r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($item_id));
        if (!$r) {
            return;
        }
        $user = $r[0];
        $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", intval($item_id));
        if (!$r) {
            return;
        }
        $self = $r[0];
        $r = q("SELECT * FROM `contact` WHERE `self` = 0 AND `uid` = %d", intval($item_id));
        if (!$r) {
            return;
        }
        require_once 'include/Contact.php';
        foreach ($r as $contact) {
            terminate_friendship($user, $self, $contact);
        }
        return;
    } elseif ($cmd === 'relocate') {
        $normal_mode = false;
        $relocate = true;
        $uid = $item_id;
    } else {
        // find ancestors
        $r = q("SELECT * FROM `item` WHERE `id` = %d and visible = 1 and moderated = 0 LIMIT 1", intval($item_id));
        if (!count($r) || !intval($r[0]['parent'])) {
            return;
        }
        $target_item = $r[0];
        $parent_id = intval($r[0]['parent']);
        $uid = $r[0]['uid'];
        $updated = $r[0]['edited'];
        // POSSIBLE CLEANUP --> The following seems superfluous. We've already checked for "if (! intval($r[0]['parent']))" a few lines up
        if (!$parent_id) {
            return;
        }
        $items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer`\n\t\t\tFROM `item` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` WHERE `parent` = %d and visible = 1 and moderated = 0 ORDER BY `id` ASC", intval($parent_id));
        if (!count($items)) {
            return;
        }
        // avoid race condition with deleting entries
        if ($items[0]['deleted']) {
            foreach ($items as $item) {
                $item['deleted'] = 1;
            }
        }
        if (count($items) == 1 && $items[0]['id'] === $target_item['id'] && $items[0]['uri'] === $items[0]['parent-uri']) {
            logger('notifier: top level post');
            $top_level = true;
        }
    }
    $r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`,\n\t\t`user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`,\n\t\t`user`.`page-flags`, `user`.`prvnets`\n\t\tFROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid`\n\t\tWHERE `contact`.`uid` = %d AND `contact`.`self` = 1 LIMIT 1", intval($uid));
    if (!count($r)) {
        return;
    }
    $owner = $r[0];
    $walltowall = $top_level && $owner['id'] != $items[0]['contact-id'] ? true : false;
    $hub = get_config('system', 'huburl');
    // If this is a public conversation, notify the feed hub
    $public_message = true;
    // Do a PuSH
    $push_notify = false;
    // fill this in with a single salmon slap if applicable
    $slap = '';
    if (!($mail || $fsuggest || $relocate)) {
        require_once 'include/group.php';
        $parent = $items[0];
        $thr_parent = q("SELECT `network` FROM `item` WHERE `uri` = '%s' AND `uid` = %d", dbesc($target_item["thr-parent"]), intval($target_item["uid"]));
        logger('Parent is ' . $parent['network'] . '. Thread parent is ' . $thr_parent[0]['network'], LOGGER_DEBUG);
        // This is IMPORTANT!!!!
        // We will only send a "notify owner to relay" or followup message if the referenced post
        // originated on our system by virtue of having our hostname somewhere
        // in the URI, AND it was a comment (not top_level) AND the parent originated elsewhere.
        // if $parent['wall'] == 1 we will already have the parent message in our array
        // and we will relay the whole lot.
        // expire sends an entire group of expire messages and cannot be forwarded.
        // However the conversation owner will be a part of the conversation and will
        // be notified during this run.
        // Other DFRN conversation members will be alerted during polled updates.
        // Diaspora members currently are not notified of expirations, and other networks have
        // either limited or no ability to process deletions. We should at least fix Diaspora
        // by stringing togther an array of retractions and sending them onward.
        $localhost = str_replace('www.', '', $a->get_hostname());
        if (strpos($localhost, ':')) {
            $localhost = substr($localhost, 0, strpos($localhost, ':'));
        }
        /**
         *
         * Be VERY CAREFUL if you make any changes to the following several lines. Seemingly innocuous changes
         * have been known to cause runaway conditions which affected several servers, along with
         * permissions issues.
         *
         */
        $relay_to_owner = false;
        if (!$top_level && $parent['wall'] == 0 && !$expire && stristr($target_item['uri'], $localhost)) {
            $relay_to_owner = true;
        }
        if ($cmd === 'uplink' && intval($parent['forum_mode']) == 1 && !$top_level) {
            $relay_to_owner = true;
        }
        // until the 'origin' flag has been in use for several months
        // we will just use it as a fallback test
        // later we will be able to use it as the primary test of whether or not to relay.
        if (!$target_item['origin']) {
            $relay_to_owner = false;
        }
        if ($parent['origin']) {
            $relay_to_owner = false;
        }
        if ($relay_to_owner) {
            logger('notifier: followup ' . $target_item["guid"], LOGGER_DEBUG);
            // local followup to remote post
            $followup = true;
            $public_message = false;
            // not public
            $conversant_str = dbesc($parent['contact-id']);
            $recipients = array($parent['contact-id']);
            if (!$target_item['private'] and $target_item['wall'] and strlen($target_item['allow_cid'] . $target_item['allow_gid'] . $target_item['deny_cid'] . $target_item['deny_gid']) == 0) {
                $push_notify = true;
            }
            // We notify Friendica users in the thread when it is an OStatus thread.
            // Hopefully this transfers the messages to the other Friendica servers. (Untested)
            if ($thr_parent and $thr_parent[0]['network'] == NETWORK_OSTATUS or $parent['network'] == NETWORK_OSTATUS) {
                $push_notify = true;
                if ($parent["network"] == NETWORK_OSTATUS) {
                    $r = q("SELECT `author-link` FROM `item` WHERE `parent` = %d AND `author-link` != '%s'", intval($target_item["parent"]), dbesc($owner['url']));
                    foreach ($r as $parent_item) {
                        $probed_contact = probe_url($parent_item["author-link"]);
                        if ($probed_contact["notify"] != "" and $probed_contact["network"] == NETWORK_DFRN) {
                            logger('Notify Friendica user ' . $probed_contact["url"] . ': ' . $probed_contact["notify"]);
                            $url_recipients[$probed_contact["notify"]] = $probed_contact["notify"];
                        }
                    }
                }
                if (count($url_recipients)) {
                    logger("url_recipients " . print_r($url_recipients, true));
                }
            }
        } else {
            $followup = false;
            logger('Distributing directly ' . $target_item["guid"], LOGGER_DEBUG);
            // don't send deletions onward for other people's stuff
            if ($target_item['deleted'] && !intval($target_item['wall'])) {
                logger('notifier: ignoring delete notification for non-wall item');
                return;
            }
            if (strlen($parent['allow_cid']) || strlen($parent['allow_gid']) || strlen($parent['deny_cid']) || strlen($parent['deny_gid'])) {
                $public_message = false;
                // private recipients, not public
            }
            $allow_people = expand_acl($parent['allow_cid']);
            $allow_groups = expand_groups(expand_acl($parent['allow_gid']), true);
            $deny_people = expand_acl($parent['deny_cid']);
            $deny_groups = expand_groups(expand_acl($parent['deny_gid']));
            // if our parent is a public forum (forum_mode == 1), uplink to the origional author causing
            // a delivery fork. private groups (forum_mode == 2) do not uplink
            if (intval($parent['forum_mode']) == 1 && !$top_level && $cmd !== 'uplink') {
                proc_run('php', 'include/notifier.php', 'uplink', $item_id);
            }
            $conversants = array();
            foreach ($items as $item) {
                $recipients[] = $item['contact-id'];
                $conversants[] = $item['contact-id'];
                // pull out additional tagged people to notify (if public message)
                if ($public_message && strlen($item['inform'])) {
                    $people = explode(',', $item['inform']);
                    foreach ($people as $person) {
                        if (substr($person, 0, 4) === 'cid:') {
                            $recipients[] = intval(substr($person, 4));
                            $conversants[] = intval(substr($person, 4));
                        } else {
                            $url_recipients[] = substr($person, 4);
                        }
                    }
                }
            }
            if (count($url_recipients)) {
                logger('notifier: ' . $target_item["guid"] . ' url_recipients ' . print_r($url_recipients, true));
            }
            $conversants = array_unique($conversants);
            $recipients = array_unique(array_merge($recipients, $allow_people, $allow_groups));
            $deny = array_unique(array_merge($deny_people, $deny_groups));
            $recipients = array_diff($recipients, $deny);
            $conversant_str = dbesc(implode(', ', $conversants));
        }
        // If the thread parent is OStatus then do some magic to distribute the messages.
        // We have not only to look at the parent, since it could be a Friendica thread.
        if ($thr_parent and $thr_parent[0]['network'] == NETWORK_OSTATUS or $parent['network'] == NETWORK_OSTATUS) {
            logger('Some parent is OStatus for ' . $target_item["guid"], LOGGER_DEBUG);
            // Send a salmon notification to every person we mentioned in the post
            $arr = explode(',', $target_item['tag']);
            foreach ($arr as $x) {
                //logger('Checking tag '.$x, LOGGER_DEBUG);
                $matches = null;
                if (preg_match('/@\\[url=([^\\]]*)\\]/', $x, $matches)) {
                    $probed_contact = probe_url($matches[1]);
                    if ($probed_contact["notify"] != "") {
                        logger('Notify mentioned user ' . $probed_contact["url"] . ': ' . $probed_contact["notify"]);
                        $url_recipients[$probed_contact["notify"]] = $probed_contact["notify"];
                    }
                }
            }
            // It only makes sense to distribute answers to OStatus messages to Friendica and OStatus - but not Diaspora
            $sql_extra = " AND `network` IN ('" . NETWORK_OSTATUS . "', '" . NETWORK_DFRN . "')";
        } else {
            $sql_extra = "";
        }
        $r = q("SELECT * FROM `contact` WHERE `id` IN ({$conversant_str}) AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0" . $sql_extra);
        if (count($r)) {
            $contacts = $r;
        }
    }
    $feed_template = get_markup_template('atom_feed.tpl');
    $mail_template = get_markup_template('atom_mail.tpl');
    $atom = '';
    $slaps = array();
    $hubxml = feed_hublinks();
    $birthday = feed_birthday($owner['uid'], $owner['timezone']);
    if (strlen($birthday)) {
        $birthday = '<dfrn:birthday>' . xmlify($birthday) . '</dfrn:birthday>';
    }
    $atom .= replace_macros($feed_template, array('$version' => xmlify(FRIENDICA_VERSION), '$feed_id' => xmlify($a->get_baseurl() . '/profile/' . $owner['nickname']), '$feed_title' => xmlify($owner['name']), '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', $updated . '+00:00', ATOM_TIME)), '$hub' => $hubxml, '$salmon' => '', '$name' => xmlify($owner['name']), '$profile_page' => xmlify($owner['url']), '$photo' => xmlify($owner['photo']), '$thumb' => xmlify($owner['thumb']), '$picdate' => xmlify(datetime_convert('UTC', 'UTC', $owner['avatar-date'] . '+00:00', ATOM_TIME)), '$uridate' => xmlify(datetime_convert('UTC', 'UTC', $owner['uri-date'] . '+00:00', ATOM_TIME)), '$namdate' => xmlify(datetime_convert('UTC', 'UTC', $owner['name-date'] . '+00:00', ATOM_TIME)), '$birthday' => $birthday, '$community' => $owner['page-flags'] == PAGE_COMMUNITY ? '<dfrn:community>1</dfrn:community>' : ''));
    if ($mail) {
        $public_message = false;
        // mail is  not public
        $body = fix_private_photos($item['body'], $owner['uid'], null, $message[0]['contact-id']);
        $atom .= replace_macros($mail_template, array('$name' => xmlify($owner['name']), '$profile_page' => xmlify($owner['url']), '$thumb' => xmlify($owner['thumb']), '$item_id' => xmlify($item['uri']), '$subject' => xmlify($item['title']), '$created' => xmlify(datetime_convert('UTC', 'UTC', $item['created'] . '+00:00', ATOM_TIME)), '$content' => xmlify($body), '$parent_id' => xmlify($item['parent-uri'])));
    } elseif ($fsuggest) {
        $public_message = false;
        // suggestions are not public
        $sugg_template = get_markup_template('atom_suggest.tpl');
        $atom .= replace_macros($sugg_template, array('$name' => xmlify($item['name']), '$url' => xmlify($item['url']), '$photo' => xmlify($item['photo']), '$request' => xmlify($item['request']), '$note' => xmlify($item['note'])));
        // We don't need this any more
        q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item['id']));
    } elseif ($relocate) {
        $public_message = false;
        // suggestions are not public
        $sugg_template = get_markup_template('atom_relocate.tpl');
        /* get site pubkey. this could be a new installation with no site keys*/
        $pubkey = get_config('system', 'site_pubkey');
        if (!$pubkey) {
            $res = new_keypair(1024);
            set_config('system', 'site_prvkey', $res['prvkey']);
            set_config('system', 'site_pubkey', $res['pubkey']);
        }
        $rp = q("SELECT `resource-id` , `scale`, type FROM `photo` \n\t\t\t\t\t\tWHERE `profile` = 1 AND `uid` = %d ORDER BY scale;", $uid);
        $photos = array();
        $ext = Photo::supportedTypes();
        foreach ($rp as $p) {
            $photos[$p['scale']] = $a->get_baseurl() . '/photo/' . $p['resource-id'] . '-' . $p['scale'] . '.' . $ext[$p['type']];
        }
        unset($rp, $ext);
        $atom .= replace_macros($sugg_template, array('$name' => xmlify($owner['name']), '$photo' => xmlify($photos[4]), '$thumb' => xmlify($photos[5]), '$micro' => xmlify($photos[6]), '$url' => xmlify($owner['url']), '$request' => xmlify($owner['request']), '$confirm' => xmlify($owner['confirm']), '$notify' => xmlify($owner['notify']), '$poll' => xmlify($owner['poll']), '$sitepubkey' => xmlify(get_config('system', 'site_pubkey'))));
        $recipients_relocate = q("SELECT * FROM contact WHERE uid = %d  AND self = 0 AND network = '%s'", intval($uid), NETWORK_DFRN);
        unset($photos);
    } else {
        $slap = ostatus_salmon($target_item, $owner);
        //$slap = atom_entry($target_item,'html',null,$owner,false);
        if ($followup) {
            foreach ($items as $item) {
                // there is only one item
                if (!$item['parent']) {
                    continue;
                }
                if ($item['id'] == $item_id) {
                    logger('notifier: followup: item: ' . print_r($item, true), LOGGER_DATA);
                    //$slap  = atom_entry($item,'html',null,$owner,false);
                    $atom .= atom_entry($item, 'text', null, $owner, false);
                }
            }
        } else {
            foreach ($items as $item) {
                if (!$item['parent']) {
                    continue;
                }
                // private emails may be in included in public conversations. Filter them.
                if ($public_message && $item['private'] == 1) {
                    continue;
                }
                $contact = get_item_contact($item, $contacts);
                if (!$contact) {
                    continue;
                }
                if ($normal_mode) {
                    // we only need the current item, but include the parent because without it
                    // older sites without a corresponding dfrn_notify change may do the wrong thing.
                    if ($item_id == $item['id'] || $item['id'] == $item['parent']) {
                        $atom .= atom_entry($item, 'text', null, $owner, true);
                    }
                } else {
                    $atom .= atom_entry($item, 'text', null, $owner, true);
                }
                if ($top_level && $public_message && $item['author-link'] === $item['owner-link'] && !$expire) {
                    $slaps[] = ostatus_salmon($item, $owner);
                }
                //$slaps[] = atom_entry($item,'html',null,$owner,true);
            }
        }
    }
    $atom .= '</feed>' . "\r\n";
    logger('notifier: ' . $atom, LOGGER_DATA);
    logger('notifier: slaps: ' . print_r($slaps, true), LOGGER_DATA);
    // If this is a public message and pubmail is set on the parent, include all your email contacts
    $mail_disabled = function_exists('imap_open') && !get_config('system', 'imap_disabled') ? 0 : 1;
    if (!$mail_disabled) {
        if (!strlen($target_item['allow_cid']) && !strlen($target_item['allow_gid']) && !strlen($target_item['deny_cid']) && !strlen($target_item['deny_gid']) && intval($target_item['pubmail'])) {
            $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `network` = '%s'", intval($uid), dbesc(NETWORK_MAIL));
            if (count($r)) {
                foreach ($r as $rr) {
                    $recipients[] = $rr['id'];
                }
            }
        }
    }
    if ($followup) {
        $recip_str = $parent['contact-id'];
    } else {
        $recip_str = implode(', ', $recipients);
    }
    if ($relocate) {
        $r = $recipients_relocate;
    } else {
        $r = q("SELECT * FROM `contact` WHERE `id` IN ( %s ) AND `blocked` = 0 AND `pending` = 0 ", dbesc($recip_str));
    }
    require_once 'include/salmon.php';
    $interval = get_config('system', 'delivery_interval') === false ? 2 : intval(get_config('system', 'delivery_interval'));
    // If we are using the worker we don't need a delivery interval
    if (get_config("system", "worker")) {
        $interval = false;
    }
    // delivery loop
    if (count($r)) {
        foreach ($r as $contact) {
            if (!$mail && !$fsuggest && !$followup && !$relocate && !$contact['self']) {
                if ($contact['network'] === NETWORK_DIASPORA && $public_message) {
                    continue;
                }
                q("insert into deliverq ( `cmd`,`item`,`contact` ) values ('%s', %d, %d )", dbesc($cmd), intval($item_id), intval($contact['id']));
            }
        }
        // This controls the number of deliveries to execute with each separate delivery process.
        // By default we'll perform one delivery per process. Assuming a hostile shared hosting
        // provider, this provides the greatest chance of deliveries if processes start getting
        // killed. We can also space them out with the delivery_interval to also help avoid them
        // getting whacked.
        // If $deliveries_per_process > 1, we will chain this number of multiple deliveries
        // together into a single process. This will reduce the overall number of processes
        // spawned for each delivery, but they will run longer.
        // When using the workerqueue, we don't need this functionality.
        $deliveries_per_process = intval(get_config('system', 'delivery_batch_count'));
        if ($deliveries_per_process <= 0 or get_config("system", "worker")) {
            $deliveries_per_process = 1;
        }
        $this_batch = array();
        for ($x = 0; $x < count($r); $x++) {
            $contact = $r[$x];
            if ($contact['self']) {
                continue;
            }
            logger("Deliver " . $target_item["guid"] . " to " . $contact['url'], LOGGER_DEBUG);
            // potentially more than one recipient. Start a new process and space them out a bit.
            // we will deliver single recipient types of message and email recipients here.
            if (!$mail && !$fsuggest && !$relocate && !$followup) {
                $this_batch[] = $contact['id'];
                if (count($this_batch) == $deliveries_per_process) {
                    proc_run('php', 'include/delivery.php', $cmd, $item_id, $this_batch);
                    $this_batch = array();
                    if ($interval) {
                        @time_sleep_until(microtime(true) + (double) $interval);
                    }
                }
                continue;
            }
            // be sure to pick up any stragglers
            if (count($this_batch)) {
                proc_run('php', 'include/delivery.php', $cmd, $item_id, $this_batch);
            }
            $deliver_status = 0;
            logger("main delivery by notifier: followup={$followup} mail={$mail} fsuggest={$fsuggest} relocate={$relocate}");
            switch ($contact['network']) {
                case NETWORK_DFRN:
                    // perform local delivery if we are on the same site
                    $basepath = implode('/', array_slice(explode('/', $contact['url']), 0, 3));
                    if (link_compare($basepath, $a->get_baseurl())) {
                        $nickname = basename($contact['url']);
                        if ($contact['issued-id']) {
                            $sql_extra = sprintf(" AND `dfrn-id` = '%s' ", dbesc($contact['issued-id']));
                        } else {
                            $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($contact['dfrn-id']));
                        }
                        $x = q("SELECT\t`contact`.*, `contact`.`uid` AS `importer_uid`,\n\t\t\t\t\t\t\t`contact`.`pubkey` AS `cpubkey`,\n\t\t\t\t\t\t\t`contact`.`prvkey` AS `cprvkey`,\n\t\t\t\t\t\t\t`contact`.`thumb` AS `thumb`,\n\t\t\t\t\t\t\t`contact`.`url` as `url`,\n\t\t\t\t\t\t\t`contact`.`name` as `senderName`,\n\t\t\t\t\t\t\t`user`.*\n\t\t\t\t\t\t\tFROM `contact`\n\t\t\t\t\t\t\tINNER JOIN `user` ON `contact`.`uid` = `user`.`uid`\n\t\t\t\t\t\t\tWHERE `contact`.`blocked` = 0 AND `contact`.`archive` = 0\n\t\t\t\t\t\t\tAND `contact`.`pending` = 0\n\t\t\t\t\t\t\tAND `contact`.`network` = '%s' AND `user`.`nickname` = '%s'\n\t\t\t\t\t\t\t{$sql_extra}\n\t\t\t\t\t\t\tAND `user`.`account_expired` = 0 AND `user`.`account_removed` = 0 LIMIT 1", dbesc(NETWORK_DFRN), dbesc($nickname));
                        if ($x && count($x)) {
                            $write_flag = $x[0]['rel'] && $x[0]['rel'] != CONTACT_IS_SHARING ? true : false;
                            if (($owner['page-flags'] == PAGE_COMMUNITY || $write_flag) && !$x[0]['writable']) {
                                q("update contact set writable = 1 where id = %d", intval($x[0]['id']));
                                $x[0]['writable'] = 1;
                            }
                            // if contact's ssl policy changed, which we just determined
                            // is on our own server, update our contact links
                            $ssl_policy = get_config('system', 'ssl_policy');
                            fix_contact_ssl_policy($x[0], $ssl_policy);
                            // If we are setup as a soapbox we aren't accepting top level posts from this person
                            if ($x[0]['page-flags'] == PAGE_SOAPBOX and $top_level) {
                                break;
                            }
                            require_once 'library/simplepie/simplepie.inc';
                            logger('mod-delivery: local delivery');
                            local_delivery($x[0], $atom);
                            break;
                        }
                    }
                    logger('notifier: dfrndelivery: ' . $contact['name']);
                    $deliver_status = dfrn_deliver($owner, $contact, $atom);
                    logger('notifier: dfrn_delivery returns ' . $deliver_status);
                    if ($deliver_status == -1) {
                        logger('notifier: delivery failed: queuing message');
                        // queue message for redelivery
                        add_to_queue($contact['id'], NETWORK_DFRN, $atom);
                    }
                    break;
                case NETWORK_OSTATUS:
                    // Do not send to ostatus if we are not configured to send to public networks
                    if ($owner['prvnets']) {
                        break;
                    }
                    if (get_config('system', 'ostatus_disabled') || get_config('system', 'dfrn_only')) {
                        break;
                    }
                    if ($followup && $contact['notify']) {
                        logger('slapdelivery followup item ' . $item_id . ' to ' . $contact['name']);
                        $deliver_status = slapper($owner, $contact['notify'], $slap);
                        if ($deliver_status == -1) {
                            // queue message for redelivery
                            add_to_queue($contact['id'], NETWORK_OSTATUS, $slap);
                        }
                    } else {
                        // only send salmon if public - e.g. if it's ok to notify
                        // a public hub, it's ok to send a salmon
                        if (count($slaps) && $public_message && !$expire) {
                            logger('slapdelivery item ' . $item_id . ' to ' . $contact['name']);
                            foreach ($slaps as $slappy) {
                                if ($contact['notify']) {
                                    $deliver_status = slapper($owner, $contact['notify'], $slappy);
                                    if ($deliver_status == -1) {
                                        // queue message for redelivery
                                        add_to_queue($contact['id'], NETWORK_OSTATUS, $slappy);
                                    }
                                }
                            }
                        }
                    }
                    break;
                case NETWORK_MAIL:
                case NETWORK_MAIL2:
                    if (get_config('system', 'dfrn_only')) {
                        break;
                    }
                    // WARNING: does not currently convert to RFC2047 header encodings, etc.
                    $addr = $contact['addr'];
                    if (!strlen($addr)) {
                        break;
                    }
                    if ($cmd === 'wall-new' || $cmd === 'comment-new') {
                        $it = null;
                        if ($cmd === 'wall-new') {
                            $it = $items[0];
                        } else {
                            $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($argv[2]), intval($uid));
                            if (count($r)) {
                                $it = $r[0];
                            }
                        }
                        if (!$it) {
                            break;
                        }
                        $local_user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($uid));
                        if (!count($local_user)) {
                            break;
                        }
                        $reply_to = '';
                        $r1 = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1", intval($uid));
                        if ($r1 && $r1[0]['reply_to']) {
                            $reply_to = $r1[0]['reply_to'];
                        }
                        $subject = $it['title'] ? email_header_encode($it['title'], 'UTF-8') : t("(no subject)");
                        // only expose our real email address to true friends
                        if ($contact['rel'] == CONTACT_IS_FRIEND && !$contact['blocked']) {
                            if ($reply_to) {
                                $headers = 'From: ' . email_header_encode($local_user[0]['username'], 'UTF-8') . ' <' . $reply_to . '>' . "\n";
                                $headers .= 'Sender: ' . $local_user[0]['email'] . "\n";
                            } else {
                                $headers = 'From: ' . email_header_encode($local_user[0]['username'], 'UTF-8') . ' <' . $local_user[0]['email'] . '>' . "\n";
                            }
                        } else {
                            $headers = 'From: ' . email_header_encode($local_user[0]['username'], 'UTF-8') . ' <' . t('noreply') . '@' . $a->get_hostname() . '>' . "\n";
                        }
                        //if($reply_to)
                        //	$headers .= 'Reply-to: ' . $reply_to . "\n";
                        $headers .= 'Message-Id: <' . iri2msgid($it['uri']) . '>' . "\n";
                        if ($it['uri'] !== $it['parent-uri']) {
                            $headers .= "References: <" . iri2msgid($it["parent-uri"]) . ">";
                            // If Threading is enabled, write down the correct parent
                            if ($it["thr-parent"] != "" and $it["thr-parent"] != $it["parent-uri"]) {
                                $headers .= " <" . iri2msgid($it["thr-parent"]) . ">";
                            }
                            $headers .= "\n";
                            if (!$it['title']) {
                                $r = q("SELECT `title` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($it['parent-uri']), intval($uid));
                                if (count($r) and $r[0]['title'] != '') {
                                    $subject = $r[0]['title'];
                                } else {
                                    $r = q("SELECT `title` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($it['parent-uri']), intval($uid));
                                    if (count($r) and $r[0]['title'] != '') {
                                        $subject = $r[0]['title'];
                                    }
                                }
                            }
                            if (strncasecmp($subject, 'RE:', 3)) {
                                $subject = 'Re: ' . $subject;
                            }
                        }
                        email_send($addr, $subject, $headers, $it);
                    }
                    break;
                case NETWORK_DIASPORA:
                    if (get_config('system', 'dfrn_only') || !get_config('system', 'diaspora_enabled')) {
                        break;
                    }
                    if ($mail) {
                        diaspora_send_mail($item, $owner, $contact);
                        break;
                    }
                    if (!$normal_mode) {
                        break;
                    }
                    // special handling for followup to public post
                    // all other public posts processed as public batches further below
                    if ($public_message) {
                        if ($followup) {
                            diaspora_send_followup($target_item, $owner, $contact, true);
                        }
                        break;
                    }
                    if (!$contact['pubkey']) {
                        break;
                    }
                    $unsupported_activities = array(ACTIVITY_DISLIKE, ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE);
                    //don't transmit activities which are not supported by diaspora
                    foreach ($unsupported_activities as $act) {
                        if (activity_match($target_item['verb'], $act)) {
                            break 2;
                        }
                    }
                    if ($target_item['deleted'] && ($target_item['uri'] === $target_item['parent-uri'] || $followup)) {
                        // send both top-level retractions and relayable retractions for owner to relay
                        diaspora_send_retraction($target_item, $owner, $contact);
                        break;
                    } elseif ($followup) {
                        // send comments and likes to owner to relay
                        diaspora_send_followup($target_item, $owner, $contact);
                        break;
                    } elseif ($target_item['uri'] !== $target_item['parent-uri']) {
                        // we are the relay - send comments, likes and relayable_retractions
                        // (of comments and likes) to our conversants
                        diaspora_send_relay($target_item, $owner, $contact);
                        break;
                    } elseif ($top_level && !$walltowall) {
                        // currently no workable solution for sending walltowall
                        diaspora_send_status($target_item, $owner, $contact);
                        break;
                    }
                    break;
                case NETWORK_FEED:
                case NETWORK_FACEBOOK:
                    if (get_config('system', 'dfrn_only')) {
                        break;
                    }
                case NETWORK_PUMPIO:
                    if (get_config('system', 'dfrn_only')) {
                        break;
                    }
                default:
                    break;
            }
        }
    }
    // send additional slaps to mentioned remote tags (@foo@example.com)
    //if($slap && count($url_recipients) && ($followup || $top_level) && ($public_message || $push_notify) && (! $expire)) {
    if ($slap && count($url_recipients) && ($public_message || $push_notify) && !$expire) {
        if (!get_config('system', 'dfrn_only')) {
            foreach ($url_recipients as $url) {
                if ($url) {
                    logger('notifier: urldelivery: ' . $url);
                    $deliver_status = slapper($owner, $url, $slap);
                    // TODO: redeliver/queue these items on failure, though there is no contact record
                }
            }
        }
    }
    if ($public_message) {
        if (!$followup) {
            $r0 = diaspora_fetch_relay();
        } else {
            $r0 = array();
        }
        $r1 = q("SELECT DISTINCT(`batch`), `id`, `name`,`network` FROM `contact` WHERE `network` = '%s'\n\t\t\tAND `uid` = %d AND `rel` != %d group by `batch` ORDER BY rand() ", dbesc(NETWORK_DIASPORA), intval($owner['uid']), intval(CONTACT_IS_SHARING));
        $r2 = q("SELECT `id`, `name`,`network` FROM `contact`\n\t\t\tWHERE `network` in ( '%s', '%s')  AND `uid` = %d AND `blocked` = 0 AND `pending` = 0 AND `archive` = 0\n\t\t\tAND `rel` != %d order by rand() ", dbesc(NETWORK_DFRN), dbesc(NETWORK_MAIL2), intval($owner['uid']), intval(CONTACT_IS_SHARING));
        $r = array_merge($r2, $r1, $r0);
        if (count($r)) {
            logger('pubdeliver: ' . print_r($r, true), LOGGER_DEBUG);
            // throw everything into the queue in case we get killed
            foreach ($r as $rr) {
                if (!$mail && !$fsuggest && !$followup) {
                    q("insert into deliverq ( `cmd`,`item`,`contact` ) values ('%s', %d, %d )", dbesc($cmd), intval($item_id), intval($rr['id']));
                }
            }
            foreach ($r as $rr) {
                // except for Diaspora batch jobs
                // Don't deliver to folks who have already been delivered to
                if ($rr['network'] !== NETWORK_DIASPORA && in_array($rr['id'], $conversants)) {
                    logger('notifier: already delivered id=' . $rr['id']);
                    continue;
                }
                if (!$mail && !$fsuggest && !$followup) {
                    logger('notifier: delivery agent: ' . $rr['name'] . ' ' . $rr['id']);
                    proc_run('php', 'include/delivery.php', $cmd, $item_id, $rr['id']);
                    if ($interval) {
                        @time_sleep_until(microtime(true) + (double) $interval);
                    }
                }
            }
        }
        $push_notify = true;
    }
    if ($push_notify and strlen($hub)) {
        $hubs = explode(',', $hub);
        if (count($hubs)) {
            foreach ($hubs as $h) {
                $h = trim($h);
                if (!strlen($h)) {
                    continue;
                }
                if ($h === '[internal]') {
                    // Set push flag for PuSH subscribers to this topic,
                    // they will be notified in queue.php
                    q("UPDATE `push_subscriber` SET `push` = 1 " . "WHERE `nickname` = '%s'", dbesc($owner['nickname']));
                    logger('Activating internal PuSH for item ' . $item_id, LOGGER_DEBUG);
                } else {
                    $params = 'hub.mode=publish&hub.url=' . urlencode($a->get_baseurl() . '/dfrn_poll/' . $owner['nickname']);
                    post_url($h, $params);
                    logger('publish for item ' . $item_id . ' ' . $h . ' ' . $params . ' returned ' . $a->get_curl_code());
                }
                if (count($hubs) > 1) {
                    sleep(7);
                }
                // try and avoid multiple hubs responding at precisely the same time
            }
        }
        // Handling the pubsubhubbub requests
        proc_run('php', 'include/pubsubpublish.php');
    }
    // If the item was deleted, clean up the `sign` table
    if ($target_item['deleted']) {
        $r = q("DELETE FROM sign where `retract_iid` = %d", intval($target_item['id']));
    }
    logger('notifier: calling hooks', LOGGER_DEBUG);
    if ($normal_mode) {
        call_hooks('notifier_normal', $target_item);
    }
    call_hooks('notifier_end', $target_item);
    return;
}
示例#10
0
文件: item.php 项目: strk/friendica
function item_post(&$a)
{
    if (!local_user() && !remote_user() && !x($_REQUEST, 'commenter')) {
        return;
    }
    require_once 'include/security.php';
    $uid = local_user();
    if (x($_REQUEST, 'dropitems')) {
        $arr_drop = explode(',', $_REQUEST['dropitems']);
        drop_items($arr_drop);
        $json = array('success' => 1);
        echo json_encode($json);
        killme();
    }
    call_hooks('post_local_start', $_REQUEST);
    //	logger('postinput ' . file_get_contents('php://input'));
    logger('postvars ' . print_r($_REQUEST, true), LOGGER_DATA);
    $api_source = x($_REQUEST, 'api_source') && $_REQUEST['api_source'] ? true : false;
    $message_id = x($_REQUEST, 'message_id') && $api_source ? strip_tags($_REQUEST['message_id']) : '';
    $return_path = x($_REQUEST, 'return') ? $_REQUEST['return'] : '';
    $preview = x($_REQUEST, 'preview') ? intval($_REQUEST['preview']) : 0;
    // Check for doubly-submitted posts, and reject duplicates
    // Note that we have to ignore previews, otherwise nothing will post
    // after it's been previewed
    if (!$preview && x($_REQUEST['post_id_random'])) {
        if (x($_SESSION['post-random']) && $_SESSION['post-random'] == $_REQUEST['post_id_random']) {
            logger("item post: duplicate post", LOGGER_DEBUG);
            item_post_return($a->get_baseurl(), $api_source, $return_path);
        } else {
            $_SESSION['post-random'] = $_REQUEST['post_id_random'];
        }
    }
    /**
     * Is this a reply to something?
     */
    $parent = x($_REQUEST, 'parent') ? intval($_REQUEST['parent']) : 0;
    $parent_uri = x($_REQUEST, 'parent_uri') ? trim($_REQUEST['parent_uri']) : '';
    $parent_item = null;
    $parent_contact = null;
    $thr_parent = '';
    $parid = 0;
    $r = false;
    $objecttype = null;
    if ($parent || $parent_uri) {
        $objecttype = ACTIVITY_OBJ_COMMENT;
        if (!x($_REQUEST, 'type')) {
            $_REQUEST['type'] = 'net-comment';
        }
        if ($parent) {
            $r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1", intval($parent));
        } elseif ($parent_uri && local_user()) {
            // This is coming from an API source, and we are logged in
            $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($parent_uri), intval(local_user()));
        }
        // if this isn't the real parent of the conversation, find it
        if ($r !== false && count($r)) {
            $parid = $r[0]['parent'];
            $parent_uri = $r[0]['uri'];
            if ($r[0]['id'] != $r[0]['parent']) {
                $r = q("SELECT * FROM `item` WHERE `id` = `parent` AND `parent` = %d LIMIT 1", intval($parid));
            }
        }
        if ($r === false || !count($r)) {
            notice(t('Unable to locate original post.') . EOL);
            if (x($_REQUEST, 'return')) {
                goaway($a->get_baseurl() . "/" . $return_path);
            }
            killme();
        }
        $parent_item = $r[0];
        $parent = $r[0]['id'];
        // multi-level threading - preserve the info but re-parent to our single level threading
        //if(($parid) && ($parid != $parent))
        $thr_parent = $parent_uri;
        if ($parent_item['contact-id'] && $uid) {
            $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($parent_item['contact-id']), intval($uid));
            if (count($r)) {
                $parent_contact = $r[0];
                // If the contact id doesn't fit with the contact, then set the contact to null
                $thrparent = q("SELECT `author-link`, `network` FROM `item` WHERE `uri` = '%s' LIMIT 1", dbesc($thr_parent));
                if (count($thrparent) and $thrparent[0]["network"] === NETWORK_OSTATUS and normalise_link($parent_contact["url"]) != normalise_link($thrparent[0]["author-link"])) {
                    $parent_contact = null;
                    require_once "include/Scrape.php";
                    $probed_contact = probe_url($thrparent[0]["author-link"]);
                    if ($probed_contact["network"] != NETWORK_FEED) {
                        $parent_contact = $probed_contact;
                        $parent_contact["nurl"] = normalise_link($probed_contact["url"]);
                        $parent_contact["thumb"] = $probed_contact["photo"];
                        $parent_contact["micro"] = $probed_contact["photo"];
                    }
                    logger('parent contact: ' . print_r($parent_contact, true), LOGGER_DEBUG);
                } else {
                    logger('no contact found: ' . print_r($thrparent, true), LOGGER_DEBUG);
                }
            }
        }
    }
    if ($parent) {
        logger('mod_item: item_post parent=' . $parent);
    }
    $profile_uid = x($_REQUEST, 'profile_uid') ? intval($_REQUEST['profile_uid']) : 0;
    $post_id = x($_REQUEST, 'post_id') ? intval($_REQUEST['post_id']) : 0;
    $app = x($_REQUEST, 'source') ? strip_tags($_REQUEST['source']) : '';
    $extid = x($_REQUEST, 'extid') ? strip_tags($_REQUEST['extid']) : '';
    $allow_moderated = false;
    // here is where we are going to check for permission to post a moderated comment.
    // First check that the parent exists and it is a wall item.
    if (x($_REQUEST, 'commenter') && (!$parent || !$parent_item['wall'])) {
        notice(t('Permission denied.') . EOL);
        if (x($_REQUEST, 'return')) {
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        killme();
    }
    // Now check that it is a page_type of PAGE_BLOG, and that valid personal details
    // have been provided, and run any anti-spam plugins
    // TODO
    if (!can_write_wall($a, $profile_uid) && !$allow_moderated) {
        notice(t('Permission denied.') . EOL);
        if (x($_REQUEST, 'return')) {
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        killme();
    }
    // is this an edited post?
    $orig_post = null;
    if ($post_id) {
        $i = q("SELECT * FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($post_id));
        if (!count($i)) {
            killme();
        }
        $orig_post = $i[0];
    }
    $user = null;
    $r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($profile_uid));
    if (count($r)) {
        $user = $r[0];
    }
    if ($orig_post) {
        $str_group_allow = $orig_post['allow_gid'];
        $str_contact_allow = $orig_post['allow_cid'];
        $str_group_deny = $orig_post['deny_gid'];
        $str_contact_deny = $orig_post['deny_cid'];
        $location = $orig_post['location'];
        $coord = $orig_post['coord'];
        $verb = $orig_post['verb'];
        $objecttype = $orig_post['object-type'];
        $emailcc = $orig_post['emailcc'];
        $app = $orig_post['app'];
        $categories = $orig_post['file'];
        $title = notags(trim($_REQUEST['title']));
        $body = escape_tags(trim($_REQUEST['body']));
        $private = $orig_post['private'];
        $pubmail_enable = $orig_post['pubmail'];
        $network = $orig_post['network'];
        $guid = $orig_post['guid'];
        $extid = $orig_post['extid'];
    } else {
        // if coming from the API and no privacy settings are set,
        // use the user default permissions - as they won't have
        // been supplied via a form.
        if ($api_source && !array_key_exists('contact_allow', $_REQUEST) && !array_key_exists('group_allow', $_REQUEST) && !array_key_exists('contact_deny', $_REQUEST) && !array_key_exists('group_deny', $_REQUEST)) {
            $str_group_allow = $user['allow_gid'];
            $str_contact_allow = $user['allow_cid'];
            $str_group_deny = $user['deny_gid'];
            $str_contact_deny = $user['deny_cid'];
        } else {
            // use the posted permissions
            $str_group_allow = perms2str($_REQUEST['group_allow']);
            $str_contact_allow = perms2str($_REQUEST['contact_allow']);
            $str_group_deny = perms2str($_REQUEST['group_deny']);
            $str_contact_deny = perms2str($_REQUEST['contact_deny']);
        }
        $title = notags(trim($_REQUEST['title']));
        $location = notags(trim($_REQUEST['location']));
        $coord = notags(trim($_REQUEST['coord']));
        $verb = notags(trim($_REQUEST['verb']));
        $emailcc = notags(trim($_REQUEST['emailcc']));
        $body = escape_tags(trim($_REQUEST['body']));
        $network = notags(trim($_REQUEST['network']));
        $guid = get_guid(32);
        $naked_body = preg_replace('/\\[(.+?)\\]/', '', $body);
        if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
            $l = new Text_LanguageDetect();
            //$lng = $l->detectConfidence($naked_body);
            //$postopts = (($lng['language']) ? 'lang=' . $lng['language'] . ';' . $lng['confidence'] : '');
            $lng = $l->detect($naked_body, 3);
            if (sizeof($lng) > 0) {
                $postopts = "";
                foreach ($lng as $language => $score) {
                    if ($postopts == "") {
                        $postopts = "lang=";
                    } else {
                        $postopts .= ":";
                    }
                    $postopts .= $language . ";" . $score;
                }
            }
            logger('mod_item: detect language' . print_r($lng, true) . $naked_body, LOGGER_DATA);
        } else {
            $postopts = '';
        }
        $private = strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny) ? 1 : 0;
        if ($user['hidewall']) {
            $private = 2;
        }
        // If this is a comment, set the permissions from the parent.
        if ($parent_item) {
            $private = 0;
            // for non native networks use the network of the original post as network of the item
            if ($parent_item['network'] != NETWORK_DIASPORA and $parent_item['network'] != NETWORK_OSTATUS and $network == "") {
                $network = $parent_item['network'];
            }
            if ($parent_item['private'] || strlen($parent_item['allow_cid']) || strlen($parent_item['allow_gid']) || strlen($parent_item['deny_cid']) || strlen($parent_item['deny_gid'])) {
                $private = $parent_item['private'] ? $parent_item['private'] : 1;
            }
            $str_contact_allow = $parent_item['allow_cid'];
            $str_group_allow = $parent_item['allow_gid'];
            $str_contact_deny = $parent_item['deny_cid'];
            $str_group_deny = $parent_item['deny_gid'];
        }
        $pubmail_enable = x($_REQUEST, 'pubmail_enable') && intval($_REQUEST['pubmail_enable']) && !$private ? 1 : 0;
        // if using the API, we won't see pubmail_enable - figure out if it should be set
        if ($api_source && $profile_uid && $profile_uid == local_user() && !$private) {
            $mail_disabled = function_exists('imap_open') && !get_config('system', 'imap_disabled') ? 0 : 1;
            if (!$mail_disabled) {
                $r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1", intval(local_user()));
                if (count($r) && intval($r[0]['pubmail'])) {
                    $pubmail_enabled = true;
                }
            }
        }
        if (!strlen($body)) {
            if ($preview) {
                killme();
            }
            info(t('Empty post discarded.') . EOL);
            if (x($_REQUEST, 'return')) {
                goaway($a->get_baseurl() . "/" . $return_path);
            }
            killme();
        }
    }
    if (strlen($categories)) {
        // get the "fileas" tags for this post
        $filedas = file_tag_file_to_list($categories, 'file');
    }
    // save old and new categories, so we can determine what needs to be deleted from pconfig
    $categories_old = $categories;
    $categories = file_tag_list_to_file(trim($_REQUEST['category']), 'category');
    $categories_new = $categories;
    if (strlen($filedas)) {
        // append the fileas stuff to the new categories list
        $categories .= file_tag_list_to_file($filedas, 'file');
    }
    // Work around doubled linefeeds in Tinymce 3.5b2
    // First figure out if it's a status post that would've been
    // created using tinymce. Otherwise leave it alone.
    /*	$plaintext = (local_user() ? intval(get_pconfig(local_user(),'system','plaintext')) || !feature_enabled($profile_uid,'richtext') : 0);
    	if((! $parent) && (! $api_source) && (! $plaintext)) {
    		$body = fix_mce_lf($body);
    	}*/
    $plaintext = local_user() ? !feature_enabled($profile_uid, 'richtext') : 0;
    if (!$parent && !$api_source && !$plaintext) {
        $body = fix_mce_lf($body);
    }
    // get contact info for poster
    $author = null;
    $self = false;
    $contact_id = 0;
    if (local_user() && local_user() == $profile_uid) {
        $self = true;
        $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", intval($_SESSION['uid']));
    } elseif (remote_user()) {
        if (is_array($_SESSION['remote'])) {
            foreach ($_SESSION['remote'] as $v) {
                if ($v['uid'] == $profile_uid) {
                    $contact_id = $v['cid'];
                    break;
                }
            }
        }
        if ($contact_id) {
            $r = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1", intval($contact_id));
        }
    }
    if (count($r)) {
        $author = $r[0];
        $contact_id = $author['id'];
    }
    // get contact info for owner
    if ($profile_uid == local_user()) {
        $contact_record = $author;
    } else {
        $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", intval($profile_uid));
        if (count($r)) {
            $contact_record = $r[0];
        }
    }
    $post_type = notags(trim($_REQUEST['type']));
    if ($post_type === 'net-comment') {
        if ($parent_item !== null) {
            if ($parent_item['wall'] == 1) {
                $post_type = 'wall-comment';
            } else {
                $post_type = 'remote-comment';
            }
        }
    }
    /**
     *
     * When a photo was uploaded into the message using the (profile wall) ajax
     * uploader, The permissions are initially set to disallow anybody but the
     * owner from seeing it. This is because the permissions may not yet have been
     * set for the post. If it's private, the photo permissions should be set
     * appropriately. But we didn't know the final permissions on the post until
     * now. So now we'll look for links of uploaded messages that are in the
     * post and set them to the same permissions as the post itself.
     *
     */
    $match = null;
    if (!$preview && preg_match_all("/\\[img([\\=0-9x]*?)\\](.*?)\\[\\/img\\]/", $body, $match)) {
        $images = $match[2];
        if (count($images)) {
            $objecttype = ACTIVITY_OBJ_IMAGE;
            foreach ($images as $image) {
                if (!stristr($image, $a->get_baseurl() . '/photo/')) {
                    continue;
                }
                $image_uri = substr($image, strrpos($image, '/') + 1);
                $image_uri = substr($image_uri, 0, strpos($image_uri, '-'));
                if (!strlen($image_uri)) {
                    continue;
                }
                $srch = '<' . intval($contact_id) . '>';
                $r = q("SELECT `id` FROM `photo` WHERE `allow_cid` = '%s' AND `allow_gid` = '' AND `deny_cid` = '' AND `deny_gid` = ''\n\t\t\t\t\tAND `resource-id` = '%s' AND `uid` = %d LIMIT 1", dbesc($srch), dbesc($image_uri), intval($profile_uid));
                if (!count($r)) {
                    continue;
                }
                $r = q("UPDATE `photo` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s'\n\t\t\t\t\tWHERE `resource-id` = '%s' AND `uid` = %d AND `album` = '%s' ", dbesc($str_contact_allow), dbesc($str_group_allow), dbesc($str_contact_deny), dbesc($str_group_deny), dbesc($image_uri), intval($profile_uid), dbesc(t('Wall Photos')));
            }
        }
    }
    /**
     * Next link in any attachment references we find in the post.
     */
    $match = false;
    if (!$preview && preg_match_all("/\\[attachment\\](.*?)\\[\\/attachment\\]/", $body, $match)) {
        $attaches = $match[1];
        if (count($attaches)) {
            foreach ($attaches as $attach) {
                $r = q("SELECT * FROM `attach` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($attach));
                if (count($r)) {
                    $r = q("UPDATE `attach` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s'\n\t\t\t\t\t\tWHERE `uid` = %d AND `id` = %d", dbesc($str_contact_allow), dbesc($str_group_allow), dbesc($str_contact_deny), dbesc($str_group_deny), intval($profile_uid), intval($attach));
                }
            }
        }
    }
    // embedded bookmark in post? set bookmark flag
    $bookmark = 0;
    if (preg_match_all("/\\[bookmark\\=([^\\]]*)\\](.*?)\\[\\/bookmark\\]/ism", $body, $match, PREG_SET_ORDER)) {
        $objecttype = ACTIVITY_OBJ_BOOKMARK;
        $bookmark = 1;
    }
    $body = bb_translate_video($body);
    /**
     * Fold multi-line [code] sequences
     */
    $body = preg_replace('/\\[\\/code\\]\\s*\\[code\\]/ism', "\n", $body);
    $body = scale_external_images($body, false);
    // Setting the object type if not defined before
    if (!$objecttype) {
        $objecttype = ACTIVITY_OBJ_NOTE;
        // Default value
        require_once "include/plaintext.php";
        $objectdata = get_attached_data($body);
        if ($post["type"] == "link") {
            $objecttype = ACTIVITY_OBJ_BOOKMARK;
        } elseif ($post["type"] == "video") {
            $objecttype = ACTIVITY_OBJ_VIDEO;
        } elseif ($post["type"] == "photo") {
            $objecttype = ACTIVITY_OBJ_IMAGE;
        }
    }
    /**
     * Look for any tags and linkify them
     */
    $str_tags = '';
    $inform = '';
    $tags = get_tags($body);
    /**
     * add a statusnet style reply tag if the original post was from there
     * and we are replying, and there isn't one already
     */
    if ($parent_contact && $parent_contact['network'] === NETWORK_OSTATUS && $parent_contact['nick'] && !in_array('@' . $parent_contact['nick'], $tags)) {
        $body = '@' . $parent_contact['nick'] . ' ' . $body;
        $tags[] = '@' . $parent_contact['nick'];
    }
    $tagged = array();
    $private_forum = false;
    if (count($tags)) {
        foreach ($tags as $tag) {
            if (strpos($tag, '#') === 0) {
                continue;
            }
            // If we already tagged 'Robert Johnson', don't try and tag 'Robert'.
            // Robert Johnson should be first in the $tags array
            $fullnametagged = false;
            for ($x = 0; $x < count($tagged); $x++) {
                if (stristr($tagged[$x], $tag . ' ')) {
                    $fullnametagged = true;
                    break;
                }
            }
            if ($fullnametagged) {
                continue;
            }
            $success = handle_tag($a, $body, $inform, $str_tags, local_user() ? local_user() : $profile_uid, $tag, $network);
            if ($success['replaced']) {
                $tagged[] = $tag;
            }
            if (is_array($success['contact']) && intval($success['contact']['prv'])) {
                $private_forum = true;
                $private_id = $success['contact']['id'];
            }
        }
    }
    if ($private_forum && !$parent && !$private) {
        // we tagged a private forum in a top level post and the message was public.
        // Restrict it.
        $private = 1;
        $str_contact_allow = '<' . $private_id . '>';
    }
    $attachments = '';
    $match = false;
    if (preg_match_all('/(\\[attachment\\]([0-9]+)\\[\\/attachment\\])/', $body, $match)) {
        foreach ($match[2] as $mtch) {
            $r = q("SELECT `id`,`filename`,`filesize`,`filetype` FROM `attach` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($mtch));
            if (count($r)) {
                if (strlen($attachments)) {
                    $attachments .= ',';
                }
                $attachments .= '[attach]href="' . $a->get_baseurl() . '/attach/' . $r[0]['id'] . '" length="' . $r[0]['filesize'] . '" type="' . $r[0]['filetype'] . '" title="' . ($r[0]['filename'] ? $r[0]['filename'] : '') . '"[/attach]';
            }
            $body = str_replace($match[1], '', $body);
        }
    }
    $wall = 0;
    if ($post_type === 'wall' || $post_type === 'wall-comment') {
        $wall = 1;
    }
    if (!strlen($verb)) {
        $verb = ACTIVITY_POST;
    }
    if ($network == "") {
        $network = NETWORK_DFRN;
    }
    $gravity = $parent ? 6 : 0;
    // even if the post arrived via API we are considering that it
    // originated on this site by default for determining relayability.
    $origin = x($_REQUEST, 'origin') ? intval($_REQUEST['origin']) : 1;
    $notify_type = $parent ? 'comment-new' : 'wall-new';
    $uri = $message_id ? $message_id : item_new_uri($a->get_hostname(), $profile_uid);
    // Fallback so that we alway have a thr-parent
    if (!$thr_parent) {
        $thr_parent = $uri;
    }
    $datarray = array();
    $datarray['uid'] = $profile_uid;
    $datarray['type'] = $post_type;
    $datarray['wall'] = $wall;
    $datarray['gravity'] = $gravity;
    $datarray['network'] = $network;
    $datarray['contact-id'] = $contact_id;
    $datarray['owner-name'] = $contact_record['name'];
    $datarray['owner-link'] = $contact_record['url'];
    $datarray['owner-avatar'] = $contact_record['thumb'];
    $datarray['author-name'] = $author['name'];
    $datarray['author-link'] = $author['url'];
    $datarray['author-avatar'] = $author['thumb'];
    $datarray['created'] = datetime_convert();
    $datarray['edited'] = datetime_convert();
    $datarray['commented'] = datetime_convert();
    $datarray['received'] = datetime_convert();
    $datarray['changed'] = datetime_convert();
    $datarray['extid'] = $extid;
    $datarray['guid'] = $guid;
    $datarray['uri'] = $uri;
    $datarray['title'] = $title;
    $datarray['body'] = $body;
    $datarray['app'] = $app;
    $datarray['location'] = $location;
    $datarray['coord'] = $coord;
    $datarray['tag'] = $str_tags;
    $datarray['file'] = $categories;
    $datarray['inform'] = $inform;
    $datarray['verb'] = $verb;
    $datarray['object-type'] = $objecttype;
    $datarray['allow_cid'] = $str_contact_allow;
    $datarray['allow_gid'] = $str_group_allow;
    $datarray['deny_cid'] = $str_contact_deny;
    $datarray['deny_gid'] = $str_group_deny;
    $datarray['private'] = $private;
    $datarray['pubmail'] = $pubmail_enable;
    $datarray['attach'] = $attachments;
    $datarray['bookmark'] = intval($bookmark);
    $datarray['thr-parent'] = $thr_parent;
    $datarray['postopts'] = $postopts;
    $datarray['origin'] = $origin;
    $datarray['moderated'] = $allow_moderated;
    /**
     * These fields are for the convenience of plugins...
     * 'self' if true indicates the owner is posting on their own wall
     * If parent is 0 it is a top-level post.
     */
    $datarray['parent'] = $parent;
    $datarray['self'] = $self;
    //	$datarray['prvnets']       = $user['prvnets'];
    if ($orig_post) {
        $datarray['edit'] = true;
    }
    // Search for hashtags
    item_body_set_hashtags($datarray);
    // preview mode - prepare the body for display and send it via json
    if ($preview) {
        require_once 'include/conversation.php';
        $o = conversation($a, array(array_merge($contact_record, $datarray)), 'search', false, true);
        logger('preview: ' . $o);
        echo json_encode(array('preview' => $o));
        killme();
    }
    call_hooks('post_local', $datarray);
    if (x($datarray, 'cancel')) {
        logger('mod_item: post cancelled by plugin.');
        if ($return_path) {
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        $json = array('cancel' => 1);
        if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload'])) {
            $json['reload'] = $a->get_baseurl() . '/' . $_REQUEST['jsreload'];
        }
        echo json_encode($json);
        killme();
    }
    // Fill the cache field
    put_item_in_cache($datarray);
    if ($orig_post) {
        $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `attach` = '%s', `file` = '%s', `rendered-html` = '%s', `rendered-hash` = '%s', `edited` = '%s', `changed` = '%s' WHERE `id` = %d AND `uid` = %d", dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['tag']), dbesc($datarray['attach']), dbesc($datarray['file']), dbesc($datarray['rendered-html']), dbesc($datarray['rendered-hash']), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($post_id), intval($profile_uid));
        create_tags_from_item($post_id);
        create_files_from_item($post_id);
        update_thread($post_id);
        // update filetags in pconfig
        file_tag_update_pconfig($uid, $categories_old, $categories_new, 'category');
        proc_run('php', "include/notifier.php", 'edit_post', "{$post_id}");
        if (x($_REQUEST, 'return') && strlen($return_path)) {
            logger('return: ' . $return_path);
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        killme();
    } else {
        $post_id = 0;
    }
    $r = q("INSERT INTO `item` (`guid`, `extid`, `uid`,`type`,`wall`,`gravity`, `network`, `contact-id`,`owner-name`,`owner-link`,`owner-avatar`, `author-name`, `author-link`, `author-avatar`,\n\t\t`created`, `edited`, `commented`, `received`, `changed`, `uri`, `thr-parent`, `title`, `body`, `app`, `location`, `coord`, `tag`, `inform`, `verb`, `object-type`, `postopts`,\n\t\t`allow_cid`, `allow_gid`, `deny_cid`, `deny_gid`, `private`, `pubmail`, `attach`, `bookmark`,`origin`, `moderated`, `file`, `rendered-html`, `rendered-hash`)\n\t\tVALUES( '%s', '%s', %d, '%s', %d, %d, '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d, '%s', '%s', '%s')", dbesc($datarray['guid']), dbesc($datarray['extid']), intval($datarray['uid']), dbesc($datarray['type']), intval($datarray['wall']), intval($datarray['gravity']), dbesc($datarray['network']), intval($datarray['contact-id']), dbesc($datarray['owner-name']), dbesc($datarray['owner-link']), dbesc($datarray['owner-avatar']), dbesc($datarray['author-name']), dbesc($datarray['author-link']), dbesc($datarray['author-avatar']), dbesc($datarray['created']), dbesc($datarray['edited']), dbesc($datarray['commented']), dbesc($datarray['received']), dbesc($datarray['changed']), dbesc($datarray['uri']), dbesc($datarray['thr-parent']), dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['app']), dbesc($datarray['location']), dbesc($datarray['coord']), dbesc($datarray['tag']), dbesc($datarray['inform']), dbesc($datarray['verb']), dbesc($datarray['object-type']), dbesc($datarray['postopts']), dbesc($datarray['allow_cid']), dbesc($datarray['allow_gid']), dbesc($datarray['deny_cid']), dbesc($datarray['deny_gid']), intval($datarray['private']), intval($datarray['pubmail']), dbesc($datarray['attach']), intval($datarray['bookmark']), intval($datarray['origin']), intval($datarray['moderated']), dbesc($datarray['file']), dbesc($datarray['rendered-html']), dbesc($datarray['rendered-hash']));
    $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' LIMIT 1", dbesc($datarray['uri']));
    if (!count($r)) {
        logger('mod_item: unable to retrieve post that was just stored.');
        notice(t('System error. Post not saved.') . EOL);
        goaway($a->get_baseurl() . "/" . $return_path);
        // NOTREACHED
    }
    $post_id = $r[0]['id'];
    logger('mod_item: saved item ' . $post_id);
    $datarray["id"] = $post_id;
    $datarray["plink"] = $a->get_baseurl() . '/display/' . urlencode($datarray["guid"]);
    // update filetags in pconfig
    file_tag_update_pconfig($uid, $categories_old, $categories_new, 'category');
    if ($parent) {
        // This item is the last leaf and gets the comment box, clear any ancestors
        $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent` = %d ", dbesc(datetime_convert()), intval($parent));
        update_thread($parent, true);
        // Inherit ACLs from the parent item.
        $r = q("UPDATE `item` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s', `private` = %d\n\t\t\tWHERE `id` = %d", dbesc($parent_item['allow_cid']), dbesc($parent_item['allow_gid']), dbesc($parent_item['deny_cid']), dbesc($parent_item['deny_gid']), intval($parent_item['private']), intval($post_id));
        if ($contact_record != $author) {
            notification(array('type' => NOTIFY_COMMENT, 'notify_flags' => $user['notify-flags'], 'language' => $user['language'], 'to_name' => $user['username'], 'to_email' => $user['email'], 'uid' => $user['uid'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . urlencode($datarray['guid']), 'source_name' => $datarray['author-name'], 'source_link' => $datarray['author-link'], 'source_photo' => $datarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item', 'parent' => $parent, 'parent_uri' => $parent_item['uri']));
        }
        // Store the comment signature information in case we need to relay to Diaspora
        store_diaspora_comment_sig($datarray, $author, $self ? $a->user['prvkey'] : false, $parent_item, $post_id);
    } else {
        $parent = $post_id;
        if ($contact_record != $author) {
            notification(array('type' => NOTIFY_WALL, 'notify_flags' => $user['notify-flags'], 'language' => $user['language'], 'to_name' => $user['username'], 'to_email' => $user['email'], 'uid' => $user['uid'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . urlencode($datarray['guid']), 'source_name' => $datarray['author-name'], 'source_link' => $datarray['author-link'], 'source_photo' => $datarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item'));
        }
    }
    // fallback so that parent always gets set to non-zero.
    if (!$parent) {
        $parent = $post_id;
    }
    $r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s', `plink` = '%s', `changed` = '%s', `last-child` = 1, `visible` = 1\n\t\tWHERE `id` = %d", intval($parent), dbesc($parent == $post_id ? $uri : $parent_item['uri']), dbesc($a->get_baseurl() . '/display/' . urlencode($datarray['guid'])), dbesc(datetime_convert()), intval($post_id));
    // photo comments turn the corresponding item visible to the profile wall
    // This way we don't see every picture in your new photo album posted to your wall at once.
    // They will show up as people comment on them.
    if (!$parent_item['visible']) {
        $r = q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d", intval($parent_item['id']));
        update_thread($parent_item['id']);
    }
    // update the commented timestamp on the parent
    q("UPDATE `item` set `commented` = '%s', `changed` = '%s' WHERE `id` = %d", dbesc(datetime_convert()), dbesc(datetime_convert()), intval($parent));
    if ($post_id != $parent) {
        update_thread($parent);
    }
    call_hooks('post_local_end', $datarray);
    if (strlen($emailcc) && $profile_uid == local_user()) {
        $erecips = explode(',', $emailcc);
        if (count($erecips)) {
            foreach ($erecips as $recip) {
                $addr = trim($recip);
                if (!strlen($addr)) {
                    continue;
                }
                $disclaimer = '<hr />' . sprintf(t('This message was sent to you by %s, a member of the Friendica social network.'), $a->user['username']) . '<br />';
                $disclaimer .= sprintf(t('You may visit them online at %s'), $a->get_baseurl() . '/profile/' . $a->user['nickname']) . EOL;
                $disclaimer .= t('Please contact the sender by replying to this post if you do not wish to receive these messages.') . EOL;
                if (!$datarray['title'] == '') {
                    $subject = email_header_encode($datarray['title'], 'UTF-8');
                } else {
                    $subject = email_header_encode('[Friendica]' . ' ' . sprintf(t('%s posted an update.'), $a->user['username']), 'UTF-8');
                }
                $link = '<a href="' . $a->get_baseurl() . '/profile/' . $a->user['nickname'] . '"><img src="' . $author['thumb'] . '" alt="' . $a->user['username'] . '" /></a><br /><br />';
                $html = prepare_body($datarray);
                $message = '<html><body>' . $link . $html . $disclaimer . '</body></html>';
                include_once 'include/html2plain.php';
                $params = array('fromName' => $a->user['username'], 'fromEmail' => $a->user['email'], 'toEmail' => $addr, 'replyTo' => $a->user['email'], 'messageSubject' => $subject, 'htmlVersion' => $message, 'textVersion' => html2plain($html . $disclaimer));
                Emailer::send($params);
            }
        }
    }
    create_tags_from_item($post_id);
    create_files_from_item($post_id);
    if ($post_id == $parent) {
        add_thread($post_id);
    }
    // This is a real juggling act on shared hosting services which kill your processes
    // e.g. dreamhost. We used to start delivery to our native delivery agents in the background
    // and then run our plugin delivery from the foreground. We're now doing plugin delivery first,
    // because as soon as you start loading up a bunch of remote delivey processes, *this* page is
    // likely to get killed off. If you end up looking at an /item URL and a blank page,
    // it's very likely the delivery got killed before all your friends could be notified.
    // Currently the only realistic fixes are to use a reliable server - which precludes shared hosting,
    // or cut back on plugins which do remote deliveries.
    proc_run('php', "include/notifier.php", $notify_type, "{$post_id}");
    logger('post_complete');
    item_post_return($a->get_baseurl(), $api_source, $return_path);
    // NOTREACHED
}
示例#11
0
 /**
  * Send a multipart/alternative message with Text and HTML versions
  *
  * @param fromName			name of the sender
  * @param fromEmail			email fo the sender
  * @param replyTo			replyTo address to direct responses
  * @param toEmail			destination email address
  * @param messageSubject	subject of the message
  * @param htmlVersion		html version of the message
  * @param textVersion		text only version of the message
  */
 public static function send($params)
 {
     $fromName = email_header_encode($params['fromName'], 'UTF-8');
     $messageSubject = email_header_encode($params['messageSubject'], 'UTF-8');
     // generate a mime boundary
     $mimeBoundary = rand(0, 9) . "-" . rand(10000000000.0, 9999999999.0) . "-" . rand(10000000000.0, 9999999999.0) . "=:" . rand(10000, 99999);
     // generate a multipart/alternative message header
     $messageHeader = "From: {$params['fromName']} <{$params['fromEmail']}>\n" . "Reply-To: {$params['fromName']} <{$params['replyTo']}>\n" . "MIME-Version: 1.0\n" . "Content-Type: multipart/alternative; boundary=\"{$mimeBoundary}\"";
     // assemble the final multipart message body with the text and html types included
     $textBody = chunk_split(base64_encode($params['textVersion']));
     $htmlBody = chunk_split(base64_encode($params['htmlVersion']));
     $multipartMessageBody = "--" . $mimeBoundary . "\n" . "Content-Type: text/plain; charset=UTF-8\n" . "Content-Transfer-Encoding: base64\n\n" . $textBody . "\n" . "--" . $mimeBoundary . "\n" . "Content-Type: text/html; charset=UTF-8\n" . "Content-Transfer-Encoding: base64\n\n" . $htmlBody . "\n" . "--" . $mimeBoundary . "--\n";
     // message ending
     // send the message
     $res = mail($params['toEmail'], $params['messageSubject'], $multipartMessageBody, $messageHeader);
     logger("notification: enotify::send returns " . $res, LOGGER_DEBUG);
 }
示例#12
0
function z_mail($params)
{
    /**
     * @brief Send a text email message
     *
     * @param array $params an assoziative array with:
     *  * \e string \b fromName        name of the sender
     *  * \e string \b fromEmail       email of the sender
     *  * \e string \b replyTo         replyTo address to direct responses
     *  * \e string \b toEmail         destination email address
     *  * \e string \b messageSubject  subject of the message
     *  * \e string \b htmlVersion     html version of the message
     *  * \e string \b textVersion     text only version of the message
     *  * \e string \b additionalMailHeader  additions to the smtp mail header
     */
    if (!$params['fromEmail']) {
        $params['fromEmail'] = get_config('system', 'from_email');
        if (!$params['fromEmail']) {
            $params['fromEmail'] = 'Administrator' . '@' . App::get_hostname();
        }
    }
    if (!$params['fromName']) {
        $params['fromName'] = get_config('system', 'from_email_name');
        if (!$params['fromName']) {
            $params['fromName'] = Zotlabs\Lib\System::get_site_name();
        }
    }
    if (!$params['replyTo']) {
        $params['replyTo'] = get_config('system', 'reply_address');
        if (!$params['replyTo']) {
            $params['replyTo'] = 'noreply' . '@' . App::get_hostname();
        }
    }
    $params['sent'] = false;
    $params['result'] = false;
    call_hooks('email_send', $params);
    if ($params['sent']) {
        logger('notification: z_mail returns ' . $params['result'], LOGGER_DEBUG);
        return $params['result'];
    }
    $fromName = email_header_encode(html_entity_decode($params['fromName'], ENT_QUOTES, 'UTF-8'), 'UTF-8');
    $messageSubject = email_header_encode(html_entity_decode($params['messageSubject'], ENT_QUOTES, 'UTF-8'), 'UTF-8');
    $messageHeader = $params['additionalMailHeader'] . "From: {$fromName} <{$params['fromEmail']}>\n" . "Reply-To: {$fromName} <{$params['replyTo']}>";
    // send the message
    $res = mail($params['toEmail'], $messageSubject, $params['textVersion'], $messageHeader);
    logger('notification: z_mail returns ' . $res, LOGGER_DEBUG);
    return $res;
}
示例#13
0
function item_post(&$a)
{
    if (!local_user() && !remote_user() && !x($_REQUEST, 'commenter')) {
        return;
    }
    require_once 'include/security.php';
    $uid = local_user();
    if (x($_REQUEST, 'dropitems')) {
        require_once 'include/items.php';
        $arr_drop = explode(',', $_REQUEST['dropitems']);
        drop_items($arr_drop);
        $json = array('success' => 1);
        echo json_encode($json);
        killme();
    }
    call_hooks('post_local_start', $_REQUEST);
    //	logger('postinput ' . file_get_contents('php://input'));
    logger('postvars ' . print_r($_REQUEST, true), LOGGER_DATA);
    $api_source = x($_REQUEST, 'api_source') && $_REQUEST['api_source'] ? true : false;
    $return_path = x($_REQUEST, 'return') ? $_REQUEST['return'] : '';
    $preview = x($_REQUEST, 'preview') ? intval($_REQUEST['preview']) : 0;
    /**
     * Is this a reply to something?
     */
    $parent = x($_REQUEST, 'parent') ? intval($_REQUEST['parent']) : 0;
    $parent_uri = x($_REQUEST, 'parent_uri') ? trim($_REQUEST['parent_uri']) : '';
    $parent_item = null;
    $parent_contact = null;
    $thr_parent = '';
    $parid = 0;
    $r = false;
    if ($parent || $parent_uri) {
        if (!x($_REQUEST, 'type')) {
            $_REQUEST['type'] = 'net-comment';
        }
        if ($parent) {
            $r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1", intval($parent));
        } elseif ($parent_uri && local_user()) {
            // This is coming from an API source, and we are logged in
            $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($parent_uri), intval(local_user()));
        }
        // if this isn't the real parent of the conversation, find it
        if ($r !== false && count($r)) {
            $parid = $r[0]['parent'];
            if ($r[0]['id'] != $r[0]['parent']) {
                $r = q("SELECT * FROM `item` WHERE `id` = `parent` AND `parent` = %d LIMIT 1", intval($parid));
            }
        }
        if ($r === false || !count($r)) {
            notice(t('Unable to locate original post.') . EOL);
            if (x($_REQUEST, 'return')) {
                goaway($a->get_baseurl() . "/" . $return_path);
            }
            killme();
        }
        $parent_item = $r[0];
        $parent = $r[0]['id'];
        // multi-level threading - preserve the info but re-parent to our single level threading
        if ($parid && $parid != $parent) {
            $thr_parent = $parent_uri;
        }
        if ($parent_item['contact-id'] && $uid) {
            $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($parent_item['contact-id']), intval($uid));
            if (count($r)) {
                $parent_contact = $r[0];
            }
        }
    }
    if ($parent) {
        logger('mod_post: parent=' . $parent);
    }
    $profile_uid = x($_REQUEST, 'profile_uid') ? intval($_REQUEST['profile_uid']) : 0;
    $post_id = x($_REQUEST, 'post_id') ? intval($_REQUEST['post_id']) : 0;
    $app = x($_REQUEST, 'source') ? strip_tags($_REQUEST['source']) : '';
    $allow_moderated = false;
    // here is where we are going to check for permission to post a moderated comment.
    // First check that the parent exists and it is a wall item.
    if (x($_REQUEST, 'commenter') && (!$parent || !$parent_item['wall'])) {
        notice(t('Permission denied.') . EOL);
        if (x($_REQUEST, 'return')) {
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        killme();
    }
    // Now check that it is a page_type of PAGE_BLOG, and that valid personal details
    // have been provided, and run any anti-spam plugins
    // TODO
    if (!can_write_wall($a, $profile_uid) && !$allow_moderated) {
        notice(t('Permission denied.') . EOL);
        if (x($_REQUEST, 'return')) {
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        killme();
    }
    // is this an edited post?
    $orig_post = null;
    if ($post_id) {
        $i = q("SELECT * FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($post_id));
        if (!count($i)) {
            killme();
        }
        $orig_post = $i[0];
    }
    $user = null;
    $r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($profile_uid));
    if (count($r)) {
        $user = $r[0];
    }
    if ($orig_post) {
        $str_group_allow = $orig_post['allow_gid'];
        $str_contact_allow = $orig_post['allow_cid'];
        $str_group_deny = $orig_post['deny_gid'];
        $str_contact_deny = $orig_post['deny_cid'];
        $title = $orig_post['title'];
        $location = $orig_post['location'];
        $coord = $orig_post['coord'];
        $verb = $orig_post['verb'];
        $emailcc = $orig_post['emailcc'];
        $app = $orig_post['app'];
        $body = escape_tags(trim($_REQUEST['body']));
        $private = $orig_post['private'];
        $pubmail_enable = $orig_post['pubmail'];
    } else {
        // if coming from the API and no privacy settings are set,
        // use the user default permissions - as they won't have
        // been supplied via a form.
        if ($api_source && !array_key_exists('contact_allow', $_REQUEST) && !array_key_exists('group_allow', $_REQUEST) && !array_key_exists('contact_deny', $_REQUEST) && !array_key_exists('group_deny', $_REQUEST)) {
            $str_group_allow = $user['allow_gid'];
            $str_contact_allow = $user['allow_cid'];
            $str_group_deny = $user['deny_gid'];
            $str_contact_deny = $user['deny_cid'];
        } else {
            // use the posted permissions
            $str_group_allow = perms2str($_REQUEST['group_allow']);
            $str_contact_allow = perms2str($_REQUEST['contact_allow']);
            $str_group_deny = perms2str($_REQUEST['group_deny']);
            $str_contact_deny = perms2str($_REQUEST['contact_deny']);
        }
        $title = notags(trim($_REQUEST['title']));
        $location = notags(trim($_REQUEST['location']));
        $coord = notags(trim($_REQUEST['coord']));
        $verb = notags(trim($_REQUEST['verb']));
        $emailcc = notags(trim($_REQUEST['emailcc']));
        $body = escape_tags(trim($_REQUEST['body']));
        $private = strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny) ? 1 : 0;
        if ($parent_item && ($parent_item['private'] || strlen($parent_item['allow_cid']) || strlen($parent_item['allow_gid']) || strlen($parent_item['deny_cid']) || strlen($parent_item['deny_gid']))) {
            $private = 1;
        }
        $pubmail_enable = x($_REQUEST, 'pubmail_enable') && intval($_REQUEST['pubmail_enable']) && !$private ? 1 : 0;
        // if using the API, we won't see pubmail_enable - figure out if it should be set
        if ($api_source && $profile_uid && $profile_uid == local_user() && !$private) {
            $mail_disabled = function_exists('imap_open') && !get_config('system', 'imap_disabled') ? 0 : 1;
            if (!$mail_disabled) {
                $r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1", intval(local_user()));
                if (count($r) && intval($r[0]['pubmail'])) {
                    $pubmail_enabled = true;
                }
            }
        }
        if (!strlen($body)) {
            if ($preview) {
                killme();
            }
            info(t('Empty post discarded.') . EOL);
            if (x($_REQUEST, 'return')) {
                goaway($a->get_baseurl() . "/" . $return_path);
            }
            killme();
        }
    }
    // get contact info for poster
    $author = null;
    $self = false;
    if ($_SESSION['uid'] && $_SESSION['uid'] == $profile_uid) {
        $self = true;
        $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", intval($_SESSION['uid']));
    } else {
        if (x($_SESSION, 'visitor_id') && intval($_SESSION['visitor_id'])) {
            $r = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1", intval($_SESSION['visitor_id']));
        }
    }
    if (count($r)) {
        $author = $r[0];
        $contact_id = $author['id'];
    }
    // get contact info for owner
    if ($profile_uid == $_SESSION['uid']) {
        $contact_record = $author;
    } else {
        $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 1 LIMIT 1", intval($profile_uid));
        if (count($r)) {
            $contact_record = $r[0];
        }
    }
    $post_type = notags(trim($_REQUEST['type']));
    if ($post_type === 'net-comment') {
        if ($parent_item !== null) {
            if ($parent_item['wall'] == 1) {
                $post_type = 'wall-comment';
            } else {
                $post_type = 'remote-comment';
            }
        }
    }
    /**
     *
     * When a photo was uploaded into the message using the (profile wall) ajax 
     * uploader, The permissions are initially set to disallow anybody but the
     * owner from seeing it. This is because the permissions may not yet have been
     * set for the post. If it's private, the photo permissions should be set
     * appropriately. But we didn't know the final permissions on the post until
     * now. So now we'll look for links of uploaded messages that are in the
     * post and set them to the same permissions as the post itself.
     *
     */
    $match = null;
    if (!$preview && preg_match_all("/\\[img\\](.*?)\\[\\/img\\]/", $body, $match)) {
        $images = $match[1];
        if (count($images)) {
            foreach ($images as $image) {
                if (!stristr($image, $a->get_baseurl() . '/photo/')) {
                    continue;
                }
                $image_uri = substr($image, strrpos($image, '/') + 1);
                $image_uri = substr($image_uri, 0, strpos($image_uri, '-'));
                if (!strlen($image_uri)) {
                    continue;
                }
                $srch = '<' . intval($profile_uid) . '>';
                $r = q("SELECT `id` FROM `photo` WHERE `allow_cid` = '%s' AND `allow_gid` = '' AND `deny_cid` = '' AND `deny_gid` = ''\n\t\t\t\t\tAND `resource-id` = '%s' AND `uid` = %d LIMIT 1", dbesc($srch), dbesc($image_uri), intval($profile_uid));
                if (!count($r)) {
                    continue;
                }
                $r = q("UPDATE `photo` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s'\n\t\t\t\t\tWHERE `resource-id` = '%s' AND `uid` = %d AND `album` = '%s' ", dbesc($str_contact_allow), dbesc($str_group_allow), dbesc($str_contact_deny), dbesc($str_group_deny), dbesc($image_uri), intval($profile_uid), dbesc(t('Wall Photos')));
            }
        }
    }
    /**
     * Next link in any attachment references we find in the post.
     */
    $match = false;
    if (!$preview && preg_match_all("/\\[attachment\\](.*?)\\[\\/attachment\\]/", $body, $match)) {
        $attaches = $match[1];
        if (count($attaches)) {
            foreach ($attaches as $attach) {
                $r = q("SELECT * FROM `attach` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($attach));
                if (count($r)) {
                    $r = q("UPDATE `attach` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s'\n\t\t\t\t\t\tWHERE `uid` = %d AND `id` = %d LIMIT 1", dbesc($str_contact_allow), dbesc($str_group_allow), dbesc($str_contact_deny), dbesc($str_group_deny), intval($profile_uid), intval($attach));
                }
            }
        }
    }
    // embedded bookmark in post? set bookmark flag
    $bookmark = 0;
    if (preg_match_all("/\\[bookmark\\=([^\\]]*)\\](.*?)\\[\\/bookmark\\]/ism", $body, $match, PREG_SET_ORDER)) {
        $bookmark = 1;
    }
    $body = bb_translate_video($body);
    /**
     * Fold multi-line [code] sequences
     */
    $body = preg_replace('/\\[\\/code\\]\\s*\\[code\\]/ism', "\n", $body);
    /**
     * Look for any tags and linkify them
     */
    $str_tags = '';
    $inform = '';
    $tags = get_tags($body);
    /**
     * add a statusnet style reply tag if the original post was from there
     * and we are replying, and there isn't one already
     */
    if ($parent_contact && $parent_contact['network'] === NETWORK_OSTATUS && $parent_contact['nick'] && !in_array('@' . $parent_contact['nick'], $tags)) {
        $body = '@' . $parent_contact['nick'] . ' ' . $body;
        $tags[] = '@' . $parent_contact['nick'];
    }
    if (count($tags)) {
        foreach ($tags as $tag) {
            if (isset($profile)) {
                unset($profile);
            }
            if (strpos($tag, '#') === 0) {
                if (strpos($tag, '[url=')) {
                    continue;
                }
                $basetag = str_replace('_', ' ', substr($tag, 1));
                $body = str_replace($tag, '#[url=' . $a->get_baseurl() . '/search?search=' . rawurlencode($basetag) . ']' . $basetag . '[/url]', $body);
                $newtag = '#[url=' . $a->get_baseurl() . '/search?search=' . rawurlencode($basetag) . ']' . $basetag . '[/url]';
                if (!stristr($str_tags, $newtag)) {
                    if (strlen($str_tags)) {
                        $str_tags .= ',';
                    }
                    $str_tags .= $newtag;
                }
                continue;
            }
            if (strpos($tag, '@') === 0) {
                if (strpos($tag, '[url=')) {
                    continue;
                }
                $stat = false;
                $name = substr($tag, 1);
                if (strpos($name, '@') || strpos($name, 'http://')) {
                    $newname = $name;
                    $links = @lrdd($name);
                    if (count($links)) {
                        foreach ($links as $link) {
                            if ($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page') {
                                $profile = $link['@attributes']['href'];
                            }
                            if ($link['@attributes']['rel'] === 'salmon') {
                                if (strlen($inform)) {
                                    $inform .= ',';
                                }
                                $inform .= 'url:' . str_replace(',', '%2c', $link['@attributes']['href']);
                            }
                        }
                    }
                } else {
                    $newname = $name;
                    $alias = '';
                    $tagcid = 0;
                    if (strrpos($newname, '+')) {
                        $tagcid = intval(substr($newname, strrpos($newname, '+') + 1));
                        if (strpos($name, ' ')) {
                            $name = substr($name, 0, strpos($name, ' '));
                        }
                    }
                    if ($tagcid) {
                        $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($tagcid), intval($profile_uid));
                    } elseif (strstr($name, '_') || strstr($name, ' ')) {
                        $newname = str_replace('_', ' ', $name);
                        $r = q("SELECT * FROM `contact` WHERE `name` = '%s' AND `uid` = %d LIMIT 1", dbesc($newname), intval($profile_uid));
                    } else {
                        $r = q("SELECT * FROM `contact` WHERE `attag` = '%s' OR `nick` = '%s' AND `uid` = %d ORDER BY `attag` DESC LIMIT 1", dbesc($name), dbesc($name), intval($profile_uid));
                    }
                    if (count($r)) {
                        $profile = $r[0]['url'];
                        if ($r[0]['network'] === 'stat') {
                            $newname = $r[0]['nick'];
                            $stat = true;
                            if ($r[0]['alias']) {
                                $alias = $r[0]['alias'];
                            }
                        } else {
                            $newname = $r[0]['name'];
                        }
                        if (strlen($inform)) {
                            $inform .= ',';
                        }
                        $inform .= 'cid:' . $r[0]['id'];
                    }
                }
                if ($profile) {
                    $body = str_replace('@' . $name, '@' . '[url=' . $profile . ']' . $newname . '[/url]', $body);
                    $profile = str_replace(',', '%2c', $profile);
                    $newtag = '@[url=' . $profile . ']' . $newname . '[/url]';
                    if (!stristr($str_tags, $newtag)) {
                        if (strlen($str_tags)) {
                            $str_tags .= ',';
                        }
                        $str_tags .= $newtag;
                    }
                    // Status.Net seems to require the numeric ID URL in a mention if the person isn't
                    // subscribed to you. But the nickname URL is OK if they are. Grrr. We'll tag both.
                    if (strlen($alias)) {
                        $newtag = '@[url=' . $alias . ']' . $newname . '[/url]';
                        if (!stristr($str_tags, $newtag)) {
                            if (strlen($str_tags)) {
                                $str_tags .= ',';
                            }
                            $str_tags .= $newtag;
                        }
                    }
                }
            }
        }
    }
    $attachments = '';
    $match = false;
    if (preg_match_all('/(\\[attachment\\]([0-9]+)\\[\\/attachment\\])/', $body, $match)) {
        foreach ($match[2] as $mtch) {
            $r = q("SELECT `id`,`filename`,`filesize`,`filetype` FROM `attach` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($profile_uid), intval($mtch));
            if (count($r)) {
                if (strlen($attachments)) {
                    $attachments .= ',';
                }
                $attachments .= '[attach]href="' . $a->get_baseurl() . '/attach/' . $r[0]['id'] . '" length="' . $r[0]['filesize'] . '" type="' . $r[0]['filetype'] . '" title="' . ($r[0]['filename'] ? $r[0]['filename'] : '') . '"[/attach]';
            }
            $body = str_replace($match[1], '', $body);
        }
    }
    $wall = 0;
    if ($post_type === 'wall' || $post_type === 'wall-comment') {
        $wall = 1;
    }
    if (!strlen($verb)) {
        $verb = ACTIVITY_POST;
    }
    $gravity = $parent ? 6 : 0;
    // even if the post arrived via API we are considering that it
    // originated on this site by default for determining relayability.
    $origin = x($_REQUEST, 'origin') ? intval($_REQUEST['origin']) : 1;
    $notify_type = $parent ? 'comment-new' : 'wall-new';
    $uri = item_new_uri($a->get_hostname(), $profile_uid);
    $datarray = array();
    $datarray['uid'] = $profile_uid;
    $datarray['type'] = $post_type;
    $datarray['wall'] = $wall;
    $datarray['gravity'] = $gravity;
    $datarray['contact-id'] = $contact_id;
    $datarray['owner-name'] = $contact_record['name'];
    $datarray['owner-link'] = $contact_record['url'];
    $datarray['owner-avatar'] = $contact_record['thumb'];
    $datarray['author-name'] = $author['name'];
    $datarray['author-link'] = $author['url'];
    $datarray['author-avatar'] = $author['thumb'];
    $datarray['created'] = datetime_convert();
    $datarray['edited'] = datetime_convert();
    $datarray['commented'] = datetime_convert();
    $datarray['received'] = datetime_convert();
    $datarray['changed'] = datetime_convert();
    $datarray['uri'] = $uri;
    $datarray['title'] = $title;
    $datarray['body'] = $body;
    $datarray['app'] = $app;
    $datarray['location'] = $location;
    $datarray['coord'] = $coord;
    $datarray['tag'] = $str_tags;
    $datarray['inform'] = $inform;
    $datarray['verb'] = $verb;
    $datarray['allow_cid'] = $str_contact_allow;
    $datarray['allow_gid'] = $str_group_allow;
    $datarray['deny_cid'] = $str_contact_deny;
    $datarray['deny_gid'] = $str_group_deny;
    $datarray['private'] = $private;
    $datarray['pubmail'] = $pubmail_enable;
    $datarray['attach'] = $attachments;
    $datarray['bookmark'] = intval($bookmark);
    $datarray['thr-parent'] = $thr_parent;
    $datarray['postopts'] = '';
    $datarray['origin'] = $origin;
    $datarray['moderated'] = $allow_moderated;
    /**
     * These fields are for the convenience of plugins...
     * 'self' if true indicates the owner is posting on their own wall
     * If parent is 0 it is a top-level post.
     */
    $datarray['parent'] = $parent;
    $datarray['self'] = $self;
    //	$datarray['prvnets']       = $user['prvnets'];
    if ($orig_post) {
        $datarray['edit'] = true;
    } else {
        $datarray['guid'] = get_guid();
    }
    // preview mode - prepare the body for display and send it via json
    if ($preview) {
        require_once 'include/conversation.php';
        $o = conversation(&$a, array(array_merge($contact_record, $datarray)), 'search', false, true);
        logger('preview: ' . $o);
        echo json_encode(array('preview' => $o));
        killme();
    }
    call_hooks('post_local', $datarray);
    if (x($datarray, 'cancel')) {
        logger('mod_item: post cancelled by plugin.');
        if ($return_path) {
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        $json = array('cancel' => 1);
        if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload'])) {
            $json['reload'] = $a->get_baseurl() . '/' . $_REQUEST['jsreload'];
        }
        echo json_encode($json);
        killme();
    }
    if ($orig_post) {
        $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `edited` = '%s' WHERE `id` = %d AND `uid` = %d LIMIT 1", dbesc($title), dbesc($body), dbesc(datetime_convert()), intval($post_id), intval($profile_uid));
        proc_run('php', "include/notifier.php", 'edit_post', "{$post_id}");
        if (x($_REQUEST, 'return') && strlen($return_path)) {
            logger('return: ' . $return_path);
            goaway($a->get_baseurl() . "/" . $return_path);
        }
        killme();
    } else {
        $post_id = 0;
    }
    $r = q("INSERT INTO `item` (`guid`, `uid`,`type`,`wall`,`gravity`,`contact-id`,`owner-name`,`owner-link`,`owner-avatar`, \n\t\t`author-name`, `author-link`, `author-avatar`, `created`, `edited`, `commented`, `received`, `changed`, `uri`, `thr-parent`, `title`, `body`, `app`, `location`, `coord`, \n\t\t`tag`, `inform`, `verb`, `postopts`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid`, `private`, `pubmail`, `attach`, `bookmark`,`origin`, `moderated` )\n\t\tVALUES( '%s', %d, '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d )", dbesc($datarray['guid']), intval($datarray['uid']), dbesc($datarray['type']), intval($datarray['wall']), intval($datarray['gravity']), intval($datarray['contact-id']), dbesc($datarray['owner-name']), dbesc($datarray['owner-link']), dbesc($datarray['owner-avatar']), dbesc($datarray['author-name']), dbesc($datarray['author-link']), dbesc($datarray['author-avatar']), dbesc($datarray['created']), dbesc($datarray['edited']), dbesc($datarray['commented']), dbesc($datarray['received']), dbesc($datarray['changed']), dbesc($datarray['uri']), dbesc($datarray['thr-parent']), dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['app']), dbesc($datarray['location']), dbesc($datarray['coord']), dbesc($datarray['tag']), dbesc($datarray['inform']), dbesc($datarray['verb']), dbesc($datarray['postopts']), dbesc($datarray['allow_cid']), dbesc($datarray['allow_gid']), dbesc($datarray['deny_cid']), dbesc($datarray['deny_gid']), intval($datarray['private']), intval($datarray['pubmail']), dbesc($datarray['attach']), intval($datarray['bookmark']), intval($datarray['origin']), intval($datarry['moderated']));
    $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' LIMIT 1", dbesc($datarray['uri']));
    if (count($r)) {
        $post_id = $r[0]['id'];
        logger('mod_item: saved item ' . $post_id);
        if ($parent) {
            // This item is the last leaf and gets the comment box, clear any ancestors
            $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent` = %d ", dbesc(datetime_convert()), intval($parent));
            // Inherit ACL's from the parent item.
            $r = q("UPDATE `item` SET `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s', `private` = %d\n\t\t\t\tWHERE `id` = %d LIMIT 1", dbesc($parent_item['allow_cid']), dbesc($parent_item['allow_gid']), dbesc($parent_item['deny_cid']), dbesc($parent_item['deny_gid']), intval($parent_item['private']), intval($post_id));
            if ($contact_record != $author) {
                notification(array('type' => NOTIFY_COMMENT, 'notify_flags' => $user['notify-flags'], 'language' => $user['language'], 'to_name' => $user['username'], 'to_email' => $user['email'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . $user['nickname'] . '/' . $post_id, 'source_name' => $datarray['author-name'], 'source_link' => $datarray['author-link'], 'source_photo' => $datarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item'));
            }
            // We won't be able to sign Diaspora comments for authenticated visitors - we don't have their private key
            if ($self) {
                require_once 'include/bb2diaspora.php';
                $signed_body = html_entity_decode(bb2diaspora($datarray['body']));
                $myaddr = $a->user['nickname'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(), '://') + 3);
                if ($datarray['verb'] === ACTIVITY_LIKE) {
                    $signed_text = $datarray['guid'] . ';' . 'Post' . ';' . $parent_item['guid'] . ';' . 'true' . ';' . $myaddr;
                } else {
                    $signed_text = $datarray['guid'] . ';' . $parent_item['guid'] . ';' . $signed_body . ';' . $myaddr;
                }
                $authorsig = base64_encode(rsa_sign($signed_text, $a->user['prvkey'], 'sha256'));
                q("insert into sign (`iid`,`signed_text`,`signature`,`signer`) values (%d,'%s','%s','%s') ", intval($post_id), dbesc($signed_text), dbesc(base64_encode($authorsig)), dbesc($myaddr));
            }
        } else {
            $parent = $post_id;
            if ($contact_record != $author) {
                notification(array('type' => NOTIFY_WALL, 'notify_flags' => $user['notify-flags'], 'language' => $user['language'], 'to_name' => $user['username'], 'to_email' => $user['email'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . $user['nickname'] . '/' . $post_id, 'source_name' => $datarray['author-name'], 'source_link' => $datarray['author-link'], 'source_photo' => $datarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item'));
            }
        }
        // fallback so that parent always gets set to non-zero.
        if (!$parent) {
            $parent = $post_id;
        }
        $r = q("UPDATE `item` SET `parent` = %d, `parent-uri` = '%s', `plink` = '%s', `changed` = '%s', `last-child` = 1, `visible` = 1\n\t\t\tWHERE `id` = %d LIMIT 1", intval($parent), dbesc($parent == $post_id ? $uri : $parent_item['uri']), dbesc($a->get_baseurl() . '/display/' . $user['nickname'] . '/' . $post_id), dbesc(datetime_convert()), intval($post_id));
        // photo comments turn the corresponding item visible to the profile wall
        // This way we don't see every picture in your new photo album posted to your wall at once.
        // They will show up as people comment on them.
        if (!$parent_item['visible']) {
            $r = q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d LIMIT 1", intval($parent_item['id']));
        }
    } else {
        logger('mod_item: unable to retrieve post that was just stored.');
        notify(t('System error. Post not saved.'));
        goaway($a->get_baseurl() . "/" . $return_path);
        // NOTREACHED
    }
    // update the commented timestamp on the parent
    q("UPDATE `item` set `commented` = '%s', `changed` = '%s' WHERE `id` = %d LIMIT 1", dbesc(datetime_convert()), dbesc(datetime_convert()), intval($parent));
    $datarray['id'] = $post_id;
    $datarray['plink'] = $a->get_baseurl() . '/display/' . $user['nickname'] . '/' . $post_id;
    call_hooks('post_local_end', $datarray);
    if (strlen($emailcc) && $profile_uid == local_user()) {
        $erecips = explode(',', $emailcc);
        if (count($erecips)) {
            foreach ($erecips as $recip) {
                $addr = trim($recip);
                if (!strlen($addr)) {
                    continue;
                }
                $disclaimer = '<hr />' . sprintf(t('This message was sent to you by %s, a member of the Friendica social network.'), $a->user['username']) . '<br />';
                $disclaimer .= sprintf(t('You may visit them online at %s'), $a->get_baseurl() . '/profile/' . $a->user['nickname']) . EOL;
                $disclaimer .= t('Please contact the sender by replying to this post if you do not wish to receive these messages.') . EOL;
                $subject = email_header_encode('[Friendica]' . ' ' . sprintf(t('%s posted an update.'), $a->user['username']), 'UTF-8');
                $headers = 'From: ' . email_header_encode($a->user['username'], 'UTF-8') . ' <' . $a->user['email'] . '>' . "\n";
                $headers .= 'MIME-Version: 1.0' . "\n";
                $headers .= 'Content-Type: text/html; charset=UTF-8' . "\n";
                $headers .= 'Content-Transfer-Encoding: 8bit' . "\n\n";
                $link = '<a href="' . $a->get_baseurl() . '/profile/' . $a->user['nickname'] . '"><img src="' . $author['thumb'] . '" alt="' . $a->user['username'] . '" /></a><br /><br />';
                $html = prepare_body($datarray);
                $message = '<html><body>' . $link . $html . $disclaimer . '</body></html>';
                @mail($addr, $subject, $message, $headers);
            }
        }
    }
    // This is a real juggling act on shared hosting services which kill your processes
    // e.g. dreamhost. We used to start delivery to our native delivery agents in the background
    // and then run our plugin delivery from the foreground. We're now doing plugin delivery first,
    // because as soon as you start loading up a bunch of remote delivey processes, *this* page is
    // likely to get killed off. If you end up looking at an /item URL and a blank page,
    // it's very likely the delivery got killed before all your friends could be notified.
    // Currently the only realistic fixes are to use a reliable server - which precludes shared hosting,
    // or cut back on plugins which do remote deliveries.
    proc_run('php', "include/notifier.php", $notify_type, "{$post_id}");
    logger('post_complete');
    // figure out how to return, depending on from whence we came
    if ($api_source) {
        return;
    }
    if ($return_path) {
        goaway($a->get_baseurl() . "/" . $return_path);
    }
    $json = array('success' => 1);
    if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload'])) {
        $json['reload'] = $a->get_baseurl() . '/' . $_REQUEST['jsreload'];
    }
    logger('post_json: ' . print_r($json, true), LOGGER_DEBUG);
    echo json_encode($json);
    killme();
    // NOTREACHED
}
示例#14
0
function invite_post(&$a)
{
    if (!local_user()) {
        notice(t('Permission denied.') . EOL);
        return;
    }
    check_form_security_token_redirectOnErr('/', 'send_invite');
    $max_invites = intval(get_config('system', 'max_invites'));
    if (!$max_invites) {
        $max_invites = 50;
    }
    $current_invites = intval(get_pconfig(local_user(), 'system', 'sent_invites'));
    if ($current_invites > $max_invites) {
        notice(t('Total invitation limit exceeded.') . EOL);
        return;
    }
    $recips = x($_POST, 'recipients') ? explode("\n", $_POST['recipients']) : array();
    $message = x($_POST, 'message') ? notags(trim($_POST['message'])) : '';
    $total = 0;
    if (get_config('system', 'invitation_only')) {
        $invonly = true;
        $x = get_pconfig(local_user(), 'system', 'invites_remaining');
        if (!$x && !is_site_admin()) {
            return;
        }
    }
    foreach ($recips as $recip) {
        $recip = trim($recip);
        if (!valid_email($recip)) {
            notice(sprintf(t('%s : Not a valid email address.'), $recip) . EOL);
            continue;
        }
        if ($invonly && ($x || is_site_admin())) {
            $code = autoname(8) . srand(1000, 9999);
            $nmessage = str_replace('$invite_code', $code, $message);
            $r = q("INSERT INTO `register` (`hash`,`created`) VALUES ('%s', '%s') ", dbesc($code), dbesc(datetime_convert()));
            if (!is_site_admin()) {
                $x--;
                if ($x >= 0) {
                    set_pconfig(local_user(), 'system', 'invites_remaining', $x);
                } else {
                    return;
                }
            }
        } else {
            $nmessage = $message;
        }
        $res = mail($recip, email_header_encode(t('Please join us on Friendica'), 'UTF-8'), $nmessage, "From: " . $a->user['email'] . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit');
        if ($res) {
            $total++;
            $current_invites++;
            set_pconfig(local_user(), 'system', 'sent_invites', $current_invites);
            if ($current_invites > $max_invites) {
                notice(t('Invitation limit exceeded. Please contact your site administrator.') . EOL);
                return;
            }
        } else {
            notice(sprintf(t('%s : Message delivery failed.'), $recip) . EOL);
        }
    }
    notice(sprintf(tt("%d message sent.", "%d messages sent.", $total), $total) . EOL);
    return;
}
示例#15
0
文件: boot.php 项目: Mauru/red
function check_config(&$a)
{
    $build = get_config('system', 'db_version');
    if (!intval($build)) {
        $build = set_config('system', 'db_version', DB_UPDATE_VERSION);
    }
    $saved = get_config('system', 'urlverify');
    if (!$saved) {
        set_config('system', 'urlverify', bin2hex(z_root()));
    }
    if ($saved && $saved != bin2hex(z_root())) {
        // our URL changed. Do something.
        $oldurl = hex2bin($saved);
        logger('Baseurl changed!');
        $oldhost = substr($oldurl, strpos($oldurl, '//') + 2);
        $host = substr(z_root(), strpos(z_root(), '//') + 2);
        $is_ip_addr = preg_match("/^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\$/", $host) ? true : false;
        $was_ip_addr = preg_match("/^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\$/", $oldhost) ? true : false;
        // only change the url to an ip address if it was already an ip and not a dns name
        if (!$is_ip_addr || $is_ip_addr && $was_ip_addr) {
            fix_system_urls($oldurl, z_root());
            set_config('system', 'urlverify', bin2hex(z_root()));
        } else {
            logger('Attempt to change baseurl from a DNS name to an IP address was refused.');
        }
    }
    // This will actually set the url to the one stored in .htconfig, and ignore what
    // we're passing - unless we are installing and it has never been set.
    $a->set_baseurl($a->get_baseurl());
    // Make sure each site has a system channel.  This is now created on install
    // so we just need to keep this around a couple of weeks until the hubs that
    // already exist have one
    $syschan_exists = get_sys_channel();
    if (!$syschan_exists) {
        create_sys_channel();
    }
    if ($build != DB_UPDATE_VERSION) {
        $stored = intval($build);
        if (!$stored) {
            logger('Critical: check_config unable to determine database schema version');
            return;
        }
        $current = intval(DB_UPDATE_VERSION);
        if ($stored < $current && file_exists('install/update.php')) {
            load_config('database');
            // We're reporting a different version than what is currently installed.
            // Run any existing update scripts to bring the database up to current.
            require_once 'install/update.php';
            // make sure that boot.php and update.php are the same release, we might be
            // updating right this very second and the correct version of the update.php
            // file may not be here yet. This can happen on a very busy site.
            if (DB_UPDATE_VERSION == UPDATE_VERSION) {
                for ($x = $stored; $x < $current; $x++) {
                    if (function_exists('update_r' . $x)) {
                        // There could be a lot of processes running or about to run.
                        // We want exactly one process to run the update command.
                        // So store the fact that we're taking responsibility
                        // after first checking to see if somebody else already has.
                        // If the update fails or times-out completely you may need to
                        // delete the config entry to try again.
                        if (get_config('database', 'update_r' . $x)) {
                            break;
                        }
                        set_config('database', 'update_r' . $x, '1');
                        // call the specific update
                        $func = 'update_r' . $x;
                        $retval = $func();
                        if ($retval) {
                            // Prevent sending hundreds of thousands of emails by creating
                            // a lockfile.
                            $lockfile = 'store/[data]/mailsent';
                            if (file_exists($lockfile) && filemtime($lockfile) > time() - 86400) {
                                return;
                            }
                            @unlink($lockfile);
                            //send the administrator an e-mail
                            file_put_contents($lockfile, $x);
                            $email_tpl = get_intltext_template("update_fail_eml.tpl");
                            $email_msg = replace_macros($email_tpl, array('$sitename' => $a->config['system']['sitename'], '$siteurl' => $a->get_baseurl(), '$update' => $x, '$error' => sprintf(t('Update %s failed. See error logs.'), $x)));
                            $subject = email_header_encode(sprintf(t('Update Error at %s'), $a->get_baseurl()));
                            mail($a->config['system']['admin_email'], $subject, $email_msg, 'From: Administrator' . '@' . $_SERVER['SERVER_NAME'] . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit');
                            //try the logger
                            logger('CRITICAL: Update Failed: ' . $x);
                        } else {
                            set_config('database', 'update_r' . $x, 'success');
                        }
                    }
                }
                set_config('system', 'db_version', DB_UPDATE_VERSION);
            }
        }
    }
    /**
     *
     * Synchronise plugins:
     *
     * $a->config['system']['addon'] contains a comma-separated list of names
     * of plugins/addons which are used on this system.
     * Go through the database list of already installed addons, and if we have
     * an entry, but it isn't in the config list, call the unload procedure
     * and mark it uninstalled in the database (for now we'll remove it).
     * Then go through the config list and if we have a plugin that isn't installed,
     * call the install procedure and add it to the database.
     *
     */
    $r = q("SELECT * FROM `addon` WHERE `installed` = 1");
    if ($r) {
        $installed = $r;
    } else {
        $installed = array();
    }
    $plugins = get_config('system', 'addon');
    $plugins_arr = array();
    if ($plugins) {
        $plugins_arr = explode(',', str_replace(' ', '', $plugins));
    }
    $a->plugins = $plugins_arr;
    $installed_arr = array();
    if (count($installed)) {
        foreach ($installed as $i) {
            if (!in_array($i['name'], $plugins_arr)) {
                unload_plugin($i['name']);
            } else {
                $installed_arr[] = $i['name'];
            }
        }
    }
    if (count($plugins_arr)) {
        foreach ($plugins_arr as $p) {
            if (!in_array($p, $installed_arr)) {
                load_plugin($p);
            }
        }
    }
    load_hooks();
    return;
}
示例#16
0
function delivery_run(&$argv, &$argc)
{
    global $a, $db;
    if (is_null($a)) {
        $a = new App();
    }
    if (is_null($db)) {
        @(include ".htconfig.php");
        require_once "include/dba.php";
        $db = new dba($db_host, $db_user, $db_pass, $db_data);
        unset($db_host, $db_user, $db_pass, $db_data);
    }
    require_once "include/session.php";
    require_once "include/datetime.php";
    require_once 'include/items.php';
    require_once 'include/bbcode.php';
    require_once 'include/diaspora.php';
    require_once 'include/email.php';
    load_config('config');
    load_config('system');
    load_hooks();
    if ($argc < 3) {
        return;
    }
    $a->set_baseurl(get_config('system', 'url'));
    logger('delivery: invoked: ' . print_r($argv, true), LOGGER_DEBUG);
    $cmd = $argv[1];
    $item_id = intval($argv[2]);
    for ($x = 3; $x < $argc; $x++) {
        $contact_id = intval($argv[$x]);
        // Some other process may have delivered this item already.
        $r = q("select * from deliverq where cmd = '%s' and item = %d and contact = %d limit 1", dbesc($cmd), dbesc($item_id), dbesc($contact_id));
        if (!count($r)) {
            continue;
        }
        $maxsysload = intval(get_config('system', 'maxloadavg'));
        if ($maxsysload < 1) {
            $maxsysload = 50;
        }
        if (function_exists('sys_getloadavg')) {
            $load = sys_getloadavg();
            if (intval($load[0]) > $maxsysload) {
                logger('system: load ' . $load . ' too high. Delivery deferred to next queue run.');
                return;
            }
        }
        // It's ours to deliver. Remove it from the queue.
        q("delete from deliverq where cmd = '%s' and item = %d and contact = %d", dbesc($cmd), dbesc($item_id), dbesc($contact_id));
        if (!$item_id || !$contact_id) {
            continue;
        }
        $expire = false;
        $top_level = false;
        $recipients = array();
        $url_recipients = array();
        $normal_mode = true;
        $recipients[] = $contact_id;
        if ($cmd === 'expire') {
            $normal_mode = false;
            $expire = true;
            $items = q("SELECT * FROM `item` WHERE `uid` = %d AND `wall` = 1 \n\t\t\t\tAND `deleted` = 1 AND `changed` > UTC_TIMESTAMP() - INTERVAL 30 MINUTE", intval($item_id));
            $uid = $item_id;
            $item_id = 0;
            if (!count($items)) {
                continue;
            }
        } else {
            // find ancestors
            $r = q("SELECT * FROM `item` WHERE `id` = %d and visible = 1 and moderated = 0 LIMIT 1", intval($item_id));
            if (!count($r) || !intval($r[0]['parent'])) {
                continue;
            }
            $target_item = $r[0];
            $parent_id = intval($r[0]['parent']);
            $uid = $r[0]['uid'];
            $updated = $r[0]['edited'];
            // POSSIBLE CLEANUP --> The following seems superfluous. We've already checked for "if (! intval($r[0]['parent']))" a few lines up
            if (!$parent_id) {
                continue;
            }
            $items = q("SELECT `item`.*, `sign`.`signed_text`,`sign`.`signature`,`sign`.`signer` \n\t\t\t\tFROM `item` LEFT JOIN `sign` ON `sign`.`iid` = `item`.`id` WHERE `parent` = %d and visible = 1 and moderated = 0 ORDER BY `id` ASC", intval($parent_id));
            if (!count($items)) {
                continue;
            }
            $icontacts = null;
            $contacts_arr = array();
            foreach ($items as $item) {
                if (!in_array($item['contact-id'], $contacts_arr)) {
                    $contacts_arr[] = intval($item['contact-id']);
                }
            }
            if (count($contacts_arr)) {
                $str_contacts = implode(',', $contacts_arr);
                $icontacts = q("SELECT * FROM `contact` \n\t\t\t\t\tWHERE `id` IN ( {$str_contacts} ) ");
            }
            if (!($icontacts && count($icontacts))) {
                continue;
            }
            // avoid race condition with deleting entries
            if ($items[0]['deleted']) {
                foreach ($items as $item) {
                    $item['deleted'] = 1;
                }
            }
            if (count($items) == 1 && $items[0]['uri'] === $items[0]['parent-uri']) {
                logger('delivery: top level post');
                $top_level = true;
            }
        }
        $r = q("SELECT `contact`.*, `user`.`pubkey` AS `upubkey`, `user`.`prvkey` AS `uprvkey`, \n\t\t\t`user`.`timezone`, `user`.`nickname`, `user`.`sprvkey`, `user`.`spubkey`, \n\t\t\t`user`.`page-flags`, `user`.`prvnets`\n\t\t\tFROM `contact` INNER JOIN `user` ON `user`.`uid` = `contact`.`uid` \n\t\t\tWHERE `contact`.`uid` = %d AND `contact`.`self` = 1 LIMIT 1", intval($uid));
        if (!count($r)) {
            continue;
        }
        $owner = $r[0];
        $walltowall = $top_level && $owner['id'] != $items[0]['contact-id'] ? true : false;
        $public_message = true;
        // fill this in with a single salmon slap if applicable
        $slap = '';
        require_once 'include/group.php';
        $parent = $items[0];
        // This is IMPORTANT!!!!
        // We will only send a "notify owner to relay" or followup message if the referenced post
        // originated on our system by virtue of having our hostname somewhere
        // in the URI, AND it was a comment (not top_level) AND the parent originated elsewhere.
        // if $parent['wall'] == 1 we will already have the parent message in our array
        // and we will relay the whole lot.
        // expire sends an entire group of expire messages and cannot be forwarded.
        // However the conversation owner will be a part of the conversation and will
        // be notified during this run.
        // Other DFRN conversation members will be alerted during polled updates.
        // Diaspora members currently are not notified of expirations, and other networks have
        // either limited or no ability to process deletions. We should at least fix Diaspora
        // by stringing togther an array of retractions and sending them onward.
        $localhost = $a->get_hostname();
        if (strpos($localhost, ':')) {
            $localhost = substr($localhost, 0, strpos($localhost, ':'));
        }
        /**
         *
         * Be VERY CAREFUL if you make any changes to the following line. Seemingly innocuous changes
         * have been known to cause runaway conditions which affected several servers, along with
         * permissions issues.
         *
         */
        if (!$top_level && $parent['wall'] == 0 && !$expire && stristr($target_item['uri'], $localhost)) {
            logger('relay denied for delivery agent.');
            /* no relay allowed for direct contact delivery */
            continue;
        }
        if (strlen($parent['allow_cid']) || strlen($parent['allow_gid']) || strlen($parent['deny_cid']) || strlen($parent['deny_gid'])) {
            $public_message = false;
            // private recipients, not public
        }
        $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `blocked` = 0 AND `pending` = 0", intval($contact_id));
        if (count($r)) {
            $contact = $r[0];
        }
        $hubxml = feed_hublinks();
        logger('notifier: slaps: ' . print_r($slaps, true), LOGGER_DATA);
        require_once 'include/salmon.php';
        if ($contact['self']) {
            continue;
        }
        $deliver_status = 0;
        switch ($contact['network']) {
            case NETWORK_DFRN:
                logger('notifier: dfrndelivery: ' . $contact['name']);
                $feed_template = get_markup_template('atom_feed.tpl');
                $mail_template = get_markup_template('atom_mail.tpl');
                $atom = '';
                $birthday = feed_birthday($owner['uid'], $owner['timezone']);
                if (strlen($birthday)) {
                    $birthday = '<dfrn:birthday>' . xmlify($birthday) . '</dfrn:birthday>';
                }
                $atom .= replace_macros($feed_template, array('$version' => xmlify(FRIENDICA_VERSION), '$feed_id' => xmlify($a->get_baseurl() . '/profile/' . $owner['nickname']), '$feed_title' => xmlify($owner['name']), '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', $updated . '+00:00', ATOM_TIME)), '$hub' => $hubxml, '$salmon' => '', '$name' => xmlify($owner['name']), '$profile_page' => xmlify($owner['url']), '$photo' => xmlify($owner['photo']), '$thumb' => xmlify($owner['thumb']), '$picdate' => xmlify(datetime_convert('UTC', 'UTC', $owner['avatar-date'] . '+00:00', ATOM_TIME)), '$uridate' => xmlify(datetime_convert('UTC', 'UTC', $owner['uri-date'] . '+00:00', ATOM_TIME)), '$namdate' => xmlify(datetime_convert('UTC', 'UTC', $owner['name-date'] . '+00:00', ATOM_TIME)), '$birthday' => $birthday, '$community' => $owner['page-flags'] == PAGE_COMMUNITY ? '<dfrn:community>1</dfrn:community>' : ''));
                foreach ($items as $item) {
                    if (!$item['parent']) {
                        continue;
                    }
                    // private emails may be in included in public conversations. Filter them.
                    if ($public_message && $item['private'] == 1) {
                        continue;
                    }
                    $item_contact = get_item_contact($item, $icontacts);
                    if (!$item_contact) {
                        continue;
                    }
                    if ($normal_mode) {
                        if ($item_id == $item['id'] || $item['id'] == $item['parent']) {
                            $atom .= atom_entry($item, 'text', null, $owner, true, $top_level ? $contact['id'] : 0);
                        }
                    } else {
                        $atom .= atom_entry($item, 'text', null, $owner, true);
                    }
                }
                $atom .= '</feed>' . "\r\n";
                logger('notifier: ' . $atom, LOGGER_DATA);
                $basepath = implode('/', array_slice(explode('/', $contact['url']), 0, 3));
                // perform local delivery if we are on the same site
                if (link_compare($basepath, $a->get_baseurl())) {
                    $nickname = basename($contact['url']);
                    if ($contact['issued-id']) {
                        $sql_extra = sprintf(" AND `dfrn-id` = '%s' ", dbesc($contact['issued-id']));
                    } else {
                        $sql_extra = sprintf(" AND `issued-id` = '%s' ", dbesc($contact['dfrn-id']));
                    }
                    $x = q("SELECT\t`contact`.*, `contact`.`uid` AS `importer_uid`,\n\t\t\t\t\t\t`contact`.`pubkey` AS `cpubkey`,\n\t\t\t\t\t\t`contact`.`prvkey` AS `cprvkey`,\n\t\t\t\t\t\t`contact`.`thumb` AS `thumb`,\n\t\t\t\t\t\t`contact`.`url` as `url`,\n\t\t\t\t\t\t`contact`.`name` as `senderName`,\n\t\t\t\t\t\t`user`.*\n\t\t\t\t\t\tFROM `contact`\n\t\t\t\t\t\tINNER JOIN `user` ON `contact`.`uid` = `user`.`uid`\n\t\t\t\t\t\tWHERE `contact`.`blocked` = 0 AND `contact`.`pending` = 0\n\t\t\t\t\t\tAND `contact`.`network` = '%s' AND `user`.`nickname` = '%s'\n\t\t\t\t\t\t{$sql_extra}\n\t\t\t\t\t\tAND `user`.`account_expired` = 0 AND `user`.`account_removed` = 0 LIMIT 1", dbesc(NETWORK_DFRN), dbesc($nickname));
                    if ($x && count($x)) {
                        $write_flag = $x[0]['rel'] && $x[0]['rel'] != CONTACT_IS_SHARING ? true : false;
                        if (($owner['page-flags'] == PAGE_COMMUNITY || $write_flag) && !$x[0]['writable']) {
                            q("update contact set writable = 1 where id = %d", intval($x[0]['id']));
                            $x[0]['writable'] = 1;
                        }
                        $ssl_policy = get_config('system', 'ssl_policy');
                        fix_contact_ssl_policy($x[0], $ssl_policy);
                        // If we are setup as a soapbox we aren't accepting input from this person
                        if ($x[0]['page-flags'] == PAGE_SOAPBOX) {
                            break;
                        }
                        require_once 'library/simplepie/simplepie.inc';
                        logger('mod-delivery: local delivery');
                        local_delivery($x[0], $atom);
                        break;
                    }
                }
                if (!was_recently_delayed($contact['id'])) {
                    $deliver_status = dfrn_deliver($owner, $contact, $atom);
                } else {
                    $deliver_status = -1;
                }
                logger('notifier: dfrn_delivery returns ' . $deliver_status);
                if ($deliver_status == -1) {
                    logger('notifier: delivery failed: queuing message');
                    add_to_queue($contact['id'], NETWORK_DFRN, $atom);
                }
                break;
            case NETWORK_OSTATUS:
                // Do not send to otatus if we are not configured to send to public networks
                if ($owner['prvnets']) {
                    break;
                }
                if (get_config('system', 'ostatus_disabled') || get_config('system', 'dfrn_only')) {
                    break;
                }
                // only send salmon if public - e.g. if it's ok to notify
                // a public hub, it's ok to send a salmon
                if ($public_message && !$expire) {
                    $slaps = array();
                    foreach ($items as $item) {
                        if (!$item['parent']) {
                            continue;
                        }
                        // private emails may be in included in public conversations. Filter them.
                        if ($public_message && $item['private'] == 1) {
                            continue;
                        }
                        $item_contact = get_item_contact($item, $icontacts);
                        if (!$item_contact) {
                            continue;
                        }
                        if ($top_level && $public_message && $item['author-link'] === $item['owner-link'] && !$expire) {
                            $slaps[] = atom_entry($item, 'html', null, $owner, true);
                        }
                    }
                    logger('notifier: slapdelivery: ' . $contact['name']);
                    foreach ($slaps as $slappy) {
                        if ($contact['notify']) {
                            if (!was_recently_delayed($contact['id'])) {
                                $deliver_status = slapper($owner, $contact['notify'], $slappy);
                            } else {
                                $deliver_status = -1;
                            }
                            if ($deliver_status == -1) {
                                // queue message for redelivery
                                add_to_queue($contact['id'], NETWORK_OSTATUS, $slappy);
                            }
                        }
                    }
                }
                break;
            case NETWORK_MAIL:
            case NETWORK_MAIL2:
                if (get_config('system', 'dfrn_only')) {
                    break;
                }
                // WARNING: does not currently convert to RFC2047 header encodings, etc.
                $addr = $contact['addr'];
                if (!strlen($addr)) {
                    break;
                }
                if ($cmd === 'wall-new' || $cmd === 'comment-new') {
                    $it = null;
                    if ($cmd === 'wall-new') {
                        $it = $items[0];
                    } else {
                        $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($argv[2]), intval($uid));
                        if (count($r)) {
                            $it = $r[0];
                        }
                    }
                    if (!$it) {
                        break;
                    }
                    $local_user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($uid));
                    if (!count($local_user)) {
                        break;
                    }
                    $reply_to = '';
                    $r1 = q("SELECT * FROM `mailacct` WHERE `uid` = %d LIMIT 1", intval($uid));
                    if ($r1 && $r1[0]['reply_to']) {
                        $reply_to = $r1[0]['reply_to'];
                    }
                    $subject = $it['title'] ? email_header_encode($it['title'], 'UTF-8') : t("(no subject)");
                    // only expose our real email address to true friends
                    if ($contact['rel'] == CONTACT_IS_FRIEND && !$contact['blocked']) {
                        if ($reply_to) {
                            $headers = 'From: ' . email_header_encode($local_user[0]['username'], 'UTF-8') . ' <' . $reply_to . '>' . "\n";
                            $headers .= 'Sender: ' . $local_user[0]['email'] . "\n";
                        } else {
                            $headers = 'From: ' . email_header_encode($local_user[0]['username'], 'UTF-8') . ' <' . $local_user[0]['email'] . '>' . "\n";
                        }
                    } else {
                        $headers = 'From: ' . email_header_encode($local_user[0]['username'], 'UTF-8') . ' <' . t('noreply') . '@' . $a->get_hostname() . '>' . "\n";
                    }
                    //if($reply_to)
                    //	$headers .= 'Reply-to: ' . $reply_to . "\n";
                    $headers .= 'Message-Id: <' . iri2msgid($it['uri']) . '>' . "\n";
                    //logger("Mail: uri: ".$it['uri']." parent-uri ".$it['parent-uri'], LOGGER_DEBUG);
                    //logger("Mail: Data: ".print_r($it, true), LOGGER_DEBUG);
                    //logger("Mail: Data: ".print_r($it, true), LOGGER_DATA);
                    if ($it['uri'] !== $it['parent-uri']) {
                        $headers .= "References: <" . iri2msgid($it["parent-uri"]) . ">";
                        // If Threading is enabled, write down the correct parent
                        if ($it["thr-parent"] != "" and $it["thr-parent"] != $it["parent-uri"]) {
                            $headers .= " <" . iri2msgid($it["thr-parent"]) . ">";
                        }
                        $headers .= "\n";
                        if (!$it['title']) {
                            $r = q("SELECT `title` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($it['parent-uri']), intval($uid));
                            if (count($r) and $r[0]['title'] != '') {
                                $subject = $r[0]['title'];
                            } else {
                                $r = q("SELECT `title` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($it['parent-uri']), intval($uid));
                                if (count($r) and $r[0]['title'] != '') {
                                    $subject = $r[0]['title'];
                                }
                            }
                        }
                        if (strncasecmp($subject, 'RE:', 3)) {
                            $subject = 'Re: ' . $subject;
                        }
                    }
                    email_send($addr, $subject, $headers, $it);
                }
                break;
            case NETWORK_DIASPORA:
                if ($public_message) {
                    $loc = 'public batch ' . $contact['batch'];
                } else {
                    $loc = $contact['name'];
                }
                logger('delivery: diaspora batch deliver: ' . $loc);
                if (get_config('system', 'dfrn_only') || !get_config('system', 'diaspora_enabled') || !$normal_mode) {
                    break;
                }
                if (!$contact['pubkey'] && !$public_message) {
                    break;
                }
                if ($target_item['verb'] === ACTIVITY_DISLIKE) {
                    // unsupported
                    break;
                } elseif ($target_item['deleted'] && $target_item['uri'] === $target_item['parent-uri']) {
                    // top-level retraction
                    logger('delivery: diaspora retract: ' . $loc);
                    diaspora_send_retraction($target_item, $owner, $contact, $public_message);
                    break;
                } elseif ($target_item['uri'] !== $target_item['parent-uri']) {
                    // we are the relay - send comments, likes and relayable_retractions to our conversants
                    logger('delivery: diaspora relay: ' . $loc);
                    diaspora_send_relay($target_item, $owner, $contact, $public_message);
                    break;
                } elseif ($top_level && !$walltowall) {
                    // currently no workable solution for sending walltowall
                    logger('delivery: diaspora status: ' . $loc);
                    diaspora_send_status($target_item, $owner, $contact, $public_message);
                    break;
                }
                logger('delivery: diaspora unknown mode: ' . $contact['name']);
                break;
            case NETWORK_FEED:
            case NETWORK_FACEBOOK:
                if (get_config('system', 'dfrn_only')) {
                    break;
                }
            case NETWORK_PUMPIO:
                if (get_config('system', 'dfrn_only')) {
                    break;
                }
            default:
                break;
        }
    }
    return;
}
示例#17
0
function new_follower($importer, $contact, $datarray, $item, $sharing = false)
{
    $url = notags(trim($datarray['author-link']));
    $name = notags(trim($datarray['author-name']));
    $photo = notags(trim($datarray['author-avatar']));
    $rawtag = $item->get_item_tags(NAMESPACE_ACTIVITY, 'actor');
    if ($rawtag && $rawtag[0]['child'][NAMESPACE_POCO]['preferredUsername'][0]['data']) {
        $nick = $rawtag[0]['child'][NAMESPACE_POCO]['preferredUsername'][0]['data'];
    }
    if (is_array($contact)) {
        if ($contact['network'] == NETWORK_OSTATUS && $contact['rel'] == CONTACT_IS_SHARING || $sharing && $contact['rel'] == CONTACT_IS_FOLLOWER) {
            $r = q("UPDATE `contact` SET `rel` = %d, `writable` = 1 WHERE `id` = %d AND `uid` = %d LIMIT 1", intval(CONTACT_IS_FRIEND), intval($contact['id']), intval($importer['uid']));
        }
        // send email notification to owner?
    } else {
        // create contact record
        $r = q("INSERT INTO `contact` ( `uid`, `created`, `url`, `nurl`, `name`, `nick`, `photo`, `network`, `rel`, \n\t\t\t`blocked`, `readonly`, `pending`, `writable` )\n\t\t\tVALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, 0, 0, 1, 1 ) ", intval($importer['uid']), dbesc(datetime_convert()), dbesc($url), dbesc(normalise_link($url)), dbesc($name), dbesc($nick), dbesc($photo), dbesc($sharing ? NETWORK_ZOT : NETWORK_OSTATUS), intval($sharing ? CONTACT_IS_SHARING : CONTACT_IS_FOLLOWER));
        $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `url` = '%s' AND `pending` = 1 LIMIT 1", intval($importer['uid']), dbesc($url));
        if (count($r)) {
            $contact_record = $r[0];
        }
        // create notification
        $hash = random_string();
        if (is_array($contact_record)) {
            $ret = q("INSERT INTO `intro` ( `uid`, `contact-id`, `blocked`, `knowyou`, `hash`, `datetime`)\n\t\t\t\tVALUES ( %d, %d, 0, 0, '%s', '%s' )", intval($importer['uid']), intval($contact_record['id']), dbesc($hash), dbesc(datetime_convert()));
        }
        $r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($importer['uid']));
        $a = get_app();
        if (count($r)) {
            if (intval($r[0]['def_gid'])) {
                require_once 'include/group.php';
                group_add_member($r[0]['uid'], '', $contact_record['id'], $r[0]['def_gid']);
            }
            if ($r[0]['notify-flags'] & NOTIFY_INTRO && $r[0]['page-flags'] == PAGE_NORMAL) {
                $email_tpl = get_intltext_template('follow_notify_eml.tpl');
                $email = replace_macros($email_tpl, array('$requestor' => strlen($name) ? $name : t('[Name Withheld]'), '$url' => $url, '$myname' => $r[0]['username'], '$siteurl' => $a->get_baseurl(), '$sitename' => $a->config['sitename']));
                $res = mail($r[0]['email'], email_header_encode(($sharing ? t('A new person is sharing with you at ') : t("You have a new follower at ")) . $a->config['sitename'], 'UTF-8'), $email, 'From: ' . 'Administrator' . '@' . $_SERVER['SERVER_NAME'] . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit');
            }
        }
    }
}
示例#18
0
/**
 * @brief Send warnings every 3-5 days if cron is not running.
 */
function check_cron_broken()
{
    $t = get_config('system', 'lastpollcheck');
    if (!$t) {
        // never checked before. Start the timer.
        set_config('system', 'lastpollcheck', datetime_convert());
        return;
    }
    if ($t > datetime_convert('UTC', 'UTC', 'now - 3 days')) {
        // Wait for 3 days before we do anything so as not to swamp the admin with messages
        return;
    }
    $d = get_config('system', 'lastpoll');
    if ($d && $d > datetime_convert('UTC', 'UTC', 'now - 3 days')) {
        // Scheduled tasks have run successfully in the last 3 days.
        set_config('system', 'lastpollcheck', datetime_convert());
        return;
    }
    $a = get_app();
    $email_tpl = get_intltext_template("cron_bad_eml.tpl");
    $email_msg = replace_macros($email_tpl, array('$sitename' => $a->config['system']['sitename'], '$siteurl' => $a->get_baseurl(), '$error' => t('Cron/Scheduled tasks not running.'), '$lastdate' => $d ? $d : t('never')));
    $subject = email_header_encode(sprintf(t('[red] Cron tasks not running on %s'), $a->get_hostname()));
    mail($a->config['system']['admin_email'], $subject, $email_msg, 'From: Administrator' . '@' . $a->get_hostname() . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit');
    set_config('system', 'lastpollcheck', datetime_convert());
    return;
}
示例#19
0
function dfrn_confirm_post(&$a, $handsfree = null)
{
    if (is_array($handsfree)) {
        /**
         * We were called directly from dfrn_request due to automatic friend acceptance.
         * Any $_POST parameters we may require are supplied in the $handsfree array.
         *
         */
        $node = $handsfree['node'];
        $a->interactive = false;
        // notice() becomes a no-op since nobody is there to see it
    } else {
        if ($a->argc > 1) {
            $node = $a->argv[1];
        }
    }
    /**
     *
     * Main entry point. Scenario 1. Our user received a friend request notification (perhaps 
     * from another site) and clicked 'Approve'. 
     * $POST['source_url'] is not set. If it is, it indicates Scenario 2.
     *
     * We may also have been called directly from dfrn_request ($handsfree != null) due to 
     * this being a page type which supports automatic friend acceptance. That is also Scenario 1
     * since we are operating on behalf of our registered user to approve a friendship.
     *
     */
    if (!x($_POST, 'source_url')) {
        $uid = is_array($handsfree) ? $handsfree['uid'] : local_user();
        if (!$uid) {
            notice(t('Permission denied.') . EOL);
            return;
        }
        $user = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($uid));
        if (!$user) {
            notice(t('Profile not found.') . EOL);
            return;
        }
        // These data elements may come from either the friend request notification form or $handsfree array.
        if (is_array($handsfree)) {
            logger('dfrn_confirm: Confirm in handsfree mode');
            $dfrn_id = $handsfree['dfrn_id'];
            $intro_id = $handsfree['intro_id'];
            $duplex = $handsfree['duplex'];
            $hidden = array_key_exists('hidden', $handsfree) ? intval($handsfree['hidden']) : 0;
            $activity = array_key_exists('activity', $handsfree) ? intval($handsfree['activity']) : 0;
        } else {
            $dfrn_id = x($_POST, 'dfrn_id') ? notags(trim($_POST['dfrn_id'])) : "";
            $intro_id = x($_POST, 'intro_id') ? intval($_POST['intro_id']) : 0;
            $duplex = x($_POST, 'duplex') ? intval($_POST['duplex']) : 0;
            $cid = x($_POST, 'contact_id') ? intval($_POST['contact_id']) : 0;
            $hidden = x($_POST, 'hidden') ? intval($_POST['hidden']) : 0;
            $activity = x($_POST, 'activity') ? intval($_POST['activity']) : 0;
        }
        /**
         *
         * Ensure that dfrn_id has precedence when we go to find the contact record.
         * We only want to search based on contact id if there is no dfrn_id, 
         * e.g. for OStatus network followers.
         *
         */
        if (strlen($dfrn_id)) {
            $cid = 0;
        }
        logger('dfrn_confirm: Confirming request for dfrn_id (issued) ' . $dfrn_id);
        if ($cid) {
            logger('dfrn_confirm: Confirming follower with contact_id: ' . $cid);
        }
        /**
         *
         * The other person will have been issued an ID when they first requested friendship.
         * Locate their record. At this time, their record will have both pending and blocked set to 1. 
         * There won't be any dfrn_id if this is a network follower, so use the contact_id instead.
         *
         */
        $r = q("SELECT * FROM `contact` WHERE ( ( `issued-id` != '' AND `issued-id` = '%s' ) OR ( `id` = %d AND `id` != 0 ) ) AND `uid` = %d AND `duplex` = 0 LIMIT 1", dbesc($dfrn_id), intval($cid), intval($uid));
        if (!count($r)) {
            logger('dfrn_confirm: Contact not found in DB.');
            notice(t('Contact not found.') . EOL);
            notice(t('This may occasionally happen if contact was requested by both persons and it has already been approved.') . EOL);
            return;
        }
        $contact = $r[0];
        $contact_id = $contact['id'];
        $relation = $contact['rel'];
        $site_pubkey = $contact['site-pubkey'];
        $dfrn_confirm = $contact['confirm'];
        $aes_allow = $contact['aes_allow'];
        $network = strlen($contact['issued-id']) ? NETWORK_DFRN : NETWORK_OSTATUS;
        if ($contact['network']) {
            $network = $contact['network'];
        }
        if ($network === NETWORK_DFRN) {
            /**
             *
             * Generate a key pair for all further communications with this person.
             * We have a keypair for every contact, and a site key for unknown people.
             * This provides a means to carry on relationships with other people if 
             * any single key is compromised. It is a robust key. We're much more 
             * worried about key leakage than anybody cracking it.  
             *
             */
            require_once 'include/crypto.php';
            $res = new_keypair(4096);
            $private_key = $res['prvkey'];
            $public_key = $res['pubkey'];
            // Save the private key. Send them the public key.
            $r = q("UPDATE `contact` SET `prvkey` = '%s' WHERE `id` = %d AND `uid` = %d LIMIT 1", dbesc($private_key), intval($contact_id), intval($uid));
            $params = array();
            /**
             *
             * Per the DFRN protocol, we will verify both ends by encrypting the dfrn_id with our 
             * site private key (person on the other end can decrypt it with our site public key).
             * Then encrypt our profile URL with the other person's site public key. They can decrypt
             * it with their site private key. If the decryption on the other end fails for either
             * item, it indicates tampering or key failure on at least one site and we will not be 
             * able to provide a secure communication pathway.
             *
             * If other site is willing to accept full encryption, (aes_allow is 1 AND we have php5.3 
             * or later) then we encrypt the personal public key we send them using AES-256-CBC and a 
             * random key which is encrypted with their site public key.  
             *
             */
            $src_aes_key = random_string();
            $result = '';
            openssl_private_encrypt($dfrn_id, $result, $user[0]['prvkey']);
            $params['dfrn_id'] = bin2hex($result);
            $params['public_key'] = $public_key;
            $my_url = $a->get_baseurl() . '/profile/' . $user[0]['nickname'];
            openssl_public_encrypt($my_url, $params['source_url'], $site_pubkey);
            $params['source_url'] = bin2hex($params['source_url']);
            if ($aes_allow && function_exists('openssl_encrypt')) {
                openssl_public_encrypt($src_aes_key, $params['aes_key'], $site_pubkey);
                $params['aes_key'] = bin2hex($params['aes_key']);
                $params['public_key'] = bin2hex(openssl_encrypt($public_key, 'AES-256-CBC', $src_aes_key));
            }
            $params['dfrn_version'] = DFRN_PROTOCOL_VERSION;
            if ($duplex == 1) {
                $params['duplex'] = 1;
            }
            if ($user[0]['page-flags'] == PAGE_COMMUNITY) {
                $params['page'] = 1;
            }
            if ($user[0]['page-flags'] == PAGE_PRVGROUP) {
                $params['page'] = 2;
            }
            logger('dfrn_confirm: Confirm: posting data to ' . $dfrn_confirm . ': ' . print_r($params, true), LOGGER_DATA);
            /**
             *
             * POST all this stuff to the other site.
             * Temporarily raise the network timeout to 120 seconds because the default 60
             * doesn't always give the other side quite enough time to decrypt everything.
             *
             */
            $a->config['system']['curl_timeout'] = 120;
            $res = post_url($dfrn_confirm, $params);
            logger('dfrn_confirm: Confirm: received data: ' . $res, LOGGER_DATA);
            // Now figure out what they responded. Try to be robust if the remote site is
            // having difficulty and throwing up errors of some kind.
            $leading_junk = substr($res, 0, strpos($res, '<?xml'));
            $res = substr($res, strpos($res, '<?xml'));
            if (!strlen($res)) {
                // No XML at all, this exchange is messed up really bad.
                // We shouldn't proceed, because the xml parser might choke,
                // and $status is going to be zero, which indicates success.
                // We can hardly call this a success.
                notice(t('Response from remote site was not understood.') . EOL);
                return;
            }
            if (strlen($leading_junk) && get_config('system', 'debugging')) {
                // This might be more common. Mixed error text and some XML.
                // If we're configured for debugging, show the text. Proceed in either case.
                notice(t('Unexpected response from remote site: ') . EOL . $leading_junk . EOL);
            }
            $xml = parse_xml_string($res);
            $status = (int) $xml->status;
            $message = unxmlify($xml->message);
            // human readable text of what may have gone wrong.
            switch ($status) {
                case 0:
                    info(t("Confirmation completed successfully.") . EOL);
                    if (strlen($message)) {
                        notice(t('Remote site reported: ') . $message . EOL);
                    }
                    break;
                case 1:
                    // birthday paradox - generate new dfrn-id and fall through.
                    $new_dfrn_id = random_string();
                    $r = q("UPDATE contact SET `issued-id` = '%s' WHERE `id` = %d AND `uid` = %d LIMIT 1", dbesc($new_dfrn_id), intval($contact_id), intval($uid));
                case 2:
                    notice(t("Temporary failure. Please wait and try again.") . EOL);
                    if (strlen($message)) {
                        notice(t('Remote site reported: ') . $message . EOL);
                    }
                    break;
                case 3:
                    notice(t("Introduction failed or was revoked.") . EOL);
                    if (strlen($message)) {
                        notice(t('Remote site reported: ') . $message . EOL);
                    }
                    break;
            }
            if ($status == 0 && $intro_id) {
                // Success. Delete the notification.
                $r = q("DELETE FROM `intro` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($intro_id), intval($uid));
            }
            if ($status != 0) {
                return;
            }
        }
        /*
         *
         * We have now established a relationship with the other site.
         * Let's make our own personal copy of their profile photo so we don't have
         * to always load it from their site.
         *
         * We will also update the contact record with the nature and scope of the relationship.
         *
         */
        require_once 'include/Photo.php';
        $photos = import_profile_photo($contact['photo'], $uid, $contact_id);
        logger('dfrn_confirm: confirm - imported photos');
        if ($network === NETWORK_DFRN) {
            $new_relation = CONTACT_IS_FOLLOWER;
            if ($relation == CONTACT_IS_SHARING || $duplex) {
                $new_relation = CONTACT_IS_FRIEND;
            }
            if ($relation == CONTACT_IS_SHARING && $duplex) {
                $duplex = 0;
            }
            $r = q("UPDATE `contact` SET \n\t\t\t\t`photo` = '%s', \n\t\t\t\t`thumb` = '%s',\n\t\t\t\t`micro` = '%s', \n\t\t\t\t`rel` = %d, \n\t\t\t\t`name-date` = '%s', \n\t\t\t\t`uri-date` = '%s', \n\t\t\t\t`avatar-date` = '%s', \n\t\t\t\t`blocked` = 0, \n\t\t\t\t`pending` = 0,\n\t\t\t\t`duplex` = %d,\n\t\t\t\t`hidden` = %d,\n\t\t\t\t`network` = 'dfrn' WHERE `id` = %d LIMIT 1\n\t\t\t", dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), intval($new_relation), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($duplex), intval($hidden), intval($contact_id));
        } else {
            // $network !== NETWORK_DFRN
            $network = $contact['network'] ? $contact['network'] : NETWORK_OSTATUS;
            $notify = $contact['notify'] ? $contact['notify'] : '';
            $poll = $contact['poll'] ? $contact['poll'] : '';
            if (!$contact['notify'] || !$contact['poll']) {
                $arr = lrdd($contact['url']);
                if (count($arr)) {
                    foreach ($arr as $link) {
                        if ($link['@attributes']['rel'] === 'salmon') {
                            $notify = $link['@attributes']['href'];
                        }
                        if ($link['@attributes']['rel'] === NAMESPACE_FEED) {
                            $poll = $link['@attributes']['href'];
                        }
                    }
                }
            }
            $new_relation = $contact['rel'];
            $writable = $contact['writable'];
            if ($network === NETWORK_DIASPORA) {
                if ($duplex) {
                    $new_relation = CONTACT_IS_FRIEND;
                } else {
                    $new_relation = CONTACT_IS_SHARING;
                }
                if ($new_relation != CONTACT_IS_FOLLOWER) {
                    $writable = 1;
                }
            }
            $r = q("DELETE FROM `intro` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($intro_id), intval($uid));
            $r = q("UPDATE `contact` SET `photo` = '%s', \n\t\t\t\t`thumb` = '%s',\n\t\t\t\t`micro` = '%s', \n\t\t\t\t`name-date` = '%s', \n\t\t\t\t`uri-date` = '%s', \n\t\t\t\t`avatar-date` = '%s', \n\t\t\t\t`notify` = '%s',\n\t\t\t\t`poll` = '%s',\n\t\t\t\t`blocked` = 0, \n\t\t\t\t`pending` = 0,\n\t\t\t\t`network` = '%s',\n\t\t\t\t`writable` = %d,\n\t\t\t\t`hidden` = %d,\n\t\t\t\t`rel` = %d\n\t\t\t\tWHERE `id` = %d LIMIT 1\n\t\t\t", dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($notify), dbesc($poll), dbesc($network), intval($writable), intval($hidden), intval($new_relation), intval($contact_id));
        }
        if ($r === false) {
            notice(t('Unable to set contact photo.') . EOL);
        }
        // reload contact info
        $r = q("SELECT * FROM `contact` WHERE `id` = %d LIMIT 1", intval($contact_id));
        if (count($r)) {
            $contact = $r[0];
        } else {
            $contact = null;
        }
        if (isset($new_relation) && $new_relation == CONTACT_IS_FRIEND) {
            if ($contact && $contact['network'] === NETWORK_DIASPORA) {
                require_once 'include/diaspora.php';
                $ret = diaspora_share($user[0], $r[0]);
                logger('mod_follow: diaspora_share returns: ' . $ret);
            }
            // Send a new friend post if we are allowed to...
            $r = q("SELECT `hide-friends` FROM `profile` WHERE `uid` = %d AND `is-default` = 1 LIMIT 1", intval($uid));
            if (count($r) && $r[0]['hide-friends'] == 0 && $activity && !$hidden) {
                require_once 'include/items.php';
                $self = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1", intval($uid));
                if (count($self)) {
                    $arr = array();
                    $arr['uri'] = $arr['parent-uri'] = item_new_uri($a->get_hostname(), $uid);
                    $arr['uid'] = $uid;
                    $arr['contact-id'] = $self[0]['id'];
                    $arr['wall'] = 1;
                    $arr['type'] = 'wall';
                    $arr['gravity'] = 0;
                    $arr['origin'] = 1;
                    $arr['author-name'] = $arr['owner-name'] = $self[0]['name'];
                    $arr['author-link'] = $arr['owner-link'] = $self[0]['url'];
                    $arr['author-avatar'] = $arr['owner-avatar'] = $self[0]['thumb'];
                    $A = '[url=' . $self[0]['url'] . ']' . $self[0]['name'] . '[/url]';
                    $APhoto = '[url=' . $self[0]['url'] . ']' . '[img]' . $self[0]['thumb'] . '[/img][/url]';
                    $B = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
                    $BPhoto = '[url=' . $contact['url'] . ']' . '[img]' . $contact['thumb'] . '[/img][/url]';
                    $arr['verb'] = ACTIVITY_FRIEND;
                    $arr['object-type'] = ACTIVITY_OBJ_PERSON;
                    $arr['body'] = sprintf(t('%1$s is now friends with %2$s'), $A, $B) . "\n\n\n" . $BPhoto;
                    $arr['object'] = '<object><type>' . ACTIVITY_OBJ_PERSON . '</type><title>' . $contact['name'] . '</title>' . '<id>' . $contact['url'] . '/' . $contact['name'] . '</id>';
                    $arr['object'] .= '<link>' . xmlify('<link rel="alternate" type="text/html" href="' . $contact['url'] . '" />' . "\n");
                    $arr['object'] .= xmlify('<link rel="photo" type="image/jpeg" href="' . $contact['thumb'] . '" />' . "\n");
                    $arr['object'] .= '</link></object>' . "\n";
                    $arr['last-child'] = 1;
                    $arr['allow_cid'] = $user[0]['allow_cid'];
                    $arr['allow_gid'] = $user[0]['allow_gid'];
                    $arr['deny_cid'] = $user[0]['deny_cid'];
                    $arr['deny_gid'] = $user[0]['deny_gid'];
                    $i = item_store($arr);
                    if ($i) {
                        proc_run('php', "include/notifier.php", "activity", "{$i}");
                    }
                }
            }
        }
        $g = q("select def_gid from user where uid = %d limit 1", intval($uid));
        if ($contact && $g && intval($g[0]['def_gid'])) {
            require_once 'include/group.php';
            group_add_member($uid, '', $contact['id'], $g[0]['def_gid']);
        }
        // Let's send our user to the contact editor in case they want to
        // do anything special with this new friend.
        if ($handsfree === null) {
            goaway($a->get_baseurl() . '/contacts/' . intval($contact_id));
        } else {
            return;
        }
        //NOTREACHED
    }
    /**
     *
     *
     * End of Scenario 1. [Local confirmation of remote friend request].
     *
     * Begin Scenario 2. This is the remote response to the above scenario.
     * This will take place on the site that originally initiated the friend request.
     * In the section above where the confirming party makes a POST and 
     * retrieves xml status information, they are communicating with the following code.
     *
     */
    if (x($_POST, 'source_url')) {
        // We are processing an external confirmation to an introduction created by our user.
        $public_key = x($_POST, 'public_key') ? $_POST['public_key'] : '';
        $dfrn_id = x($_POST, 'dfrn_id') ? hex2bin($_POST['dfrn_id']) : '';
        $source_url = x($_POST, 'source_url') ? hex2bin($_POST['source_url']) : '';
        $aes_key = x($_POST, 'aes_key') ? $_POST['aes_key'] : '';
        $duplex = x($_POST, 'duplex') ? intval($_POST['duplex']) : 0;
        $page = x($_POST, 'page') ? intval($_POST['page']) : 0;
        $version_id = x($_POST, 'dfrn_version') ? (double) $_POST['dfrn_version'] : 2.0;
        $forum = $page == 1 ? 1 : 0;
        $prv = $page == 2 ? 1 : 0;
        logger('dfrn_confirm: requestee contacted: ' . $node);
        logger('dfrn_confirm: request: POST=' . print_r($_POST, true), LOGGER_DATA);
        // If $aes_key is set, both of these items require unpacking from the hex transport encoding.
        if (x($aes_key)) {
            $aes_key = hex2bin($aes_key);
            $public_key = hex2bin($public_key);
        }
        // Find our user's account
        $r = q("SELECT * FROM `user` WHERE `nickname` = '%s' LIMIT 1", dbesc($node));
        if (!count($r)) {
            $message = sprintf(t('No user record found for \'%s\' '), $node);
            xml_status(3, $message);
            // failure
            // NOTREACHED
        }
        $my_prvkey = $r[0]['prvkey'];
        $local_uid = $r[0]['uid'];
        if (!strstr($my_prvkey, 'PRIVATE KEY')) {
            $message = t('Our site encryption key is apparently messed up.');
            xml_status(3, $message);
        }
        // verify everything
        $decrypted_source_url = "";
        openssl_private_decrypt($source_url, $decrypted_source_url, $my_prvkey);
        if (!strlen($decrypted_source_url)) {
            $message = t('Empty site URL was provided or URL could not be decrypted by us.');
            xml_status(3, $message);
            // NOTREACHED
        }
        $ret = q("SELECT * FROM `contact` WHERE `url` = '%s' AND `uid` = %d LIMIT 1", dbesc($decrypted_source_url), intval($local_uid));
        if (!count($ret)) {
            if (strstr($decrypted_source_url, 'http:')) {
                $newurl = str_replace('http:', 'https:', $decrypted_source_url);
            } else {
                $newurl = str_replace('https:', 'http:', $decrypted_source_url);
            }
            $ret = q("SELECT * FROM `contact` WHERE `url` = '%s' AND `uid` = %d LIMIT 1", dbesc($newurl), intval($local_uid));
            if (!count($ret)) {
                // this is either a bogus confirmation (?) or we deleted the original introduction.
                $message = t('Contact record was not found for you on our site.');
                xml_status(3, $message);
                return;
                // NOTREACHED
            }
        }
        $relation = $ret[0]['rel'];
        // Decrypt all this stuff we just received
        $foreign_pubkey = $ret[0]['site-pubkey'];
        $dfrn_record = $ret[0]['id'];
        if (!$foreign_pubkey) {
            $message = sprintf(t('Site public key not available in contact record for URL %s.'), $newurl);
            xml_status(3, $message);
        }
        $decrypted_dfrn_id = "";
        openssl_public_decrypt($dfrn_id, $decrypted_dfrn_id, $foreign_pubkey);
        if (strlen($aes_key)) {
            $decrypted_aes_key = "";
            openssl_private_decrypt($aes_key, $decrypted_aes_key, $my_prvkey);
            $dfrn_pubkey = openssl_decrypt($public_key, 'AES-256-CBC', $decrypted_aes_key);
        } else {
            $dfrn_pubkey = $public_key;
        }
        $r = q("SELECT * FROM `contact` WHERE `dfrn-id` = '%s' LIMIT 1", dbesc($decrypted_dfrn_id));
        if (count($r)) {
            $message = t('The ID provided by your system is a duplicate on our system. It should work if you try again.');
            xml_status(1, $message);
            // Birthday paradox - duplicate dfrn-id
            // NOTREACHED
        }
        $r = q("UPDATE `contact` SET `dfrn-id` = '%s', `pubkey` = '%s' WHERE `id` = %d LIMIT 1", dbesc($decrypted_dfrn_id), dbesc($dfrn_pubkey), intval($dfrn_record));
        if (!count($r)) {
            $message = t('Unable to set your contact credentials on our system.');
            xml_status(3, $message);
        }
        // It's possible that the other person also requested friendship.
        // If it is a duplex relationship, ditch the issued-id if one exists.
        if ($duplex) {
            $r = q("UPDATE `contact` SET `issued-id` = '' WHERE `id` = %d LIMIT 1", intval($dfrn_record));
        }
        // We're good but now we have to scrape the profile photo and send notifications.
        $r = q("SELECT `photo` FROM `contact` WHERE `id` = %d LIMIT 1", intval($dfrn_record));
        if (count($r)) {
            $photo = $r[0]['photo'];
        } else {
            $photo = $a->get_baseurl() . '/images/person-175.jpg';
        }
        require_once "include/Photo.php";
        $photos = import_profile_photo($photo, $local_uid, $dfrn_record);
        logger('dfrn_confirm: request - photos imported');
        $new_relation = CONTACT_IS_SHARING;
        if ($relation == CONTACT_IS_FOLLOWER || $duplex) {
            $new_relation = CONTACT_IS_FRIEND;
        }
        if ($relation == CONTACT_IS_FOLLOWER && $duplex) {
            $duplex = 0;
        }
        $r = q("UPDATE `contact` SET \n\t\t\t`photo` = '%s', \n\t\t\t`thumb` = '%s', \n\t\t\t`micro` = '%s',\n\t\t\t`rel` = %d, \n\t\t\t`name-date` = '%s', \n\t\t\t`uri-date` = '%s', \n\t\t\t`avatar-date` = '%s', \n\t\t\t`blocked` = 0, \n\t\t\t`pending` = 0,\n\t\t\t`duplex` = %d, \n\t\t\t`forum` = %d,\n\t\t\t`prv` = %d,\n\t\t\t`network` = '%s' WHERE `id` = %d LIMIT 1\n\t\t", dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), intval($new_relation), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc(datetime_convert()), intval($duplex), intval($forum), intval($prv), dbesc(NETWORK_DFRN), intval($dfrn_record));
        if ($r === false) {
            // indicates schema is messed up or total db failure
            $message = t('Unable to update your contact profile details on our system');
            xml_status(3, $message);
        }
        // Otherwise everything seems to have worked and we are almost done. Yay!
        // Send an email notification
        logger('dfrn_confirm: request: info updated');
        $r = q("SELECT `contact`.*, `user`.* FROM `contact` LEFT JOIN `user` ON `contact`.`uid` = `user`.`uid`\n\t\t\tWHERE `contact`.`id` = %d LIMIT 1", intval($dfrn_record));
        if (count($r)) {
            $combined = $r[0];
        }
        if (count($r) && $r[0]['notify-flags'] & NOTIFY_CONFIRM) {
            push_lang($r[0]['language']);
            $tpl = $new_relation == CONTACT_IS_FRIEND ? get_intltext_template('friend_complete_eml.tpl') : get_intltext_template('intro_complete_eml.tpl');
            $email_tpl = replace_macros($tpl, array('$sitename' => $a->config['sitename'], '$siteurl' => $a->get_baseurl(), '$username' => $r[0]['username'], '$email' => $r[0]['email'], '$fn' => $r[0]['name'], '$dfrn_url' => $r[0]['url'], '$uid' => $newuid));
            require_once 'include/email.php';
            $res = mail($r[0]['email'], email_header_encode(sprintf(t("Connection accepted at %s"), $a->config['sitename']), 'UTF-8'), $email_tpl, 'From: ' . 'Administrator' . '@' . $_SERVER['SERVER_NAME'] . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit');
            if (!$res) {
                // pointless throwing an error here and confusing the person at the other end of the wire.
            }
            pop_lang();
        }
        // Send a new friend post if we are allowed to...
        if ($page && intval(get_pconfig($local_uid, 'system', 'post_joingroup'))) {
            $r = q("SELECT `hide-friends` FROM `profile` WHERE `uid` = %d AND `is-default` = 1 LIMIT 1", intval($local_uid));
            if (count($r) && $r[0]['hide-friends'] == 0) {
                require_once 'include/items.php';
                $self = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1", intval($local_uid));
                if (count($self)) {
                    $arr = array();
                    $arr['uri'] = $arr['parent-uri'] = item_new_uri($a->get_hostname(), $local_uid);
                    $arr['uid'] = $local_uid;
                    $arr['contact-id'] = $self[0]['id'];
                    $arr['wall'] = 1;
                    $arr['type'] = 'wall';
                    $arr['gravity'] = 0;
                    $arr['origin'] = 1;
                    $arr['author-name'] = $arr['owner-name'] = $self[0]['name'];
                    $arr['author-link'] = $arr['owner-link'] = $self[0]['url'];
                    $arr['author-avatar'] = $arr['owner-avatar'] = $self[0]['thumb'];
                    $A = '[url=' . $self[0]['url'] . ']' . $self[0]['name'] . '[/url]';
                    $APhoto = '[url=' . $self[0]['url'] . ']' . '[img]' . $self[0]['thumb'] . '[/img][/url]';
                    $B = '[url=' . $combined['url'] . ']' . $combined['name'] . '[/url]';
                    $BPhoto = '[url=' . $combined['url'] . ']' . '[img]' . $combined['thumb'] . '[/img][/url]';
                    $arr['verb'] = ACTIVITY_JOIN;
                    $arr['object-type'] = ACTIVITY_OBJ_GROUP;
                    $arr['body'] = sprintf(t('%1$s has joined %2$s'), $A, $B) . "\n\n\n" . $BPhoto;
                    $arr['object'] = '<object><type>' . ACTIVITY_OBJ_GROUP . '</type><title>' . $combined['name'] . '</title>' . '<id>' . $combined['url'] . '/' . $combined['name'] . '</id>';
                    $arr['object'] .= '<link>' . xmlify('<link rel="alternate" type="text/html" href="' . $combined['url'] . '" />' . "\n");
                    $arr['object'] .= xmlify('<link rel="photo" type="image/jpeg" href="' . $combined['thumb'] . '" />' . "\n");
                    $arr['object'] .= '</link></object>' . "\n";
                    $arr['last-child'] = 1;
                    $arr['allow_cid'] = $user[0]['allow_cid'];
                    $arr['allow_gid'] = $user[0]['allow_gid'];
                    $arr['deny_cid'] = $user[0]['deny_cid'];
                    $arr['deny_gid'] = $user[0]['deny_gid'];
                    $i = item_store($arr);
                    if ($i) {
                        proc_run('php', "include/notifier.php", "activity", "{$i}");
                    }
                }
            }
        }
        xml_status(0);
        // Success
        return;
        // NOTREACHED
        ////////////////////// End of this scenario ///////////////////////////////////////////////
    }
    // somebody arrived here by mistake or they are fishing. Send them to the homepage.
    goaway(z_root());
    // NOTREACHED
}
示例#20
0
function verify_email_address($arr)
{
    $hash = random_string();
    $r = q("INSERT INTO register ( hash, created, uid, password, language ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ", dbesc($hash), dbesc(datetime_convert()), intval($arr['account']['account_id']), dbesc('verify'), dbesc($arr['account']['account_language']));
    $email_msg = replace_macros(get_intltext_template('register_verify_member.tpl'), array('$sitename' => get_config('system', 'sitename'), '$siteurl' => z_root(), '$email' => $arr['email'], '$uid' => $arr['account']['account_id'], '$hash' => $hash, '$details' => $details));
    $res = mail($arr['email'], email_header_encode(sprintf(t('Registration confirmation for %s'), get_config('system', 'sitename'))), $email_msg, 'From: ' . 'Administrator' . '@' . get_app()->get_hostname() . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit');
    if ($res) {
        $delivered++;
    } else {
        logger('send_reg_approval_email: failed to ' . $admin['email'] . 'account_id: ' . $arr['account']['account_id']);
    }
    return $res;
}
示例#21
0
 function register_post(&$a)
 {
     global $lang;
     $verified = 0;
     $blocked = 1;
     $arr = array('post' => $_POST);
     call_hooks('register_post', $arr);
     $max_dailies = intval(get_config('system', 'max_daily_registrations'));
     if ($max_dailies) {
         $r = q("select count(*) as total from user where register_date > UTC_TIMESTAMP - INTERVAL 1 day");
         if ($r && $r[0]['total'] >= $max_dailies) {
             return;
         }
     }
     switch ($a->config['register_policy']) {
         case REGISTER_OPEN:
             $blocked = 0;
             $verified = 1;
             break;
         case REGISTER_APPROVE:
             $blocked = 1;
             $verified = 0;
             break;
         default:
         case REGISTER_CLOSED:
             if (!x($_SESSION, 'authenticated') && !x($_SESSION, 'administrator')) {
                 notice(t('Permission denied.') . EOL);
                 return;
             }
             $blocked = 1;
             $verified = 0;
             break;
     }
     require_once 'include/user.php';
     $arr = $_POST;
     $arr['blocked'] = $blocked;
     $arr['verified'] = $verified;
     $result = create_user($arr);
     if (!$result['success']) {
         notice($result['message']);
         return;
     }
     $user = $result['user'];
     if ($netpublish && $a->config['register_policy'] != REGISTER_APPROVE) {
         $url = $a->get_baseurl() . '/profile/' . $user['nickname'];
         proc_run('php', "include/directory.php", "{$url}");
     }
     $using_invites = get_config('system', 'invitation_only');
     $num_invites = get_config('system', 'number_invites');
     $invite_id = x($_POST, 'invite_id') ? notags(trim($_POST['invite_id'])) : '';
     if ($a->config['register_policy'] == REGISTER_OPEN) {
         if ($using_invites && $invite_id) {
             q("delete * from register where hash = '%s' limit 1", dbesc($invite_id));
             set_pconfig($user['uid'], 'system', 'invites_remaining', $num_invites);
         }
         $email_tpl = get_intltext_template("register_open_eml.tpl");
         $email_tpl = replace_macros($email_tpl, array('$sitename' => $a->config['sitename'], '$siteurl' => $a->get_baseurl(), '$username' => $user['username'], '$email' => $user['email'], '$password' => $result['password'], '$uid' => $user['uid']));
         $res = mail($user['email'], email_header_encode(sprintf(t('Registration details for %s'), $a->config['sitename']), 'UTF-8'), $email_tpl, 'From: ' . 'Administrator' . '@' . $_SERVER['SERVER_NAME'] . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit');
         if ($res) {
             info(t('Registration successful. Please check your email for further instructions.') . EOL);
             goaway(z_root());
         } else {
             notice(t('Failed to send email message. Here is the message that failed.') . $email_tpl . EOL);
         }
     } elseif ($a->config['register_policy'] == REGISTER_APPROVE) {
         if (!strlen($a->config['admin_email'])) {
             notice(t('Your registration can not be processed.') . EOL);
             goaway(z_root());
         }
         $hash = random_string();
         $r = q("INSERT INTO `register` ( `hash`, `created`, `uid`, `password`, `language` ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ", dbesc($hash), dbesc(datetime_convert()), intval($user['uid']), dbesc($result['password']), dbesc($lang));
         $r = q("SELECT `language` FROM `user` WHERE `email` = '%s' LIMIT 1", dbesc($a->config['admin_email']));
         if (count($r)) {
             push_lang($r[0]['language']);
         } else {
             push_lang('en');
         }
         if ($using_invites && $invite_id) {
             q("delete * from register where hash = '%s' limit 1", dbesc($invite_id));
             set_pconfig($user['uid'], 'system', 'invites_remaining', $num_invites);
         }
         $email_tpl = get_intltext_template("register_verify_eml.tpl");
         $email_tpl = replace_macros($email_tpl, array('$sitename' => $a->config['sitename'], '$siteurl' => $a->get_baseurl(), '$username' => $user['username'], '$email' => $user['email'], '$password' => $result['password'], '$uid' => $user['uid'], '$hash' => $hash));
         $res = mail($a->config['admin_email'], email_header_encode(sprintf(t('Registration request at %s'), $a->config['sitename']), 'UTF-8'), $email_tpl, 'From: ' . 'Administrator' . '@' . $_SERVER['SERVER_NAME'] . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'Content-transfer-encoding: 8bit');
         pop_lang();
         if ($res) {
             info(t('Your registration is pending approval by the site owner.') . EOL);
             goaway(z_root());
         }
     }
     return;
 }