예제 #1
0
 /**
  * Main email posting controller, reads, parses, checks and posts an email message or PM
  *
  * What it does:
  * - Allows a user to reply to a topic on the board by emailing a reply to a
  * notification message.
  * - It must have the security key in the email or it will be rejected
  * - It must be from the email of a registered user
  * - The key must have been sent to that user
  * - Keys are used once and then discarded
  * - Accessed by email imap cron script, and ManageMaillist.controller.php.
  *
  * @param string|null $data used to supply a full headers+body email
  * @param boolean $force used to override common failure errors
  * @param string|null $key used to supply a lost key
  */
 public function action_pbe_post($data = null, $force = false, $key = null)
 {
     global $txt, $modSettings, $language, $user_info, $maintenance;
     // The function is not even on ...
     if (empty($modSettings['maillist_enabled'])) {
         return;
     }
     // Our mail parser and our main subs
     require_once SUBSDIR . '/EmailParse.class.php';
     require_once SUBSDIR . '/Emailpost.subs.php';
     // Init
     loadLanguage('Maillist');
     setMemoryLimit('128M');
     // Load the email parser and get some data to work with
     $email_message = new Email_Parse();
     $email_message->read_data($data, BOARDDIR);
     if (!$email_message->raw_message) {
         return false;
     }
     // Ask for an html version (if available) and some needed details
     $email_message->read_email(true, $email_message->raw_message);
     $email_message->load_address();
     $email_message->load_key($key);
     // If the feature is on but the post/pm function is not enabled, just log the message.
     if (empty($modSettings['pbe_post_enabled']) && empty($modSettings['pbe_pm_enabled'])) {
         return pbe_emailError('error_email_notenabled', $email_message);
     }
     // Spam I am?
     if ($email_message->load_spam() && !$force) {
         return pbe_emailError('error_found_spam', $email_message);
     }
     // Load the user from the database based on the sending email address
     $email_message->email['from'] = !empty($email_message->email['from']) ? strtolower($email_message->email['from']) : '';
     $pbe = query_load_user_info($email_message->email['from']);
     // Can't find this email in our database, a non-user, a spammer, a looser, a poser or even worse?
     if (empty($pbe)) {
         return pbe_emailError('error_not_find_member', $email_message);
     }
     // Find the message security key, without it we are not going anywhere ever
     if (empty($email_message->message_key_id)) {
         return pbe_emailError('error_missing_key', $email_message);
     }
     // Good we have a key, who was it sent to?
     $key_owner = query_key_owner($email_message->message_key_id);
     // Can't find this key in the database, either
     // a) spam attempt or b) replying with an expired/consumed key
     if (empty($key_owner) && !$force) {
         return pbe_emailError('error_' . ($email_message->message_type === 'p' ? 'pm_' : '') . 'not_find_entry', $email_message);
     }
     // The key received was not sent to this member ... how we love those email aggregators
     if (strtolower($key_owner) !== $email_message->email['from'] && !$force) {
         return pbe_emailError('error_key_sender_match', $email_message);
     }
     // In maintenance mode, just log it for now
     if (!empty($maintenance) && $maintenance !== 2 && !$pbe['user_info']['is_admin'] && !$user_info['is_admin']) {
         return pbe_emailError('error_in_maintenance_mode', $email_message);
     }
     // The email looks valid, now on to check the actual user trying to make the post/pm
     // lets load the topic/message info and any additional permissions we need
     if ($email_message->message_type === 't' || $email_message->message_type === 'm') {
         // Load the message/topic details
         $topic_info = query_load_message($email_message->message_type, $email_message->message_id, $pbe);
         if (empty($topic_info)) {
             return pbe_emailError('error_topic_gone', $email_message);
         }
         // Load board permissions
         query_load_permissions('board', $pbe, $topic_info);
     } else {
         // Load the PM details
         $pm_info = query_load_message($email_message->message_type, $email_message->message_id, $pbe);
         if (empty($pm_info)) {
             // Duh oh ... likely they deleted the PM on the site and are now
             // replying to the PM by email, the agony!
             return pbe_emailError('error_pm_not_found', $email_message);
         }
     }
     // Account for moderation actions
     pbe_check_moderation($pbe);
     // Maybe they want to do additional spam / security checking
     call_integration_hook('integrate_mailist_checks_before', array($email_message, $pbe));
     // Load in the correct Re: for the language
     if ($language === $pbe['user_info']['language']) {
         $pbe['response_prefix'] = $txt['response_prefix'];
     } else {
         loadLanguage('index', $language, false);
         $pbe['response_prefix'] = $txt['response_prefix'];
         loadLanguage('index');
     }
     // Allow for new topics to be started via a email subject change
     if (!empty($modSettings['maillist_newtopic_change']) && $email_message->message_type === 'm') {
         $subject = str_replace($pbe['response_prefix'], '', pbe_clean_email_subject($email_message->subject));
         $current_subject = str_replace($pbe['response_prefix'], '', $topic_info['subject']);
         // If it does not match, then we go to make a new topic instead
         if (trim($subject) != trim($current_subject)) {
             $board_info = query_load_board_details($topic_info['id_board'], $pbe);
             return pbe_create_topic($pbe, $email_message, $board_info);
         }
     }
     // Time to make a Post or a PM, first up topic and message replies
     if ($email_message->message_type === 't' || $email_message->message_type === 'm') {
         $result = pbe_create_post($pbe, $email_message, $topic_info);
     } elseif ($email_message->message_type === 'p') {
         $result = pbe_create_pm($pbe, $email_message, $pm_info);
     }
     if (!empty($result)) {
         // We have now posted or PM'ed .. lets do some database maintenance cause maintenance is fun :'(
         query_key_maintenance($email_message);
         // Update this user so the log shows they were/are active, no luking in the email ether
         query_update_member_stats($pbe, $email_message, $email_message->message_type === 'p' ? $pm_info : $topic_info);
     }
     return !empty($result);
 }
예제 #2
0
/**
 * Creates a failed email entry in the postby_emails_error table
 *
 * - Attempts an auto-correct for common errors so the admin / moderator
 * - can choose to approve the email with the corrections
 *
 * @package Maillist
 * @param string $error
 * @param Email_Parse $email_message
 */
function pbe_emailError($error, $email_message)
{
    global $txt;
    $db = database();
    loadLanguage('EmailTemplates');
    // Some extra items we will need to remove from the message subject
    $pm_subject_leader = str_replace('{SUBJECT}', '', $txt['new_pm_subject']);
    // Clean the subject like we don't know where it has been
    $subject = trim(str_replace($pm_subject_leader, '', $email_message->subject));
    $subject = pbe_clean_email_subject($subject);
    $subject = $subject === '' ? $txt['no_subject'] : $subject;
    // Start off with what we know about the security key, even if its nothing
    $message_key = (string) $email_message->message_key_id;
    $message_type = (string) $email_message->message_type;
    $message_id = (int) $email_message->message_id;
    $board_id = -1;
    // First up is the old, wrong email address, lets see who this should have come from if its not a new topic request
    if ($error === 'error_not_find_member' && $email_message->message_type !== 'x') {
        $key_owner = query_key_owner($email_message->message_key_id);
        if (!empty($key_owner)) {
            // Valid key so show who should have sent this key in? email aggravaters :P often mess this up
            $email_message->email['from'] = $email_message->email['from'] . ' => ' . $key_owner;
            // Since we have a valid key set those details as well
            $message_key = $email_message->message_key_id;
            $message_type = $email_message->message_type;
            $message_id = $email_message->message_id;
        }
    }
    // A valid key but it was not sent to this user ... but we did get the email from a valid site user
    if ($error === 'error_key_sender_match') {
        $key_owner = query_key_owner($email_message->message_key_id);
        if (!empty($key_owner)) {
            // Valid key so show who should have sent this key in
            $email_message->email['from'] = $key_owner . ' => ' . $email_message->email['from'];
            // Since we have a valid key set those details as well
            $message_key = $email_message->message_key_id;
            $message_type = $email_message->message_type;
            $message_id = $email_message->message_id;
        }
    }
    // No key? We should at a minimum have who its from and a subject, so use that
    if ($email_message->message_type !== 'x' && (empty($message_key) || $error === 'error_pm_not_found')) {
        // We don't have the message type (since we don't have a key)
        // Attempt to see if it might be a PM so we handle it correctly
        if (empty($message_type) && strpos($email_message->subject, $pm_subject_leader) !== false) {
            $message_type = 'p';
        }
        // Find all keys sent to this user, sorted by date
        $user_keys = query_user_keys($email_message->email['from']);
        // While we have keys to look at see if we can match up this lost message on subjects
        foreach ($user_keys as $user_key) {
            if (preg_match('~([a-z0-9]{32})\\-(p|t|m)(\\d+)~', $user_key['id_email'], $match)) {
                $key = $match[0];
                $type = $match[2];
                $message = $match[3];
                // If we know/suspect its a "m,t or p" then use that to avoid a match on a wrong type, that would be bad ;)
                if (!empty($message_type) && $message_type === $type || empty($message_type) && $type !== 'p') {
                    // lets look up this message/topic/pm and see if the subjects match ... if they do then tada!
                    if (query_load_subject($message, $type, $email_message->email['from']) === $subject) {
                        // This email has a subject that matches the subject of a message that was sent to them
                        $message_key = $key;
                        $message_id = $message;
                        $message_type = $type;
                        break;
                    }
                }
            }
        }
    }
    // Maybe we have enough to find the board id where this was going
    if (!empty($message_id) && $message_type !== 'p') {
        $board_id = query_load_board($message_id);
    }
    // Log the error so the moderators can take a look, helps keep them sharp
    $id = isset($_REQUEST['item']) ? (int) $_REQUEST['item'] : 0;
    $db->insert(!empty($id) ? 'replace' : 'ignore', '{db_prefix}postby_emails_error', array('id_email' => 'int', 'error' => 'string', 'data_id' => 'string', 'subject' => 'string', 'id_message' => 'int', 'id_board' => 'int', 'email_from' => 'string', 'message_type' => 'string', 'message' => 'string'), array($id, $error, $message_key, $subject, $message_id, $board_id, $email_message->email['from'], $message_type, $email_message->raw_message), array('id_email'));
    // Flush the moderator error number cache, if we are here it likely just changed.
    cache_put_data('num_menu_errors', null, 900);
    // If not running from the cli, then go back to the form
    if (isset($_POST['item'])) {
        // Back to the form we go
        $_SESSION['email_error'] = $txt[$error];
        redirectexit('action=admin;area=maillist');
    }
    return false;
}