示例#1
0
    die('Hacking attempt...');
}
// The shop action (for the template)
$context['shop_do'] = 'bank';
// Add to the linktree
$context['linktree'][] = array('url' => $scripturl . '?action=shop;do=bank', 'name' => $txt['shop_bank']);
// Are they allowed in the bank?
isAllowedTo('shop_bank');
// If we're in the main page of the bank
if ($_GET['do'] == 'bank') {
    // Set the page title
    $context['page_title'] = $txt['shop'] . ' - ' . $txt['shop_bank'];
    // Load the 'bank' sub template
    $context['sub_template'] = 'bank';
} elseif ($_GET['do'] == 'bank2') {
    spamProtection('login');
    // Make sure the amount of money is numeric
    $_POST['amount'] = (double) $_POST['amount'];
    // If they're depositing some money
    if ($_POST['type'] == 'deposit') {
        // If user is trying to deposit more money than they have
        if ($_POST['amount'] + $modSettings['shopFeeDeposit'] > $context['user']['money']) {
            $context['shop_buy_message'] = $txt['shop_dont_have_much'];
        } elseif ($_POST['amount'] <= 0) {
            $context['shop_buy_message'] = $txt['shop_no_negative'];
        } elseif ($_POST['amount'] < $modSettings['shopMinDeposit']) {
            $context['shop_buy_message'] = sprintf($txt['shop_deposit_small'], formatMoney($modSettings['shopMinDeposit']));
        } else {
            // Add amount to member's bank money, and remove from money in pockey
            db_query("\n\t\t\t\tUPDATE {$db_prefix}members\n\t\t\t\tSET moneyBank = moneyBank + {$_POST['amount']},\n\t\t\t\t\tmoney = money - ({$_POST['amount']} + {$modSettings['shopFeeDeposit']})\n\t\t\t\tWHERE ID_MEMBER = {$ID_MEMBER}\n\t\t\t\tLIMIT 1", __FILE__, __LINE__);
            cache_put_data('user_settings-' . $ID_MEMBER, null, 60);
示例#2
0
function MessagePost2()
{
    global $txt, $ID_MEMBER, $context, $sourcedir;
    global $db_prefix, $user_info, $modSettings, $scripturl, $func;
    isAllowedTo('pm_send');
    require_once $sourcedir . '/Subs-Auth.php';
    if (loadLanguage('PersonalMessage', '', false) === false) {
        loadLanguage('InstantMessage');
    }
    // Extract out the spam settings - it saves database space!
    list($modSettings['max_pm_recipients'], $modSettings['pm_posts_verification'], $modSettings['pm_posts_per_hour']) = explode(',', $modSettings['pm_spam_settings']);
    // Check whether we've gone over the limit of messages we can send per hour - fatal error if fails!
    if (!empty($modSettings['pm_posts_per_hour']) && !allowedTo(array('admin_forum', 'moderate_forum', 'send_mail'))) {
        // How many messages have they sent this last hour?
        $request = db_query("\n\t\t\tSELECT COUNT(pr.ID_PM) AS postCount\n\t\t\tFROM ({$db_prefix}personal_messages AS pm, {$db_prefix}pm_recipients AS pr)\n\t\t\tWHERE pm.ID_MEMBER_FROM = {$ID_MEMBER}\n\t\t\t\tAND pm.msgtime > " . (time() - 3600) . "\n\t\t\t\tAND pr.ID_PM = pm.ID_PM", __FILE__, __LINE__);
        list($postCount) = mysql_fetch_row($request);
        mysql_free_result($request);
        if (!empty($postCount) && $postCount >= $modSettings['pm_posts_per_hour']) {
            // Excempt moderators.
            $request = db_query("\n\t\t\t\tSELECT ID_MEMBER\n\t\t\t\tFROM {$db_prefix}moderators\n\t\t\t\tWHERE ID_MEMBER = {$ID_MEMBER}", __FILE__, __LINE__);
            if (mysql_num_rows($request) == 0) {
                fatal_error(sprintf($txt['pm_too_many_per_hour'], $modSettings['pm_posts_per_hour']));
            }
            mysql_free_result($request);
        }
    }
    // Initialize the errors we're about to make.
    $post_errors = array();
    // If your session timed out, show an error, but do allow to re-submit.
    if (checkSession('post', '', false) != '') {
        $post_errors[] = 'session_timeout';
    }
    $_REQUEST['subject'] = isset($_REQUEST['subject']) ? trim($_REQUEST['subject']) : '';
    $_REQUEST['to'] = empty($_POST['to']) ? empty($_GET['to']) ? '' : $_GET['to'] : stripslashes($_POST['to']);
    $_REQUEST['bcc'] = empty($_POST['bcc']) ? empty($_GET['bcc']) ? '' : $_GET['bcc'] : stripslashes($_POST['bcc']);
    // Did they make any mistakes?
    if ($_REQUEST['subject'] == '') {
        $post_errors[] = 'no_subject';
    }
    if (!isset($_REQUEST['message']) || $_REQUEST['message'] == '') {
        $post_errors[] = 'no_message';
    } elseif (!empty($modSettings['max_messageLength']) && $func['strlen']($_REQUEST['message']) > $modSettings['max_messageLength']) {
        $post_errors[] = 'long_message';
    }
    if (empty($_REQUEST['to']) && empty($_REQUEST['bcc']) && empty($_REQUEST['u'])) {
        $post_errors[] = 'no_to';
    }
    // Wrong verification code?
    if (!$user_info['is_admin'] && !empty($modSettings['pm_posts_verification']) && $user_info['posts'] < $modSettings['pm_posts_verification'] && (empty($_REQUEST['visual_verification_code']) || strtoupper($_REQUEST['visual_verification_code']) !== $_SESSION['visual_verification_code'])) {
        $post_errors[] = 'wrong_verification_code';
    }
    // If they did, give a chance to make ammends.
    if (!empty($post_errors)) {
        return messagePostError($post_errors, $func['htmlspecialchars']($_REQUEST['to']), $func['htmlspecialchars']($_REQUEST['bcc']));
    }
    // Want to take a second glance before you send?
    if (isset($_REQUEST['preview'])) {
        // Set everything up to be displayed.
        $context['preview_subject'] = $func['htmlspecialchars'](stripslashes($_REQUEST['subject']));
        $context['preview_message'] = $func['htmlspecialchars'](stripslashes($_REQUEST['message']), ENT_QUOTES);
        preparsecode($context['preview_message'], true);
        // Parse out the BBC if it is enabled.
        $context['preview_message'] = parse_bbc($context['preview_message']);
        // Censor, as always.
        censorText($context['preview_subject']);
        censorText($context['preview_message']);
        // Set a descriptive title.
        $context['page_title'] = $txt[507] . ' - ' . $context['preview_subject'];
        // Pretend they messed up :P.
        return messagePostError(array(), $func['htmlspecialchars']($_REQUEST['to']), $func['htmlspecialchars']($_REQUEST['bcc']));
    }
    // Protect from message spamming.
    spamProtection('spam');
    // Prevent double submission of this form.
    checkSubmitOnce('check');
    // Initialize member ID array.
    $recipients = array('to' => array(), 'bcc' => array());
    // Format the to and bcc members.
    $input = array('to' => array(), 'bcc' => array());
    if (empty($_REQUEST['u'])) {
        // To who..?
        if (!empty($_REQUEST['to'])) {
            // We're going to take out the "s anyway ;).
            $_REQUEST['to'] = strtr($_REQUEST['to'], array('\\"' => '"'));
            preg_match_all('~"([^"]+)"~', $_REQUEST['to'], $matches);
            $input['to'] = array_unique(array_merge($matches[1], explode(',', preg_replace('~"([^"]+)"~', '', $_REQUEST['to']))));
        }
        // Your secret's safe with me!
        if (!empty($_REQUEST['bcc'])) {
            // We're going to take out the "s anyway ;).
            $_REQUEST['bcc'] = strtr($_REQUEST['bcc'], array('\\"' => '"'));
            preg_match_all('~"([^"]+)"~', $_REQUEST['bcc'], $matches);
            $input['bcc'] = array_unique(array_merge($matches[1], explode(',', preg_replace('~"([^"]+)"~', '', $_REQUEST['bcc']))));
        }
        foreach ($input as $rec_type => $rec) {
            foreach ($rec as $index => $member) {
                if (strlen(trim($member)) > 0) {
                    $input[$rec_type][$index] = $func['htmlspecialchars']($func['strtolower'](stripslashes(trim($member))));
                } else {
                    unset($input[$rec_type][$index]);
                }
            }
        }
        // Find the requested members - bcc and to.
        $foundMembers = findMembers(array_merge($input['to'], $input['bcc']));
        // Store IDs of the members that were found.
        foreach ($foundMembers as $member) {
            // It's easier this way.
            $member['name'] = strtr($member['name'], array('&#039;' => '\''));
            foreach ($input as $rec_type => $to_members) {
                if (array_intersect(array($func['strtolower']($member['username']), $func['strtolower']($member['name']), $func['strtolower']($member['email'])), $to_members)) {
                    $recipients[$rec_type][] = $member['id'];
                    // Get rid of this username. The ones that remain were not found.
                    $input[$rec_type] = array_diff($input[$rec_type], array($func['strtolower']($member['username']), $func['strtolower']($member['name']), $func['strtolower']($member['email'])));
                }
            }
        }
    } else {
        $_REQUEST['u'] = explode(',', $_REQUEST['u']);
        foreach ($_REQUEST['u'] as $key => $uID) {
            $_REQUEST['u'][$key] = (int) $uID;
        }
        $request = db_query("\n\t\t\tSELECT ID_MEMBER\n\t\t\tFROM {$db_prefix}members\n\t\t\tWHERE ID_MEMBER IN (" . implode(',', $_REQUEST['u']) . ")\n\t\t\tLIMIT " . count($_REQUEST['u']), __FILE__, __LINE__);
        while ($row = mysql_fetch_assoc($request)) {
            $recipients['to'][] = $row['ID_MEMBER'];
        }
        mysql_free_result($request);
    }
    // Before we send the PM, let's make sure we don't have an abuse of numbers.
    if (!empty($modSettings['max_pm_recipients']) && count($recipients['to']) + count($recipients['bcc']) > $modSettings['max_pm_recipients'] && !allowedTo(array('moderate_forum', 'send_mail', 'admin_forum'))) {
        $context['send_log'] = array('sent' => array(), 'failed' => array(sprintf($txt['pm_too_many_recipients'], $modSettings['max_pm_recipients'])));
    } else {
        if (!empty($recipients['to']) || !empty($recipients['bcc'])) {
            $context['send_log'] = sendpm($recipients, $_REQUEST['subject'], $_REQUEST['message'], !empty($_REQUEST['outbox']));
        } else {
            $context['send_log'] = array('sent' => array(), 'failed' => array());
        }
    }
    // Add a log message for all recipients that were not found.
    foreach ($input as $rec_type => $rec) {
        // Either bad_to or bad_bcc.
        if (!empty($rec) && !in_array('bad_' . $rec_type, $post_errors)) {
            $post_errors[] = 'bad_' . $rec_type;
        }
        foreach ($rec as $i => $member) {
            $context['send_log']['failed'][] = sprintf($txt['pm_error_user_not_found'], $input[$rec_type][$i]);
        }
    }
    // Mark the message as "replied to".
    if (!empty($context['send_log']['sent']) && !empty($_REQUEST['replied_to']) && isset($_REQUEST['f']) && $_REQUEST['f'] == 'inbox') {
        db_query("\n\t\t\tUPDATE {$db_prefix}pm_recipients\n\t\t\tSET is_read = is_read | 2\n\t\t\tWHERE ID_PM = " . (int) $_REQUEST['replied_to'] . "\n\t\t\t\tAND ID_MEMBER = {$ID_MEMBER}\n\t\t\tLIMIT 1", __FILE__, __LINE__);
    }
    // If one or more of the recipient were invalid, go back to the post screen with the failed usernames.
    if (!empty($context['send_log']['failed'])) {
        return messagePostError($post_errors, empty($input['to']) ? '' : '&quot;' . implode('&quot;, &quot;', $input['to']) . '&quot;', empty($input['bcc']) ? '' : '&quot;' . implode('&quot;, &quot;', $input['bcc']) . '&quot;');
    }
    // Go back to the where they sent from, if possible...
    redirectexit($context['current_label_redirect']);
}
示例#3
0
function method_report_post()
{
    global $context, $mobdb, $modSettings, $scripturl, $user_info, $sourcedir, $txt;
    // Get the message ID
    if (!isset($context['mob_request']['params'][0])) {
        outputRPCResult(false, $txt['smf272']);
    }
    $id_msg = (int) $context['mob_request']['params'][0][0];
    $reason = utf8ToAscii(base64_decode($context['mob_request']['params'][1][0]));
    require_once $sourcedir . '/Subs-Post.php';
    $mobdb->query("\n        SELECT m.subject, m.ID_MEMBER, m.posterName, mem.realName, m.ID_TOPIC, m.ID_BOARD\n        FROM {db_prefix}messages AS m\n            LEFT JOIN {db_prefix}members AS mem ON (m.ID_MEMBER = mem.ID_MEMBER)\n        WHERE m.ID_MSG = {$id_msg}\n        LIMIT 1", array());
    if ($mobdb->num_rows() == 0) {
        outputRPCResult(false, $txt['smf272']);
    }
    $message_info = $mobdb->fetch_assoc();
    global $topic, $board;
    list($subject, $member, $posterName, $realName, $topic, $board) = array($message_info['subject'], $message_info['ID_MEMBER'], $message_info['posterName'], $message_info['realName'], $message_info['ID_TOPIC'], $message_info['ID_BOARD']);
    $mobdb->free_result();
    loadBoard();
    loadPermissions();
    // You can't use this if it's off or you are not allowed to do it.
    if (!allowedTo('report_any')) {
        outputRPCResult(false, $txt['cannot_report_any']);
    }
    spamProtection('spam');
    if ($member == $user_info['id']) {
        outputRPCResult(false, $txt['rtm_not_own']);
    }
    $posterName = un_htmlspecialchars($realName) . ($realName != $posterName ? ' (' . $posterName . ')' : '');
    $reporterName = un_htmlspecialchars($user_info['name']) . ($user_info['name'] != $user_info['username'] && $user_info['username'] != '' ? ' (' . $user_info['username'] . ')' : '');
    $subject = un_htmlspecialchars($subject);
    // Get a list of members with the moderate_board permission.
    require_once $sourcedir . '/Subs-Members.php';
    $moderators = membersAllowedTo('moderate_board', $board);
    $mobdb->query("\n        SELECT ID_MEMBER, emailAddress, lngfile\n        FROM {db_prefix}members\n        WHERE ID_MEMBER IN (" . implode(', ', $moderators) . ")\n            AND notifyTypes != 4\n        ORDER BY lngfile", array());
    // Check that moderators do exist!
    if ($mobdb->num_rows() == 0) {
        outputRPCResult(false, $txt['rtm11']);
    }
    // Send every moderator an email.
    while ($row = $mobdb->fetch_assoc()) {
        loadLanguage('Post', empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile'], false);
        // Send it to the moderator.
        sendmail($row['emailAddress'], $txt['rtm3'] . ': ' . $subject . ' ' . $txt['rtm4'] . ' ' . $posterName, sprintf($txt['rtm_email1'], $subject) . ' ' . $posterName . ' ' . $txt['rtm_email2'] . ' ' . (empty($user_info['id']) ? $txt['guest'] . ' (' . $user_info['ip'] . ')' : $reporterName) . ' ' . $txt['rtm_email3'] . ":\n\n" . $scripturl . '?topic=' . $topic . '.msg' . $id_msg . '#msg' . $id_msg . "\n\n" . $txt['rtm_email_comment'] . ":\n" . $reason . "\n\n" . $txt[130], $user_info['email']);
    }
    $mobdb->free_result();
    outputRPCResult(true);
}
示例#4
0
 /**
  * Send the emails.
  *
  * - Sends off emails to all the moderators.
  * - Sends to administrators and global moderators. (1 and 2)
  * - Called by action_reporttm(), and thus has the same permission and setting requirements as it does.
  * - Accessed through ?action=reporttm when posting.
  */
 public function action_reporttm2()
 {
     global $txt, $scripturl, $topic, $board, $user_info, $modSettings, $language, $context;
     // You must have the proper permissions!
     isAllowedTo('report_any');
     // Make sure they aren't spamming.
     spamProtection('reporttm');
     require_once SUBSDIR . '/Mail.subs.php';
     // No errors, yet.
     $report_errors = Error_Context::context('report', 1);
     // Check their session.
     if (checkSession('post', '', false) != '') {
         $report_errors->addError('session_timeout');
     }
     // Make sure we have a comment and it's clean.
     if (!isset($_POST['comment']) || Util::htmltrim($_POST['comment']) === '') {
         $report_errors->addError('no_comment');
     }
     $poster_comment = strtr(Util::htmlspecialchars($_POST['comment']), array("\r" => '', "\t" => ''));
     if (Util::strlen($poster_comment) > 254) {
         $report_errors->addError('post_too_long');
     }
     // Guests need to provide their address!
     if ($user_info['is_guest']) {
         require_once SUBSDIR . '/DataValidator.class.php';
         if (!Data_Validator::is_valid($_POST, array('email' => 'valid_email'), array('email' => 'trim'))) {
             empty($_POST['email']) ? $report_errors->addError('no_email') : $report_errors->addError('bad_email');
         }
         isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt['guest_title']));
         $user_info['email'] = htmlspecialchars($_POST['email'], ENT_COMPAT, 'UTF-8');
     }
     // Could they get the right verification code?
     if ($user_info['is_guest'] && !empty($modSettings['guests_report_require_captcha'])) {
         require_once SUBSDIR . '/VerificationControls.class.php';
         $verificationOptions = array('id' => 'report');
         $context['require_verification'] = create_control_verification($verificationOptions, true);
         if (is_array($context['require_verification'])) {
             foreach ($context['require_verification'] as $error) {
                 $report_errors->addError($error, 0);
             }
         }
     }
     // Any errors?
     if ($report_errors->hasErrors()) {
         return $this->action_reporttm();
     }
     // Get the basic topic information, and make sure they can see it.
     $msg_id = (int) $_POST['msg'];
     $message = posterDetails($msg_id, $topic);
     if (empty($message)) {
         fatal_lang_error('no_board', false);
     }
     $poster_name = un_htmlspecialchars($message['real_name']) . ($message['real_name'] != $message['poster_name'] ? ' (' . $message['poster_name'] . ')' : '');
     $reporterName = un_htmlspecialchars($user_info['name']) . ($user_info['name'] != $user_info['username'] && $user_info['username'] != '' ? ' (' . $user_info['username'] . ')' : '');
     $subject = un_htmlspecialchars($message['subject']);
     // Get a list of members with the moderate_board permission.
     require_once SUBSDIR . '/Members.subs.php';
     $moderators = membersAllowedTo('moderate_board', $board);
     $result = getBasicMemberData($moderators, array('preferences' => true, 'sort' => 'lngfile'));
     $mod_to_notify = array();
     foreach ($result as $row) {
         if ($row['notify_types'] != 4) {
             $mod_to_notify[] = $row;
         }
     }
     // Check that moderators do exist!
     if (empty($mod_to_notify)) {
         fatal_lang_error('no_mods', false);
     }
     // If we get here, I believe we should make a record of this, for historical significance, yabber.
     if (empty($modSettings['disable_log_report'])) {
         require_once SUBSDIR . '/Messages.subs.php';
         $id_report = recordReport($message, $poster_comment);
         // If we're just going to ignore these, then who gives a monkeys...
         if ($id_report === false) {
             redirectexit('topic=' . $topic . '.msg' . $msg_id . '#msg' . $msg_id);
         }
     }
     // Find out who the real moderators are - for mod preferences.
     require_once SUBSDIR . '/Boards.subs.php';
     $real_mods = getBoardModerators($board, true);
     // Send every moderator an email.
     foreach ($mod_to_notify as $row) {
         // Maybe they don't want to know?!
         if (!empty($row['mod_prefs'])) {
             list(, , $pref_binary) = explode('|', $row['mod_prefs']);
             if (!($pref_binary & 1) && (!($pref_binary & 2) || !in_array($row['id_member'], $real_mods))) {
                 continue;
             }
         }
         $replacements = array('TOPICSUBJECT' => $subject, 'POSTERNAME' => $poster_name, 'REPORTERNAME' => $reporterName, 'TOPICLINK' => $scripturl . '?topic=' . $topic . '.msg' . $msg_id . '#msg' . $msg_id, 'REPORTLINK' => !empty($id_report) ? $scripturl . '?action=moderate;area=reports;report=' . $id_report : '', 'COMMENT' => $_POST['comment']);
         $emaildata = loadEmailTemplate('report_to_moderator', $replacements, empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']);
         // Send it to the moderator.
         sendmail($row['email_address'], $emaildata['subject'], $emaildata['body'], $user_info['email'], null, false, 2);
     }
     // Keep track of when the mod reports get updated, that way we know when we need to look again.
     updateSettings(array('last_mod_report_action' => time()));
     // Back to the post we reported!
     redirectexit('reportsent;topic=' . $topic . '.msg' . $msg_id . '#msg' . $msg_id);
 }
示例#5
0
 /**
  * Shows the contact form for the user to fill out
  * Needs to be enabled to be used
  */
 public function action_contact()
 {
     global $context, $txt, $user_info, $modSettings;
     // Already inside, no need to use this, just send a PM
     // Disabled, you cannot enter.
     if (!$user_info['is_guest'] || empty($modSettings['enable_contactform']) || $modSettings['enable_contactform'] == 'disabled') {
         redirectexit();
     }
     loadLanguage('Login');
     loadTemplate('Register');
     if (isset($_REQUEST['send'])) {
         checkSession('post');
         validateToken('contact');
         spamProtection('contact');
         // No errors, yet.
         $context['errors'] = array();
         loadLanguage('Errors');
         // Could they get the right send topic verification code?
         require_once SUBSDIR . '/VerificationControls.class.php';
         require_once SUBSDIR . '/Members.subs.php';
         // form validation
         require_once SUBSDIR . '/DataValidator.class.php';
         $validator = new Data_Validator();
         $validator->sanitation_rules(array('emailaddress' => 'trim', 'contactmessage' => 'trim|Util::htmlspecialchars'));
         $validator->validation_rules(array('emailaddress' => 'required|valid_email', 'contactmessage' => 'required'));
         $validator->text_replacements(array('emailaddress' => $txt['error_email'], 'contactmessage' => $txt['error_message']));
         // Any form errors
         if (!$validator->validate($_POST)) {
             $context['errors'] = $validator->validation_errors();
         }
         // How about any verification errors
         $verificationOptions = array('id' => 'contactform');
         $context['require_verification'] = create_control_verification($verificationOptions, true);
         if (is_array($context['require_verification'])) {
             foreach ($context['require_verification'] as $error) {
                 $context['errors'][] = $txt['error_' . $error];
             }
         }
         // No errors, then send the PM to the admins
         if (empty($context['errors'])) {
             $admins = admins();
             if (!empty($admins)) {
                 require_once SUBSDIR . '/PersonalMessage.subs.php';
                 sendpm(array('to' => array_keys($admins), 'bcc' => array()), $txt['contact_subject'], $_REQUEST['contactmessage'], false, array('id' => 0, 'name' => $validator->emailaddress, 'username' => $validator->emailaddress));
             }
             // Send the PM
             redirectexit('action=contact;sa=done');
         } else {
             $context['emailaddress'] = $validator->emailaddress;
             $context['contactmessage'] = $validator->contactmessage;
         }
     }
     if (isset($_GET['sa']) && $_GET['sa'] == 'done') {
         $context['sub_template'] = 'contact_form_done';
     } else {
         $context['sub_template'] = 'contact_form';
         $context['page_title'] = $txt['admin_contact_form'];
         require_once SUBSDIR . '/VerificationControls.class.php';
         $verificationOptions = array('id' => 'contactform');
         $context['require_verification'] = create_control_verification($verificationOptions);
         $context['visual_verification_id'] = $verificationOptions['id'];
     }
     createToken('contact');
 }
示例#6
0
/**
 * Send it!
 */
function MessagePost2()
{
    global $txt, $context, $sourcedir;
    global $user_info, $modSettings, $scripturl, $smcFunc;
    isAllowedTo('pm_send');
    require_once $sourcedir . '/Subs-Auth.php';
    loadLanguage('PersonalMessage', '', false);
    // Extract out the spam settings - it saves database space!
    list($modSettings['max_pm_recipients'], $modSettings['pm_posts_verification'], $modSettings['pm_posts_per_hour']) = explode(',', $modSettings['pm_spam_settings']);
    // Initialize the errors we're about to make.
    $post_errors = array();
    // Check whether we've gone over the limit of messages we can send per hour - fatal error if fails!
    if (!empty($modSettings['pm_posts_per_hour']) && !allowedTo(array('admin_forum', 'moderate_forum', 'send_mail')) && $user_info['mod_cache']['bq'] == '0=1' && $user_info['mod_cache']['gq'] == '0=1') {
        // How many have they sent this last hour?
        $request = $smcFunc['db_query']('', '
			SELECT COUNT(pr.id_pm) AS post_count
			FROM {db_prefix}personal_messages AS pm
				INNER JOIN {db_prefix}pm_recipients AS pr ON (pr.id_pm = pm.id_pm)
			WHERE pm.id_member_from = {int:current_member}
				AND pm.msgtime > {int:msgtime}', array('current_member' => $user_info['id'], 'msgtime' => time() - 3600));
        list($postCount) = $smcFunc['db_fetch_row']($request);
        $smcFunc['db_free_result']($request);
        if (!empty($postCount) && $postCount >= $modSettings['pm_posts_per_hour']) {
            if (!isset($_REQUEST['xml'])) {
                fatal_lang_error('pm_too_many_per_hour', true, array($modSettings['pm_posts_per_hour']));
            } else {
                $post_errors[] = 'pm_too_many_per_hour';
            }
        }
    }
    // If your session timed out, show an error, but do allow to re-submit.
    if (!isset($_REQUEST['xml']) && checkSession('post', '', false) != '') {
        $post_errors[] = 'session_timeout';
    }
    $_REQUEST['subject'] = isset($_REQUEST['subject']) ? trim($_REQUEST['subject']) : '';
    $_REQUEST['to'] = empty($_POST['to']) ? empty($_GET['to']) ? '' : $_GET['to'] : $_POST['to'];
    $_REQUEST['bcc'] = empty($_POST['bcc']) ? empty($_GET['bcc']) ? '' : $_GET['bcc'] : $_POST['bcc'];
    // Route the input from the 'u' parameter to the 'to'-list.
    if (!empty($_POST['u'])) {
        $_POST['recipient_to'] = explode(',', $_POST['u']);
    }
    // Construct the list of recipients.
    $recipientList = array();
    $namedRecipientList = array();
    $namesNotFound = array();
    foreach (array('to', 'bcc') as $recipientType) {
        // First, let's see if there's user ID's given.
        $recipientList[$recipientType] = array();
        if (!empty($_POST['recipient_' . $recipientType]) && is_array($_POST['recipient_' . $recipientType])) {
            foreach ($_POST['recipient_' . $recipientType] as $recipient) {
                $recipientList[$recipientType][] = (int) $recipient;
            }
        }
        // Are there also literal names set?
        if (!empty($_REQUEST[$recipientType])) {
            // We're going to take out the "s anyway ;).
            $recipientString = strtr($_REQUEST[$recipientType], array('\\"' => '"'));
            preg_match_all('~"([^"]+)"~', $recipientString, $matches);
            $namedRecipientList[$recipientType] = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $recipientString))));
            foreach ($namedRecipientList[$recipientType] as $index => $recipient) {
                if (strlen(trim($recipient)) > 0) {
                    $namedRecipientList[$recipientType][$index] = $smcFunc['htmlspecialchars']($smcFunc['strtolower'](trim($recipient)));
                } else {
                    unset($namedRecipientList[$recipientType][$index]);
                }
            }
            if (!empty($namedRecipientList[$recipientType])) {
                $foundMembers = findMembers($namedRecipientList[$recipientType]);
                // Assume all are not found, until proven otherwise.
                $namesNotFound[$recipientType] = $namedRecipientList[$recipientType];
                foreach ($foundMembers as $member) {
                    $testNames = array($smcFunc['strtolower']($member['username']), $smcFunc['strtolower']($member['name']), $smcFunc['strtolower']($member['email']));
                    if (count(array_intersect($testNames, $namedRecipientList[$recipientType])) !== 0) {
                        $recipientList[$recipientType][] = $member['id'];
                        // Get rid of this username, since we found it.
                        $namesNotFound[$recipientType] = array_diff($namesNotFound[$recipientType], $testNames);
                    }
                }
            }
        }
        // Selected a recipient to be deleted? Remove them now.
        if (!empty($_POST['delete_recipient'])) {
            $recipientList[$recipientType] = array_diff($recipientList[$recipientType], array((int) $_POST['delete_recipient']));
        }
        // Make sure we don't include the same name twice
        $recipientList[$recipientType] = array_unique($recipientList[$recipientType]);
    }
    // Are we changing the recipients some how?
    $is_recipient_change = !empty($_POST['delete_recipient']) || !empty($_POST['to_submit']) || !empty($_POST['bcc_submit']);
    // Check if there's at least one recipient.
    if (empty($recipientList['to']) && empty($recipientList['bcc'])) {
        $post_errors[] = 'no_to';
    }
    // Make sure that we remove the members who did get it from the screen.
    if (!$is_recipient_change) {
        foreach ($recipientList as $recipientType => $dummy) {
            if (!empty($namesNotFound[$recipientType])) {
                $post_errors[] = 'bad_' . $recipientType;
                // Since we already have a post error, remove the previous one.
                $post_errors = array_diff($post_errors, array('no_to'));
                foreach ($namesNotFound[$recipientType] as $name) {
                    $context['send_log']['failed'][] = sprintf($txt['pm_error_user_not_found'], $name);
                }
            }
        }
    }
    // Did they make any mistakes?
    if ($_REQUEST['subject'] == '') {
        $post_errors[] = 'no_subject';
    }
    if (!isset($_REQUEST['message']) || $_REQUEST['message'] == '') {
        $post_errors[] = 'no_message';
    } elseif (!empty($modSettings['max_messageLength']) && $smcFunc['strlen']($_REQUEST['message']) > $modSettings['max_messageLength']) {
        $post_errors[] = 'long_message';
    } else {
        // Preparse the message.
        $message = $_REQUEST['message'];
        preparsecode($message);
        // Make sure there's still some content left without the tags.
        if ($smcFunc['htmltrim'](strip_tags(parse_bbc($smcFunc['htmlspecialchars']($message, ENT_QUOTES), false), '<img>')) === '' && (!allowedTo('admin_forum') || strpos($message, '[html]') === false)) {
            $post_errors[] = 'no_message';
        }
    }
    // Wrong verification code?
    if (!$user_info['is_admin'] && !isset($_REQUEST['xml']) && !empty($modSettings['pm_posts_verification']) && $user_info['posts'] < $modSettings['pm_posts_verification']) {
        require_once $sourcedir . '/Subs-Editor.php';
        $verificationOptions = array('id' => 'pm');
        $context['require_verification'] = create_control_verification($verificationOptions, true);
        if (is_array($context['require_verification'])) {
            $post_errors = array_merge($post_errors, $context['require_verification']);
        }
    }
    // If they did, give a chance to make ammends.
    if (!empty($post_errors) && !$is_recipient_change && !isset($_REQUEST['preview']) && !isset($_REQUEST['xml'])) {
        return messagePostError($post_errors, $namedRecipientList, $recipientList);
    }
    // Want to take a second glance before you send?
    if (isset($_REQUEST['preview'])) {
        // Set everything up to be displayed.
        $context['preview_subject'] = $smcFunc['htmlspecialchars']($_REQUEST['subject']);
        $context['preview_message'] = $smcFunc['htmlspecialchars']($_REQUEST['message'], ENT_QUOTES);
        preparsecode($context['preview_message'], true);
        // Parse out the BBC if it is enabled.
        $context['preview_message'] = parse_bbc($context['preview_message']);
        // Censor, as always.
        censorText($context['preview_subject']);
        censorText($context['preview_message']);
        // Set a descriptive title.
        $context['page_title'] = $txt['preview'] . ' - ' . $context['preview_subject'];
        // Pretend they messed up but don't ignore if they really did :P.
        return messagePostError($post_errors, $namedRecipientList, $recipientList);
    } elseif ($is_recipient_change) {
        // Maybe we couldn't find one?
        foreach ($namesNotFound as $recipientType => $names) {
            $post_errors[] = 'bad_' . $recipientType;
            foreach ($names as $name) {
                $context['send_log']['failed'][] = sprintf($txt['pm_error_user_not_found'], $name);
            }
        }
        return messagePostError(array(), $namedRecipientList, $recipientList);
    }
    // Want to save this as a draft and think about it some more?
    if (!empty($modSettings['drafts_enabled']) && !empty($modSettings['drafts_pm_enabled']) && isset($_POST['save_draft'])) {
        require_once $sourcedir . '/Drafts.php';
        SavePMDraft($post_errors, $recipientList);
        return messagePostError($post_errors, $namedRecipientList, $recipientList);
    } elseif (!empty($modSettings['max_pm_recipients']) && count($recipientList['to']) + count($recipientList['bcc']) > $modSettings['max_pm_recipients'] && !allowedTo(array('moderate_forum', 'send_mail', 'admin_forum'))) {
        $context['send_log'] = array('sent' => array(), 'failed' => array(sprintf($txt['pm_too_many_recipients'], $modSettings['max_pm_recipients'])));
        return messagePostError($post_errors, $namedRecipientList, $recipientList);
    }
    // Protect from message spamming.
    spamProtection('pm');
    // Prevent double submission of this form.
    checkSubmitOnce('check');
    // Do the actual sending of the PM.
    if (!empty($recipientList['to']) || !empty($recipientList['bcc'])) {
        $context['send_log'] = sendpm($recipientList, $_REQUEST['subject'], $_REQUEST['message'], !empty($_REQUEST['outbox']), null, !empty($_REQUEST['pm_head']) ? (int) $_REQUEST['pm_head'] : 0);
    } else {
        $context['send_log'] = array('sent' => array(), 'failed' => array());
    }
    // Mark the message as "replied to".
    if (!empty($context['send_log']['sent']) && !empty($_REQUEST['replied_to']) && isset($_REQUEST['f']) && $_REQUEST['f'] == 'inbox') {
        $smcFunc['db_query']('', '
			UPDATE {db_prefix}pm_recipients
			SET is_read = is_read | 2
			WHERE id_pm = {int:replied_to}
				AND id_member = {int:current_member}', array('current_member' => $user_info['id'], 'replied_to' => (int) $_REQUEST['replied_to']));
    }
    // If one or more of the recipient were invalid, go back to the post screen with the failed usernames.
    if (!empty($context['send_log']['failed'])) {
        return messagePostError($post_errors, $namesNotFound, array('to' => array_intersect($recipientList['to'], $context['send_log']['failed']), 'bcc' => array_intersect($recipientList['bcc'], $context['send_log']['failed'])));
    }
    // Message sent successfully?
    if (!empty($context['send_log']) && empty($context['send_log']['failed'])) {
        $context['current_label_redirect'] = $context['current_label_redirect'] . ';done=sent';
    }
    // Go back to the where they sent from, if possible...
    redirectexit($context['current_label_redirect']);
}
示例#7
0
function RemindPick()
{
    global $context, $txt, $scripturl, $sourcedir, $user_info, $webmaster_email, $smcFunc, $language, $modSettings;
    checkSession();
    validateToken('remind');
    createToken('remind');
    // Coming with a known ID?
    if (!empty($_REQUEST['uid'])) {
        $where = 'id_member = {int:id_member}';
        $where_params['id_member'] = (int) $_REQUEST['uid'];
    } elseif (isset($_POST['user']) && $_POST['user'] != '') {
        $where = 'member_name = {string:member_name}';
        $where_params['member_name'] = $_POST['user'];
        $where_params['email_address'] = $_POST['user'];
    }
    // You must enter a username/email address.
    if (empty($where)) {
        fatal_lang_error('username_no_exist', false);
    }
    // Make sure we are not being slammed
    spamProtection('remind');
    // Find the user!
    $request = $smcFunc['db_query']('', '
		SELECT id_member, real_name, member_name, email_address, is_activated, validation_code, lngfile, openid_uri, secret_question
		FROM {db_prefix}members
		WHERE ' . $where . '
		LIMIT 1', array_merge($where_params, array()));
    // Maybe email?
    if ($smcFunc['db_num_rows']($request) == 0 && empty($_REQUEST['uid'])) {
        $smcFunc['db_free_result']($request);
        $request = $smcFunc['db_query']('', '
			SELECT id_member, real_name, member_name, email_address, is_activated, validation_code, lngfile, openid_uri, secret_question
			FROM {db_prefix}members
			WHERE email_address = {string:email_address}
			LIMIT 1', array_merge($where_params, array()));
        if ($smcFunc['db_num_rows']($request) == 0) {
            fatal_lang_error('no_user_with_email', false);
        }
    }
    $row = $smcFunc['db_fetch_assoc']($request);
    $smcFunc['db_free_result']($request);
    $context['account_type'] = !empty($row['openid_uri']) ? 'openid' : 'password';
    // If the user isn't activated/approved, give them some feedback on what to do next.
    if ($row['is_activated'] != 1) {
        // Awaiting approval...
        if (trim($row['validation_code']) == '') {
            fatal_error($txt['registration_not_approved'] . ' <a href="' . $scripturl . '?action=activate;user='******'user'] . '">' . $txt['here'] . '</a>.', false);
        } else {
            fatal_error($txt['registration_not_activated'] . ' <a href="' . $scripturl . '?action=activate;user='******'user'] . '">' . $txt['here'] . '</a>.', false);
        }
    }
    // You can't get emailed if you have no email address.
    $row['email_address'] = trim($row['email_address']);
    if ($row['email_address'] == '') {
        fatal_error($txt['no_reminder_email'] . '<br />' . $txt['send_email'] . ' <a href="mailto:' . $webmaster_email . '">webmaster</a> ' . $txt['to_ask_password'] . '.');
    }
    // If they have no secret question then they can only get emailed the item, or they are requesting the email, send them an email.
    if (empty($row['secret_question']) || isset($_POST['reminder_type']) && $_POST['reminder_type'] == 'email') {
        // Randomly generate a new password, with only alpha numeric characters that is a max length of 10 chars.
        require_once $sourcedir . '/Subs-Members.php';
        $password = generateValidationCode();
        require_once $sourcedir . '/Subs-Post.php';
        $replacements = array('REALNAME' => $row['real_name'], 'REMINDLINK' => $scripturl . '?action=reminder;sa=setpassword;u=' . $row['id_member'] . ';code=' . $password, 'IP' => $user_info['ip'], 'MEMBERNAME' => $row['member_name'], 'OPENID' => $row['openid_uri']);
        $emaildata = loadEmailTemplate('forgot_' . $context['account_type'], $replacements, empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']);
        $context['description'] = $txt['reminder_' . (!empty($row['openid_uri']) ? 'openid_' : '') . 'sent'];
        // If they were using OpenID simply email them their OpenID identity.
        sendmail($row['email_address'], $emaildata['subject'], $emaildata['body'], null, null, false, 1);
        if (empty($row['openid_uri'])) {
            // Set the password in the database.
            updateMemberData($row['id_member'], array('validation_code' => substr(md5($password), 0, 10)));
        }
        // Set up the template.
        $context['sub_template'] = 'sent';
        // Dont really.
        return;
    } elseif (isset($_POST['reminder_type']) && $_POST['reminder_type'] == 'secret') {
        return SecretAnswerInput();
    }
    // No we're here setup the context for template number 2!
    $context['sub_template'] = 'reminder_pick';
    $context['current_member'] = array('id' => $row['id_member'], 'name' => $row['member_name']);
}
示例#8
0
function Post2()
{
    global $board, $topic, $txt, $modSettings, $sourcedir, $context;
    global $user_info, $board_info, $options, $smcFunc;
    // Sneaking off, are we?
    if (empty($_POST) && empty($topic)) {
        redirectexit('action=post;board=' . $board . '.0');
    } elseif (empty($_POST) && !empty($topic)) {
        redirectexit('action=post;topic=' . $topic . '.0');
    }
    // No need!
    $context['robot_no_index'] = true;
    // If we came from WYSIWYG then turn it back into BBC regardless.
    if (!empty($_REQUEST['message_mode']) && isset($_REQUEST['message'])) {
        require_once $sourcedir . '/Subs-Editor.php';
        $_REQUEST['message'] = html_to_bbc($_REQUEST['message']);
        // We need to unhtml it now as it gets done shortly.
        $_REQUEST['message'] = un_htmlspecialchars($_REQUEST['message']);
        // We need this for everything else.
        $_POST['message'] = $_REQUEST['message'];
    }
    // Previewing? Go back to start.
    if (isset($_REQUEST['preview'])) {
        return Post();
    }
    // Prevent double submission of this form.
    checkSubmitOnce('check');
    // No errors as yet.
    $post_errors = array();
    // If the session has timed out, let the user re-submit their form.
    if (checkSession('post', '', false) != '') {
        $post_errors[] = 'session_timeout';
    }
    // Wrong verification code?
    if (!$user_info['is_admin'] && !$user_info['is_mod'] && !empty($modSettings['posts_require_captcha']) && ($user_info['posts'] < $modSettings['posts_require_captcha'] || $user_info['is_guest'] && $modSettings['posts_require_captcha'] == -1)) {
        require_once $sourcedir . '/Subs-Editor.php';
        $verificationOptions = array('id' => 'post');
        $context['require_verification'] = create_control_verification($verificationOptions, true);
        if (is_array($context['require_verification'])) {
            $post_errors = array_merge($post_errors, $context['require_verification']);
        }
    }
    require_once $sourcedir . '/Subs-Post.php';
    loadLanguage('Post');
    // If this isn't a new topic load the topic info that we need.
    if (!empty($topic)) {
        $request = $smcFunc['db_query']('', '
			SELECT locked, is_sticky, id_poll, approved, id_first_msg, id_last_msg, id_member_started, id_board
			FROM {db_prefix}topics
			WHERE id_topic = {int:current_topic}
			LIMIT 1', array('current_topic' => $topic));
        $topic_info = $smcFunc['db_fetch_assoc']($request);
        $smcFunc['db_free_result']($request);
        // Though the topic should be there, it might have vanished.
        if (!is_array($topic_info)) {
            fatal_lang_error('topic_doesnt_exist');
        }
        // Did this topic suddenly move? Just checking...
        if ($topic_info['id_board'] != $board) {
            fatal_lang_error('not_a_topic');
        }
    }
    // Replying to a topic?
    if (!empty($topic) && !isset($_REQUEST['msg'])) {
        // Don't allow a post if it's locked.
        if ($topic_info['locked'] != 0 && !allowedTo('moderate_board')) {
            fatal_lang_error('topic_locked', false);
        }
        // Sorry, multiple polls aren't allowed... yet.  You should stop giving me ideas :P.
        if (isset($_REQUEST['poll']) && $topic_info['id_poll'] > 0) {
            unset($_REQUEST['poll']);
        }
        // Do the permissions and approval stuff...
        $becomesApproved = true;
        if ($topic_info['id_member_started'] != $user_info['id']) {
            if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_any') && !allowedTo('post_reply_any')) {
                $becomesApproved = false;
            } else {
                isAllowedTo('post_reply_any');
            }
        } elseif (!allowedTo('post_reply_any')) {
            if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_own') && !allowedTo('post_reply_own')) {
                $becomesApproved = false;
            } else {
                isAllowedTo('post_reply_own');
            }
        }
        if (isset($_POST['lock'])) {
            // Nothing is changed to the lock.
            if (empty($topic_info['locked']) && empty($_POST['lock']) || !empty($_POST['lock']) && !empty($topic_info['locked'])) {
                unset($_POST['lock']);
            } elseif (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']) {
                unset($_POST['lock']);
            } elseif (!allowedTo('lock_any')) {
                // You cannot override a moderator lock.
                if ($topic_info['locked'] == 1) {
                    unset($_POST['lock']);
                } else {
                    $_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
                }
            } else {
                $_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
            }
        }
        // So you wanna (un)sticky this...let's see.
        if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || $_POST['sticky'] == $topic_info['is_sticky'] || !allowedTo('make_sticky'))) {
            unset($_POST['sticky']);
        }
        // If the number of replies has changed, if the setting is enabled, go back to Post() - which handles the error.
        if (empty($options['no_new_reply_warning']) && isset($_POST['last_msg']) && $topic_info['id_last_msg'] > $_POST['last_msg']) {
            $_REQUEST['preview'] = true;
            return Post();
        }
        $posterIsGuest = $user_info['is_guest'];
    } elseif (empty($topic)) {
        // Now don't be silly, new topics will get their own id_msg soon enough.
        unset($_REQUEST['msg'], $_POST['msg'], $_GET['msg']);
        // Do like, the permissions, for safety and stuff...
        $becomesApproved = true;
        if ($modSettings['postmod_active'] && !allowedTo('post_new') && allowedTo('post_unapproved_topics')) {
            $becomesApproved = false;
        } else {
            isAllowedTo('post_new');
        }
        if (isset($_POST['lock'])) {
            // New topics are by default not locked.
            if (empty($_POST['lock'])) {
                unset($_POST['lock']);
            } elseif (!allowedTo(array('lock_any', 'lock_own'))) {
                unset($_POST['lock']);
            } else {
                $_POST['lock'] = allowedTo('lock_any') ? 1 : 2;
            }
        }
        if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || empty($_POST['sticky']) || !allowedTo('make_sticky'))) {
            unset($_POST['sticky']);
        }
        $posterIsGuest = $user_info['is_guest'];
    } elseif (isset($_REQUEST['msg']) && !empty($topic)) {
        $_REQUEST['msg'] = (int) $_REQUEST['msg'];
        $request = $smcFunc['db_query']('', '
			SELECT id_member, poster_name, poster_email, poster_time, approved
			FROM {db_prefix}messages
			WHERE id_msg = {int:id_msg}
			LIMIT 1', array('id_msg' => $_REQUEST['msg']));
        if ($smcFunc['db_num_rows']($request) == 0) {
            fatal_lang_error('cant_find_messages', false);
        }
        $row = $smcFunc['db_fetch_assoc']($request);
        $smcFunc['db_free_result']($request);
        if (!empty($topic_info['locked']) && !allowedTo('moderate_board')) {
            fatal_lang_error('topic_locked', false);
        }
        if (isset($_POST['lock'])) {
            // Nothing changes to the lock status.
            if (empty($_POST['lock']) && empty($topic_info['locked']) || !empty($_POST['lock']) && !empty($topic_info['locked'])) {
                unset($_POST['lock']);
            } elseif (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']) {
                unset($_POST['lock']);
            } elseif (!allowedTo('lock_any')) {
                // You're not allowed to break a moderator's lock.
                if ($topic_info['locked'] == 1) {
                    unset($_POST['lock']);
                } else {
                    $_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
                }
            } else {
                $_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
            }
        }
        // Change the sticky status of this topic?
        if (isset($_POST['sticky']) && (!allowedTo('make_sticky') || $_POST['sticky'] == $topic_info['is_sticky'])) {
            unset($_POST['sticky']);
        }
        if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any')) {
            if ((!$modSettings['postmod_active'] || $row['approved']) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time()) {
                fatal_lang_error('modify_post_time_passed', false);
            } elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_own')) {
                isAllowedTo('modify_replies');
            } else {
                isAllowedTo('modify_own');
            }
        } elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_any')) {
            isAllowedTo('modify_replies');
            // If you're modifying a reply, I say it better be logged...
            $moderationAction = true;
        } else {
            isAllowedTo('modify_any');
            // Log it, assuming you're not modifying your own post.
            if ($row['id_member'] != $user_info['id']) {
                $moderationAction = true;
            }
        }
        $posterIsGuest = empty($row['id_member']);
        // Can they approve it?
        $can_approve = allowedTo('approve_posts');
        $becomesApproved = $modSettings['postmod_active'] ? $can_approve && !$row['approved'] ? !empty($_REQUEST['approve']) ? 1 : 0 : $row['approved'] : 1;
        $approve_has_changed = $row['approved'] != $becomesApproved;
        if (!allowedTo('moderate_forum') || !$posterIsGuest) {
            $_POST['guestname'] = $row['poster_name'];
            $_POST['email'] = $row['poster_email'];
        }
    }
    // If the poster is a guest evaluate the legality of name and email.
    if ($posterIsGuest) {
        $_POST['guestname'] = !isset($_POST['guestname']) ? '' : trim($_POST['guestname']);
        $_POST['email'] = !isset($_POST['email']) ? '' : trim($_POST['email']);
        if ($_POST['guestname'] == '' || $_POST['guestname'] == '_') {
            $post_errors[] = 'no_name';
        }
        if ($smcFunc['strlen']($_POST['guestname']) > 25) {
            $post_errors[] = 'long_name';
        }
        if (empty($modSettings['guest_post_no_email'])) {
            // Only check if they changed it!
            if (!isset($row) || $row['poster_email'] != $_POST['email']) {
                if (!allowedTo('moderate_forum') && (!isset($_POST['email']) || $_POST['email'] == '')) {
                    $post_errors[] = 'no_email';
                }
                if (!allowedTo('moderate_forum') && preg_match('~^[0-9A-Za-z=_+\\-/][0-9A-Za-z=_\'+\\-/\\.]*@[\\w\\-]+(\\.[\\w\\-]+)*(\\.[\\w]{2,6})$~', $_POST['email']) == 0) {
                    $post_errors[] = 'bad_email';
                }
            }
            // Now make sure this email address is not banned from posting.
            isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt['guest_title']));
        }
        // In case they are making multiple posts this visit, help them along by storing their name.
        if (empty($post_errors)) {
            $_SESSION['guest_name'] = $_POST['guestname'];
            $_SESSION['guest_email'] = $_POST['email'];
        }
    }
    // Check the subject and message.
    if (!isset($_POST['subject']) || $smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['subject'])) === '') {
        $post_errors[] = 'no_subject';
    }
    if (!isset($_POST['message']) || $smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['message']), ENT_QUOTES) === '') {
        $post_errors[] = 'no_message';
    } elseif (!empty($modSettings['max_messageLength']) && $smcFunc['strlen']($_POST['message']) > $modSettings['max_messageLength']) {
        $post_errors[] = 'long_message';
    } else {
        // Prepare the message a bit for some additional testing.
        $_POST['message'] = $smcFunc['htmlspecialchars']($_POST['message'], ENT_QUOTES);
        // Preparse code. (Zef)
        if ($user_info['is_guest']) {
            $user_info['name'] = $_POST['guestname'];
        }
        preparsecode($_POST['message']);
        // Let's see if there's still some content left without the tags.
        if ($smcFunc['htmltrim'](strip_tags(parse_bbc($_POST['message'], false), '<img>')) === '' && (!allowedTo('admin_forum') || strpos($_POST['message'], '[html]') === false)) {
            $post_errors[] = 'no_message';
        }
    }
    if (isset($_POST['calendar']) && !isset($_REQUEST['deleteevent']) && $smcFunc['htmltrim']($_POST['evtitle']) === '') {
        $post_errors[] = 'no_event';
    }
    // You are not!
    if (isset($_POST['message']) && strtolower($_POST['message']) == 'i am the administrator.' && !$user_info['is_admin']) {
        fatal_error('Knave! Masquerader! Charlatan!', false);
    }
    // Validate the poll...
    if (isset($_REQUEST['poll']) && $modSettings['pollMode'] == '1') {
        if (!empty($topic) && !isset($_REQUEST['msg'])) {
            fatal_lang_error('no_access', false);
        }
        // This is a new topic... so it's a new poll.
        if (empty($topic)) {
            isAllowedTo('poll_post');
        } elseif ($user_info['id'] == $topic_info['id_member_started'] && !allowedTo('poll_add_any')) {
            isAllowedTo('poll_add_own');
        } else {
            isAllowedTo('poll_add_any');
        }
        if (!isset($_POST['question']) || trim($_POST['question']) == '') {
            $post_errors[] = 'no_question';
        }
        $_POST['options'] = empty($_POST['options']) ? array() : htmltrim__recursive($_POST['options']);
        // Get rid of empty ones.
        foreach ($_POST['options'] as $k => $option) {
            if ($option == '') {
                unset($_POST['options'][$k], $_POST['options'][$k]);
            }
        }
        // What are you going to vote between with one choice?!?
        if (count($_POST['options']) < 2) {
            $post_errors[] = 'poll_few';
        }
    }
    if ($posterIsGuest) {
        // If user is a guest, make sure the chosen name isn't taken.
        require_once $sourcedir . '/Subs-Members.php';
        if (isReservedName($_POST['guestname'], 0, true, false) && (!isset($row['poster_name']) || $_POST['guestname'] != $row['poster_name'])) {
            $post_errors[] = 'bad_name';
        }
    } elseif (!isset($_REQUEST['msg'])) {
        $_POST['guestname'] = $user_info['username'];
        $_POST['email'] = $user_info['email'];
    }
    // Any mistakes?
    if (!empty($post_errors)) {
        loadLanguage('Errors');
        // Previewing.
        $_REQUEST['preview'] = true;
        $context['post_error'] = array('messages' => array());
        foreach ($post_errors as $post_error) {
            $context['post_error'][$post_error] = true;
            if ($post_error == 'long_message') {
                $txt['error_' . $post_error] = sprintf($txt['error_' . $post_error], $modSettings['max_messageLength']);
            }
            $context['post_error']['messages'][] = $txt['error_' . $post_error];
        }
        return Post();
    }
    // Make sure the user isn't spamming the board.
    if (!isset($_REQUEST['msg'])) {
        spamProtection('post');
    }
    // At about this point, we're posting and that's that.
    ignore_user_abort(true);
    @set_time_limit(300);
    // Add special html entities to the subject, name, and email.
    $_POST['subject'] = strtr($smcFunc['htmlspecialchars']($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
    $_POST['guestname'] = htmlspecialchars($_POST['guestname']);
    $_POST['email'] = htmlspecialchars($_POST['email']);
    // At this point, we want to make sure the subject isn't too long.
    if ($smcFunc['strlen']($_POST['subject']) > 100) {
        $_POST['subject'] = $smcFunc['substr']($_POST['subject'], 0, 100);
    }
    // Make the poll...
    if (isset($_REQUEST['poll'])) {
        // Make sure that the user has not entered a ridiculous number of options..
        if (empty($_POST['poll_max_votes']) || $_POST['poll_max_votes'] <= 0) {
            $_POST['poll_max_votes'] = 1;
        } elseif ($_POST['poll_max_votes'] > count($_POST['options'])) {
            $_POST['poll_max_votes'] = count($_POST['options']);
        } else {
            $_POST['poll_max_votes'] = (int) $_POST['poll_max_votes'];
        }
        $_POST['poll_expire'] = (int) $_POST['poll_expire'];
        $_POST['poll_expire'] = $_POST['poll_expire'] > 9999 ? 9999 : ($_POST['poll_expire'] < 0 ? 0 : $_POST['poll_expire']);
        // Just set it to zero if it's not there..
        if (!isset($_POST['poll_hide'])) {
            $_POST['poll_hide'] = 0;
        } else {
            $_POST['poll_hide'] = (int) $_POST['poll_hide'];
        }
        $_POST['poll_change_vote'] = isset($_POST['poll_change_vote']) ? 1 : 0;
        $_POST['poll_guest_vote'] = isset($_POST['poll_guest_vote']) ? 1 : 0;
        // Make sure guests are actually allowed to vote generally.
        if ($_POST['poll_guest_vote']) {
            require_once $sourcedir . '/Subs-Members.php';
            $allowedVoteGroups = groupsAllowedTo('poll_vote', $board);
            if (!in_array(-1, $allowedVoteGroups['allowed'])) {
                $_POST['poll_guest_vote'] = 0;
            }
        }
        // If the user tries to set the poll too far in advance, don't let them.
        if (!empty($_POST['poll_expire']) && $_POST['poll_expire'] < 1) {
            fatal_lang_error('poll_range_error', false);
        } elseif (empty($_POST['poll_expire']) && $_POST['poll_hide'] == 2) {
            $_POST['poll_hide'] = 1;
        }
        // Clean up the question and answers.
        $_POST['question'] = htmlspecialchars($_POST['question']);
        $_POST['question'] = $smcFunc['truncate']($_POST['question'], 255);
        $_POST['question'] = preg_replace('~&amp;#(\\d{4,5}|[2-9]\\d{2,4}|1[2-9]\\d);~', '&#$1;', $_POST['question']);
        $_POST['options'] = htmlspecialchars__recursive($_POST['options']);
    }
    // Check if they are trying to delete any current attachments....
    if (isset($_REQUEST['msg'], $_POST['attach_del']) && (allowedTo('post_attachment') || $modSettings['postmod_active'] && allowedTo('post_unapproved_attachments'))) {
        $del_temp = array();
        foreach ($_POST['attach_del'] as $i => $dummy) {
            $del_temp[$i] = (int) $dummy;
        }
        require_once $sourcedir . '/ManageAttachments.php';
        $attachmentQuery = array('attachment_type' => 0, 'id_msg' => (int) $_REQUEST['msg'], 'not_id_attach' => $del_temp);
        removeAttachments($attachmentQuery);
    }
    // ...or attach a new file...
    if (isset($_FILES['attachment']['name']) || !empty($_SESSION['temp_attachments']) && empty($_POST['from_qr'])) {
        // Verify they can post them!
        if (!$modSettings['postmod_active'] || !allowedTo('post_unapproved_attachments')) {
            isAllowedTo('post_attachment');
        }
        // Make sure we're uploading to the right place.
        if (!empty($modSettings['currentAttachmentUploadDir'])) {
            if (!is_array($modSettings['attachmentUploadDir'])) {
                $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']);
            }
            // The current directory, of course!
            $current_attach_dir = $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']];
        } else {
            $current_attach_dir = $modSettings['attachmentUploadDir'];
        }
        // If this isn't a new post, check the current attachments.
        if (isset($_REQUEST['msg'])) {
            $request = $smcFunc['db_query']('', '
				SELECT COUNT(*), SUM(size)
				FROM {db_prefix}attachments
				WHERE id_msg = {int:id_msg}
					AND attachment_type = {int:attachment_type}', array('id_msg' => (int) $_REQUEST['msg'], 'attachment_type' => 0));
            list($quantity, $total_size) = $smcFunc['db_fetch_row']($request);
            $smcFunc['db_free_result']($request);
        } else {
            $quantity = 0;
            $total_size = 0;
        }
        if (!empty($_SESSION['temp_attachments'])) {
            foreach ($_SESSION['temp_attachments'] as $attachID => $name) {
                if (preg_match('~^post_tmp_' . $user_info['id'] . '_\\d+$~', $attachID) == 0) {
                    continue;
                }
                if (!empty($_POST['attach_del']) && !in_array($attachID, $_POST['attach_del'])) {
                    unset($_SESSION['temp_attachments'][$attachID]);
                    @unlink($current_attach_dir . '/' . $attachID);
                    continue;
                }
                $_FILES['attachment']['tmp_name'][] = $attachID;
                $_FILES['attachment']['name'][] = $name;
                $_FILES['attachment']['size'][] = filesize($current_attach_dir . '/' . $attachID);
                list($_FILES['attachment']['width'][], $_FILES['attachment']['height'][]) = @getimagesize($current_attach_dir . '/' . $attachID);
                unset($_SESSION['temp_attachments'][$attachID]);
            }
        }
        if (!isset($_FILES['attachment']['name'])) {
            $_FILES['attachment']['tmp_name'] = array();
        }
        $attachIDs = array();
        foreach ($_FILES['attachment']['tmp_name'] as $n => $dummy) {
            if ($_FILES['attachment']['name'][$n] == '') {
                continue;
            }
            // Have we reached the maximum number of files we are allowed?
            $quantity++;
            if (!empty($modSettings['attachmentNumPerPostLimit']) && $quantity > $modSettings['attachmentNumPerPostLimit']) {
                checkSubmitOnce('free');
                fatal_lang_error('attachments_limit_per_post', false, array($modSettings['attachmentNumPerPostLimit']));
            }
            // Check the total upload size for this post...
            $total_size += $_FILES['attachment']['size'][$n];
            if (!empty($modSettings['attachmentPostLimit']) && $total_size > $modSettings['attachmentPostLimit'] * 1024) {
                checkSubmitOnce('free');
                fatal_lang_error('file_too_big', false, array($modSettings['attachmentPostLimit']));
            }
            $attachmentOptions = array('post' => isset($_REQUEST['msg']) ? $_REQUEST['msg'] : 0, 'poster' => $user_info['id'], 'name' => $_FILES['attachment']['name'][$n], 'tmp_name' => $_FILES['attachment']['tmp_name'][$n], 'size' => $_FILES['attachment']['size'][$n], 'approved' => !$modSettings['postmod_active'] || allowedTo('post_attachment'));
            if (createAttachment($attachmentOptions)) {
                $attachIDs[] = $attachmentOptions['id'];
                if (!empty($attachmentOptions['thumb'])) {
                    $attachIDs[] = $attachmentOptions['thumb'];
                }
            } else {
                if (in_array('could_not_upload', $attachmentOptions['errors'])) {
                    checkSubmitOnce('free');
                    fatal_lang_error('attach_timeout', 'critical');
                }
                if (in_array('too_large', $attachmentOptions['errors'])) {
                    checkSubmitOnce('free');
                    fatal_lang_error('file_too_big', false, array($modSettings['attachmentSizeLimit']));
                }
                if (in_array('bad_extension', $attachmentOptions['errors'])) {
                    checkSubmitOnce('free');
                    fatal_error($attachmentOptions['name'] . '.<br />' . $txt['cant_upload_type'] . ' ' . $modSettings['attachmentExtensions'] . '.', false);
                }
                if (in_array('directory_full', $attachmentOptions['errors'])) {
                    checkSubmitOnce('free');
                    fatal_lang_error('ran_out_of_space', 'critical');
                }
                if (in_array('bad_filename', $attachmentOptions['errors'])) {
                    checkSubmitOnce('free');
                    fatal_error(basename($attachmentOptions['name']) . '.<br />' . $txt['restricted_filename'] . '.', 'critical');
                }
                if (in_array('taken_filename', $attachmentOptions['errors'])) {
                    checkSubmitOnce('free');
                    fatal_lang_error('filename_exists');
                }
                if (in_array('bad_attachment', $attachmentOptions['errors'])) {
                    checkSubmitOnce('free');
                    fatal_lang_error('bad_attachment');
                }
            }
        }
    }
    // Make the poll...
    if (isset($_REQUEST['poll'])) {
        // Create the poll.
        $smcFunc['db_insert']('', '{db_prefix}polls', array('question' => 'string-255', 'hide_results' => 'int', 'max_votes' => 'int', 'expire_time' => 'int', 'id_member' => 'int', 'poster_name' => 'string-255', 'change_vote' => 'int', 'guest_vote' => 'int'), array($_POST['question'], $_POST['poll_hide'], $_POST['poll_max_votes'], empty($_POST['poll_expire']) ? 0 : time() + $_POST['poll_expire'] * 3600 * 24, $user_info['id'], $_POST['guestname'], $_POST['poll_change_vote'], $_POST['poll_guest_vote']), array('id_poll'));
        $id_poll = $smcFunc['db_insert_id']('{db_prefix}polls', 'id_poll');
        // Create each answer choice.
        $i = 0;
        $pollOptions = array();
        foreach ($_POST['options'] as $option) {
            $pollOptions[] = array($id_poll, $i, $option);
            $i++;
        }
        $smcFunc['db_insert']('insert', '{db_prefix}poll_choices', array('id_poll' => 'int', 'id_choice' => 'int', 'label' => 'string-255'), $pollOptions, array('id_poll', 'id_choice'));
    } else {
        $id_poll = 0;
    }
    // Creating a new topic?
    $newTopic = empty($_REQUEST['msg']) && empty($topic);
    $_POST['icon'] = !empty($attachIDs) && $_POST['icon'] == 'xx' ? 'clip' : $_POST['icon'];
    // Collect all parameters for the creation or modification of a post.
    $msgOptions = array('id' => empty($_REQUEST['msg']) ? 0 : (int) $_REQUEST['msg'], 'subject' => $_POST['subject'], 'body' => $_POST['message'], 'icon' => preg_replace('~[\\./\\\\*:"\'<>]~', '', $_POST['icon']), 'smileys_enabled' => !isset($_POST['ns']), 'attachments' => empty($attachIDs) ? array() : $attachIDs, 'approved' => $becomesApproved);
    $topicOptions = array('id' => empty($topic) ? 0 : $topic, 'board' => $board, 'poll' => isset($_REQUEST['poll']) ? $id_poll : null, 'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null, 'sticky_mode' => isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics']) ? (int) $_POST['sticky'] : null, 'mark_as_read' => true, 'is_approved' => !$modSettings['postmod_active'] || empty($topic) || !empty($board_info['cur_topic_approved']));
    $posterOptions = array('id' => $user_info['id'], 'name' => $_POST['guestname'], 'email' => $_POST['email'], 'update_post_count' => !$user_info['is_guest'] && !isset($_REQUEST['msg']) && $board_info['posts_count']);
    // This is an already existing message. Edit it.
    if (!empty($_REQUEST['msg'])) {
        // Have admins allowed people to hide their screwups?
        if (time() - $row['poster_time'] > $modSettings['edit_wait_time'] || $user_info['id'] != $row['id_member']) {
            $msgOptions['modify_time'] = time();
            $msgOptions['modify_name'] = $user_info['name'];
        }
        // This will save some time...
        if (empty($approve_has_changed)) {
            unset($msgOptions['approved']);
        }
        modifyPost($msgOptions, $topicOptions, $posterOptions);
    } else {
        createPost($msgOptions, $topicOptions, $posterOptions);
        if (isset($topicOptions['id'])) {
            $topic = $topicOptions['id'];
        }
    }
    // Editing or posting an event?
    if (isset($_POST['calendar']) && (!isset($_REQUEST['eventid']) || $_REQUEST['eventid'] == -1)) {
        require_once $sourcedir . '/Subs-Calendar.php';
        // Make sure they can link an event to this post.
        canLinkEvent();
        // Insert the event.
        $eventOptions = array('board' => $board, 'topic' => $topic, 'title' => $_POST['evtitle'], 'member' => $user_info['id'], 'start_date' => sprintf('%04d-%02d-%02d', $_POST['year'], $_POST['month'], $_POST['day']), 'span' => isset($_POST['span']) && $_POST['span'] > 0 ? min((int) $modSettings['cal_maxspan'], (int) $_POST['span'] - 1) : 0);
        insertEvent($eventOptions);
    } elseif (isset($_POST['calendar'])) {
        $_REQUEST['eventid'] = (int) $_REQUEST['eventid'];
        // Validate the post...
        require_once $sourcedir . '/Subs-Calendar.php';
        validateEventPost();
        // If you're not allowed to edit any events, you have to be the poster.
        if (!allowedTo('calendar_edit_any')) {
            // Get the event's poster.
            $request = $smcFunc['db_query']('', '
				SELECT id_member
				FROM {db_prefix}calendar
				WHERE id_event = {int:id_event}', array('id_event' => $_REQUEST['eventid']));
            $row2 = $smcFunc['db_fetch_assoc']($request);
            $smcFunc['db_free_result']($request);
            // Silly hacker, Trix are for kids. ...probably trademarked somewhere, this is FAIR USE! (parody...)
            isAllowedTo('calendar_edit_' . ($row2['id_member'] == $user_info['id'] ? 'own' : 'any'));
        }
        // Delete it?
        if (isset($_REQUEST['deleteevent'])) {
            $smcFunc['db_query']('', '
				DELETE FROM {db_prefix}calendar
				WHERE id_event = {int:id_event}', array('id_event' => $_REQUEST['eventid']));
        } else {
            $span = !empty($modSettings['cal_allowspan']) && !empty($_REQUEST['span']) ? min((int) $modSettings['cal_maxspan'], (int) $_REQUEST['span'] - 1) : 0;
            $start_time = mktime(0, 0, 0, (int) $_REQUEST['month'], (int) $_REQUEST['day'], (int) $_REQUEST['year']);
            $smcFunc['db_query']('', '
				UPDATE {db_prefix}calendar
				SET end_date = {date:end_date},
					start_date = {date:start_date},
					title = {string:title}
				WHERE id_event = {int:id_event}', array('end_date' => strftime('%Y-%m-%d', $start_time + $span * 86400), 'start_date' => strftime('%Y-%m-%d', $start_time), 'id_event' => $_REQUEST['eventid'], 'title' => $smcFunc['htmlspecialchars']($_REQUEST['evtitle'], ENT_QUOTES)));
        }
        updateSettings(array('calendar_updated' => time()));
    }
    // Marking read should be done even for editing messages....
    // Mark all the parents read.  (since you just posted and they will be unread.)
    if (!$user_info['is_guest'] && !empty($board_info['parent_boards'])) {
        $smcFunc['db_query']('', '
			UPDATE {db_prefix}log_boards
			SET id_msg = {int:id_msg}
			WHERE id_member = {int:current_member}
				AND id_board IN ({array_int:board_list})', array('current_member' => $user_info['id'], 'board_list' => array_keys($board_info['parent_boards']), 'id_msg' => $modSettings['maxMsgID']));
    }
    // Turn notification on or off.  (note this just blows smoke if it's already on or off.)
    if (!empty($_POST['notify']) && allowedTo('mark_any_notify')) {
        $smcFunc['db_insert']('ignore', '{db_prefix}log_notify', array('id_member' => 'int', 'id_topic' => 'int', 'id_board' => 'int'), array($user_info['id'], $topic, 0), array('id_member', 'id_topic', 'id_board'));
    } elseif (!$newTopic) {
        $smcFunc['db_query']('', '
			DELETE FROM {db_prefix}log_notify
			WHERE id_member = {int:current_member}
				AND id_topic = {int:current_topic}', array('current_member' => $user_info['id'], 'current_topic' => $topic));
    }
    // Log an act of moderation - modifying.
    if (!empty($moderationAction)) {
        logAction('modify', array('topic' => $topic, 'message' => (int) $_REQUEST['msg'], 'member' => $row['id_member'], 'board' => $board));
    }
    if (isset($_POST['lock']) && $_POST['lock'] != 2) {
        logAction('lock', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board']));
    }
    if (isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics'])) {
        logAction('sticky', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board']));
    }
    // Notify any members who have notification turned on for this topic - only do this if it's going to be approved(!)
    if ($becomesApproved) {
        if ($newTopic) {
            $notifyData = array('body' => $_POST['message'], 'subject' => $_POST['subject'], 'name' => $user_info['name'], 'poster' => $user_info['id'], 'msg' => $msgOptions['id'], 'board' => $board, 'topic' => $topic);
            notifyMembersBoard($notifyData);
        } elseif (empty($_REQUEST['msg'])) {
            // Only send it to everyone if the topic is approved, otherwise just to the topic starter if they want it.
            if ($topic_info['approved']) {
                sendNotifications($topic, 'reply');
            } else {
                sendNotifications($topic, 'reply', array(), $topic_info['id_member_started']);
            }
        }
    }
    // Returning to the topic?
    if (!empty($_REQUEST['goback'])) {
        // Mark the board as read.... because it might get confusing otherwise.
        $smcFunc['db_query']('', '
			UPDATE {db_prefix}log_boards
			SET id_msg = {int:maxMsgID}
			WHERE id_member = {int:current_member}
				AND id_board = {int:current_board}', array('current_board' => $board, 'current_member' => $user_info['id'], 'maxMsgID' => $modSettings['maxMsgID']));
    }
    if ($board_info['num_topics'] == 0) {
        cache_put_data('board-' . $board, null, 120);
    }
    if (!empty($_POST['announce_topic'])) {
        redirectexit('action=announce;sa=selectgroup;topic=' . $topic . (!empty($_POST['move']) && allowedTo('move_any') ? ';move' : '') . (empty($_REQUEST['goback']) ? '' : ';goback'));
    }
    if (!empty($_POST['move']) && allowedTo('move_any')) {
        redirectexit('action=movetopic;topic=' . $topic . '.0' . (empty($_REQUEST['goback']) ? '' : ';goback'));
    }
    // Return to post if the mod is on.
    if (isset($_REQUEST['msg']) && !empty($_REQUEST['goback'])) {
        redirectexit('topic=' . $topic . '.msg' . $_REQUEST['msg'] . '#msg' . $_REQUEST['msg'], $context['browser']['is_ie']);
    } elseif (!empty($_REQUEST['goback'])) {
        redirectexit('topic=' . $topic . '.new#new', $context['browser']['is_ie']);
    } else {
        redirectexit('board=' . $board . '.0');
    }
}
function Register2($verifiedOpenID = false)
{
    global $scripturl, $txt, $modSettings, $context, $sourcedir;
    global $user_info, $options, $settings, $smcFunc;
    // Start collecting together any errors.
    $reg_errors = array();
    // Did we save some open ID fields?
    if ($verifiedOpenID && !empty($context['openid_save_fields'])) {
        foreach ($context['openid_save_fields'] as $id => $value) {
            $_POST[$id] = $value;
        }
    }
    // You can't register if it's disabled.
    if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 3) {
        fatal_lang_error('registration_disabled', false);
    }
    // Things we don't do for people who have already confirmed their OpenID allegances via register.
    if (!$verifiedOpenID) {
        // Well, if you don't agree, you can't register.
        if (!empty($modSettings['requireAgreement']) && empty($_SESSION['registration_agreed'])) {
            redirectexit();
        }
        // Make sure they came from *somewhere*, have a session.
        if (!isset($_SESSION['old_url'])) {
            redirectexit('action=register');
        }
        // Are they under age, and under age users are banned?
        if (!empty($modSettings['coppaAge']) && empty($modSettings['coppaType']) && empty($_SESSION['skip_coppa'])) {
            // !!! This should be put in Errors, imho.
            loadLanguage('Login');
            fatal_lang_error('under_age_registration_prohibited', false, array($modSettings['coppaAge']));
        }
        // Check whether the visual verification code was entered correctly.
        if (!empty($modSettings['reg_verification'])) {
            require_once $sourcedir . '/Subs-Editor.php';
            $verificationOptions = array('id' => 'register');
            $context['visual_verification'] = create_control_verification($verificationOptions, true);
            if (is_array($context['visual_verification'])) {
                loadLanguage('Errors');
                foreach ($context['visual_verification'] as $error) {
                    $reg_errors[] = $txt['error_' . $error];
                }
            }
        }
    }
    foreach ($_POST as $key => $value) {
        if (!is_array($_POST[$key])) {
            $_POST[$key] = htmltrim__recursive(str_replace(array("\n", "\r"), '', $_POST[$key]));
        }
    }
    // Collect all extra registration fields someone might have filled in.
    $possible_strings = array('website_url', 'website_title', 'aim', 'yim', 'skype', 'gtalk', 'location', 'birthdate', 'time_format', 'buddy_list', 'pm_ignore_list', 'smiley_set', 'signature', 'personal_text', 'avatar', 'lngfile', 'secret_question', 'secret_answer');
    $possible_ints = array('pm_email_notify', 'notify_types', 'icq', 'gender', 'id_theme');
    $possible_floats = array('time_offset');
    $possible_bools = array('notify_announcements', 'notify_regularity', 'notify_send_body', 'hide_email', 'show_online');
    if (isset($_POST['secret_answer']) && $_POST['secret_answer'] != '') {
        $_POST['secret_answer'] = md5($_POST['secret_answer']);
    }
    // Needed for isReservedName() and registerMember().
    require_once $sourcedir . '/Subs-Members.php';
    // Validation... even if we're not a mall.
    if (isset($_POST['real_name']) && (!empty($modSettings['allow_editDisplayName']) || allowedTo('moderate_forum'))) {
        $_POST['real_name'] = trim(preg_replace('~[\\t\\n\\r \\x0B\\0' . ($context['utf8'] ? $context['server']['complex_preg_chars'] ? '\\x{A0}\\x{AD}\\x{2000}-\\x{200F}\\x{201F}\\x{202F}\\x{3000}\\x{FEFF}' : " ­ -‏‟ ‟ " : '\\x00-\\x08\\x0B\\x0C\\x0E-\\x19\\xA0') . ']+~' . ($context['utf8'] ? 'u' : ''), ' ', $_POST['real_name']));
        if (trim($_POST['real_name']) != '' && !isReservedName($_POST['real_name']) && $smcFunc['strlen']($_POST['real_name']) < 60) {
            $possible_strings[] = 'real_name';
        }
    }
    if (isset($_POST['msn']) && preg_match('~^[0-9A-Za-z=_+\\-/][0-9A-Za-z=_\'+\\-/\\.]*@[\\w\\-]+(\\.[\\w\\-]+)*(\\.[\\w]{2,6})$~', $_POST['msn']) != 0) {
        $profile_strings[] = 'msn';
    }
    // Handle a string as a birthdate...
    if (isset($_POST['birthdate']) && $_POST['birthdate'] != '') {
        $_POST['birthdate'] = strftime('%Y-%m-%d', strtotime($_POST['birthdate']));
    } elseif (!empty($_POST['bday1']) && !empty($_POST['bday2'])) {
        $_POST['birthdate'] = sprintf('%04d-%02d-%02d', empty($_POST['bday3']) ? 0 : (int) $_POST['bday3'], (int) $_POST['bday1'], (int) $_POST['bday2']);
    }
    // By default assume email is hidden, only show it if we tell it to.
    $_POST['hide_email'] = !empty($_POST['allow_email']) ? 0 : 1;
    // Validate the passed language file.
    if (isset($_POST['lngfile']) && !empty($modSettings['userLanguage'])) {
        // Do we have any languages?
        if (empty($context['languages'])) {
            getLanguages();
        }
        // Did we find it?
        if (isset($context['languages'][$_POST['lngfile']])) {
            $_SESSION['language'] = $_POST['lngfile'];
        } else {
            unset($_POST['lngfile']);
        }
    } else {
        unset($_POST['lngfile']);
    }
    // Some of these fields we may not want.
    if (!empty($modSettings['registration_fields'])) {
        // But we might want some of them if the admin asks for them.
        $standard_fields = array('icq', 'msn', 'aim', 'yim', 'location', 'gender');
        $reg_fields = explode(',', $modSettings['registration_fields']);
        $exclude_fields = array_diff($standard_fields, $reg_fields);
        // Website is a little different
        if (!in_array('website', $reg_fields)) {
            $exclude_fields = array_merge($exclude_fields, array('website_url', 'website_title'));
        }
        // We used to accept signature on registration but it's being abused by spammers these days, so no more.
        $exclude_fields[] = 'signature';
    } else {
        $exclude_fields = array('signature', 'icq', 'msn', 'aim', 'yim', 'location', 'gender', 'website_url', 'website_title');
    }
    $possible_strings = array_diff($possible_strings, $exclude_fields);
    $possible_ints = array_diff($possible_ints, $exclude_fields);
    $possible_floats = array_diff($possible_floats, $exclude_fields);
    $possible_bools = array_diff($possible_bools, $exclude_fields);
    // Set the options needed for registration.
    $regOptions = array('interface' => 'guest', 'username' => !empty($_POST['user']) ? $_POST['user'] : '', 'email' => !empty($_POST['email']) ? $_POST['email'] : '', 'password' => !empty($_POST['passwrd1']) ? $_POST['passwrd1'] : '', 'password_check' => !empty($_POST['passwrd2']) ? $_POST['passwrd2'] : '', 'openid' => !empty($_POST['openid_identifier']) ? $_POST['openid_identifier'] : '', 'auth_method' => !empty($_POST['authenticate']) ? $_POST['authenticate'] : '', 'check_reserved_name' => true, 'check_password_strength' => true, 'check_email_ban' => true, 'send_welcome_email' => !empty($modSettings['send_welcomeEmail']), 'require' => !empty($modSettings['coppaAge']) && !$verifiedOpenID && empty($_SESSION['skip_coppa']) ? 'coppa' : (empty($modSettings['registration_method']) ? 'nothing' : ($modSettings['registration_method'] == 1 ? 'activation' : 'approval')), 'extra_register_vars' => array(), 'theme_vars' => array());
    // Include the additional options that might have been filled in.
    foreach ($possible_strings as $var) {
        if (isset($_POST[$var])) {
            $regOptions['extra_register_vars'][$var] = $smcFunc['htmlspecialchars']($_POST[$var], ENT_QUOTES);
        }
    }
    foreach ($possible_ints as $var) {
        if (isset($_POST[$var])) {
            $regOptions['extra_register_vars'][$var] = (int) $_POST[$var];
        }
    }
    foreach ($possible_floats as $var) {
        if (isset($_POST[$var])) {
            $regOptions['extra_register_vars'][$var] = (double) $_POST[$var];
        }
    }
    foreach ($possible_bools as $var) {
        if (isset($_POST[$var])) {
            $regOptions['extra_register_vars'][$var] = empty($_POST[$var]) ? 0 : 1;
        }
    }
    // Registration options are always default options...
    if (isset($_POST['default_options'])) {
        $_POST['options'] = isset($_POST['options']) ? $_POST['options'] + $_POST['default_options'] : $_POST['default_options'];
    }
    $regOptions['theme_vars'] = isset($_POST['options']) && is_array($_POST['options']) ? $_POST['options'] : array();
    // Make sure they are clean, dammit!
    $regOptions['theme_vars'] = htmlspecialchars__recursive($regOptions['theme_vars']);
    // If Quick Reply hasn't been set then set it to be shown but collapsed.
    if (!isset($regOptions['theme_vars']['display_quick_reply'])) {
        $regOptions['theme_vars']['display_quick_reply'] = 1;
    }
    // Check whether we have fields that simply MUST be displayed?
    $request = $smcFunc['db_query']('', '
		SELECT col_name, field_name, field_type, field_length, mask, show_reg
		FROM {db_prefix}custom_fields
		WHERE active = {int:is_active}', array('is_active' => 1));
    $custom_field_errors = array();
    while ($row = $smcFunc['db_fetch_assoc']($request)) {
        // Don't allow overriding of the theme variables.
        if (isset($regOptions['theme_vars'][$row['col_name']])) {
            unset($regOptions['theme_vars'][$row['col_name']]);
        }
        // Not actually showing it then?
        if (!$row['show_reg']) {
            continue;
        }
        // Prepare the value!
        $value = isset($_POST['customfield'][$row['col_name']]) ? trim($_POST['customfield'][$row['col_name']]) : '';
        // We only care for text fields as the others are valid to be empty.
        if (!in_array($row['field_type'], array('check', 'select', 'radio'))) {
            // Is it too long?
            if ($row['field_length'] && $row['field_length'] < $smcFunc['strlen']($value)) {
                $custom_field_errors[] = array('custom_field_too_long', array($row['field_name'], $row['field_length']));
            }
            // Any masks to apply?
            if ($row['field_type'] == 'text' && !empty($row['mask']) && $row['mask'] != 'none') {
                //!!! We never error on this - just ignore it at the moment...
                if ($row['mask'] == 'email' && (preg_match('~^[0-9A-Za-z=_+\\-/][0-9A-Za-z=_\'+\\-/\\.]*@[\\w\\-]+(\\.[\\w\\-]+)*(\\.[\\w]{2,6})$~', $value) === 0 || strlen($value) > 255)) {
                    $custom_field_errors[] = array('custom_field_invalid_email', array($row['field_name']));
                } elseif ($row['mask'] == 'number' && preg_match('~[^\\d]~', $value)) {
                    $custom_field_errors[] = array('custom_field_not_number', array($row['field_name']));
                } elseif (substr($row['mask'], 0, 5) == 'regex' && trim($value) != '' && preg_match(substr($row['mask'], 5), $value) === 0) {
                    $custom_field_errors[] = array('custom_field_inproper_format', array($row['field_name']));
                }
            }
        }
        // xxx if we are editing our minecraft name, make sure there are no duplicates
        if (($row['col_name'] == "cust_minecra" || $row['col_name'] == "cust_rscnam") && $value != '') {
            $already_taken_memID = -1;
            $already_taken_memName = 'This user';
            // first check the custom names
            $mc_request = $smcFunc['db_query']('', '
						SELECT `id_member`
						FROM `{db_prefix}themes`
						WHERE `variable` = {string:col_name}
							AND `value` = {string:value}', array('col_name' => $row['col_name'], 'value' => strtolower($value)));
            if ($mc_row = $smcFunc['db_fetch_assoc']($mc_request)) {
                $already_taken_memID = $mc_row['id_member'];
            }
            $smcFunc['db_free_result']($mc_request);
            // if custom name is not taken, compare it to account names, or just grab name
            $mc_request = $smcFunc['db_query']('', '
						SELECT `id_member`, `real_name`
						FROM `{db_prefix}members`
						WHERE id_member = {int:already_taken_memID} OR 
								(
									(
										`real_name` = {string:value}
										OR `member_name` = {string:value}
									)
								)', array('already_taken_memID' => $already_taken_memID, 'value' => strtolower($value)));
            if ($mc_row = $smcFunc['db_fetch_assoc']($mc_request)) {
                $already_taken_memID = $mc_row['id_member'];
                $already_taken_memName = $mc_row['real_name'];
            }
            $smcFunc['db_free_result']($mc_request);
            if ($already_taken_memID != -1) {
                // then someone already is using this name
                global $boardurl;
                $what_name = $row['col_name'] == "cust_minecra" ? 'Minecraft' : 'RSC';
                die('<html>Error: <a href="' . $boardurl . '/index.php?action=profile;u=' . $already_taken_memID . "\">{$already_taken_memName}</a> has already registered this {$what_name} name!</html>");
            }
        }
        if ($row['col_name'] == "cust_moparcr" && $value != '' && strlen($value) != 40) {
            if (strlen($value) > 30) {
                die("<html>Error: Maximum length for MoparCraft server password is 30 characters.</html>");
            }
            if ($value == $regOptions['password']) {
                die("<html>Error: You can't set your MoparCraft server password to be the same as your forum password, if you want to use your forum password, leave this blank.</html>");
            }
            $value = sha1(strtolower($regOptions['username']) . htmlspecialchars_decode($value));
            $_POST['customfield'][$row['col_name']] = $value;
        }
        // xxx end if we are editing our minecraft name, make sure there are no duplicates
        // Is this required but not there?
        if (trim($value) == '' && $row['show_reg'] > 1) {
            $custom_field_errors[] = array('custom_field_empty', array($row['field_name']));
        }
    }
    $smcFunc['db_free_result']($request);
    // Process any errors.
    if (!empty($custom_field_errors)) {
        loadLanguage('Errors');
        foreach ($custom_field_errors as $error) {
            $reg_errors[] = vsprintf($txt['error_' . $error[0]], $error[1]);
        }
    }
    // Lets check for other errors before trying to register the member.
    if (!empty($reg_errors)) {
        $_REQUEST['step'] = 2;
        return Register($reg_errors);
    }
    // If they're wanting to use OpenID we need to validate them first.
    if (empty($_SESSION['openid']['verified']) && !empty($_POST['authenticate']) && $_POST['authenticate'] == 'openid') {
        // What do we need to save?
        $save_variables = array();
        foreach ($_POST as $k => $v) {
            if (!in_array($k, array('sc', 'sesc', $context['session_var'], 'passwrd1', 'passwrd2', 'regSubmit'))) {
                $save_variables[$k] = $v;
            }
        }
        require_once $sourcedir . '/Subs-OpenID.php';
        smf_openID_validate($_POST['openid_identifier'], false, $save_variables);
    } elseif ($verifiedOpenID || !empty($_POST['openid_identifier']) && $_POST['authenticate'] == 'openid') {
        $regOptions['username'] = !empty($_POST['user']) && trim($_POST['user']) != '' ? $_POST['user'] : $_SESSION['openid']['nickname'];
        $regOptions['email'] = !empty($_POST['email']) && trim($_POST['email']) != '' ? $_POST['email'] : $_SESSION['openid']['email'];
        $regOptions['auth_method'] = 'openid';
        $regOptions['openid'] = !empty($_POST['openid_identifier']) ? $_POST['openid_identifier'] : $_SESSION['openid']['openid_uri'];
    }
    $memberID = registerMember($regOptions, true);
    // What there actually an error of some kind dear boy?
    if (is_array($memberID)) {
        $reg_errors = array_merge($reg_errors, $memberID);
        $_REQUEST['step'] = 2;
        return Register($reg_errors);
    }
    // Do our spam protection now.
    spamProtection('register');
    // We'll do custom fields after as then we get to use the helper function!
    if (!empty($_POST['customfield'])) {
        require_once $sourcedir . '/Profile.php';
        require_once $sourcedir . '/Profile-Modify.php';
        makeCustomFieldChanges($memberID, 'register');
    }
    // If COPPA has been selected then things get complicated, setup the template.
    if (!empty($modSettings['coppaAge']) && empty($_SESSION['skip_coppa'])) {
        redirectexit('action=coppa;member=' . $memberID);
    } elseif (!empty($modSettings['registration_method'])) {
        loadTemplate('Register');
        $context += array('page_title' => $txt['register'], 'title' => $txt['registration_successful'], 'sub_template' => 'after', 'description' => $modSettings['registration_method'] == 2 ? $txt['approval_after_registration'] : $txt['activate_after_registration']);
    } else {
        call_integration_hook('integrate_activate', array($row['member_name']));
        setLoginCookie(60 * $modSettings['cookieTime'], $memberID, sha1(sha1(strtolower($regOptions['username']) . $regOptions['password']) . $regOptions['register_vars']['password_salt']));
        redirectexit('action=login2;sa=check;member=' . $memberID, $context['server']['needs_login_fix']);
    }
}
示例#10
0
function ReportToModerator2()
{
    global $txt, $scripturl, $db_prefix, $topic, $board, $user_info, $ID_MEMBER, $modSettings, $sourcedir, $language;
    // Check their session... don't want them redirected here without their knowledge.
    checkSession();
    spamProtection('spam');
    // You must have the proper permissions!
    isAllowedTo('report_any');
    require_once $sourcedir . '/Subs-Post.php';
    // Get the basic topic information, and make sure they can see it.
    $_POST['msg'] = (int) $_POST['msg'];
    $request = db_query("\n\t\tSELECT m.subject, m.ID_MEMBER, m.posterName, mem.realName\n\t\tFROM {$db_prefix}messages AS m\n\t\t\tLEFT JOIN {$db_prefix}members AS mem ON (m.ID_MEMBER = mem.ID_MEMBER)\n\t\tWHERE m.ID_MSG = {$_POST['msg']}\n\t\t\tAND m.ID_TOPIC = {$topic}\n\t\tLIMIT 1", __FILE__, __LINE__);
    if (mysql_num_rows($request) == 0) {
        fatal_lang_error('smf232');
    }
    list($subject, $member, $posterName, $realName) = mysql_fetch_row($request);
    mysql_free_result($request);
    if ($member == $ID_MEMBER) {
        fatal_lang_error('rtm_not_own', false);
    }
    $posterName = un_htmlspecialchars($realName) . ($realName != $posterName ? ' (' . $posterName . ')' : '');
    $reporterName = un_htmlspecialchars($user_info['name']) . ($user_info['name'] != $user_info['username'] && $user_info['username'] != '' ? ' (' . $user_info['username'] . ')' : '');
    $subject = un_htmlspecialchars($subject);
    // Get a list of members with the moderate_board permission.
    require_once $sourcedir . '/Subs-Members.php';
    $moderators = membersAllowedTo('moderate_board', $board);
    $request = db_query("\n\t\tSELECT ID_MEMBER, emailAddress, lngfile\n\t\tFROM {$db_prefix}members\n\t\tWHERE ID_MEMBER IN (" . implode(', ', $moderators) . ")\n\t\t\tAND notifyTypes != 4\n\t\tORDER BY lngfile", __FILE__, __LINE__);
    // Check that moderators do exist!
    if (mysql_num_rows($request) == 0) {
        fatal_lang_error('rtm11', false);
    }
    // Send every moderator an email.
    while ($row = mysql_fetch_assoc($request)) {
        loadLanguage('Post', empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile'], false);
        // Send it to the moderator.
        sendmail($row['emailAddress'], $txt['rtm3'] . ': ' . $subject . ' ' . $txt['rtm4'] . ' ' . $posterName, sprintf($txt['rtm_email1'], $subject) . ' ' . $posterName . ' ' . $txt['rtm_email2'] . ' ' . (empty($ID_MEMBER) ? $txt['guest'] . ' (' . $user_info['ip'] . ')' : $reporterName) . ' ' . $txt['rtm_email3'] . ":\n\n" . $scripturl . '?topic=' . $topic . '.msg' . $_POST['msg'] . '#msg' . $_POST['msg'] . "\n\n" . $txt['rtm_email_comment'] . ":\n" . $_POST['comment'] . "\n\n" . $txt[130], $user_info['email']);
    }
    mysql_free_result($request);
    // Back to the board! (you probably don't want to see the post anymore..)
    redirectexit('board=' . $board . '.0');
}
示例#11
0
function Login2()
{
    global $txt, $db_prefix, $scripturl, $user_info, $user_settings;
    global $cookiename, $maintenance, $ID_MEMBER, $modSettings, $context, $sc;
    global $sourcedir;
    // Load cookie authentication stuff.
    require_once $sourcedir . '/Subs-Auth.php';
    if (isset($_GET['sa']) && $_GET['sa'] == 'salt' && !$user_info['is_guest']) {
        if (isset($_COOKIE[$cookiename]) && preg_match('~^a:[34]:\\{i:0;(i:\\d{1,6}|s:[1-8]:"\\d{1,8}");i:1;s:(0|40):"([a-fA-F0-9]{40})?";i:2;[id]:\\d{1,14};(i:3;i:\\d;)?\\}$~', $_COOKIE[$cookiename]) === 1) {
            list(, , $timeout) = @unserialize($_COOKIE[$cookiename]);
        } elseif (isset($_SESSION['login_' . $cookiename])) {
            list(, , $timeout) = @unserialize(stripslashes($_SESSION['login_' . $cookiename]));
        } else {
            trigger_error('Login2(): Cannot be logged in without a session or cookie', E_USER_ERROR);
        }
        $user_settings['passwordSalt'] = substr(md5(mt_rand()), 0, 4);
        updateMemberData($ID_MEMBER, array('passwordSalt' => '\'' . $user_settings['passwordSalt'] . '\''));
        setLoginCookie($timeout - time(), $ID_MEMBER, sha1($user_settings['passwd'] . $user_settings['passwordSalt']));
        redirectexit('action=login2;sa=check;member=' . $ID_MEMBER, $context['server']['needs_login_fix']);
    } elseif (isset($_GET['sa']) && $_GET['sa'] == 'check') {
        // Strike!  You're outta there!
        if ($_GET['member'] != $ID_MEMBER) {
            fatal_lang_error('login_cookie_error', false);
        }
        // Some whitelisting for login_url...
        if (empty($_SESSION['login_url'])) {
            redirectexit();
        } else {
            // Best not to clutter the session data too much...
            $temp = $_SESSION['login_url'];
            unset($_SESSION['login_url']);
            redirectexit($temp);
        }
    }
    // Beyond this point you are assumed to be a guest trying to login.
    if (!$user_info['is_guest']) {
        redirectexit();
    }
    // Set the login_url if it's not already set.
    if (empty($_SESSION['login_url']) && isset($_SESSION['old_url']) && preg_match('~(board|topic)[=,]~', $_SESSION['old_url']) != 0) {
        $_SESSION['login_url'] = $_SESSION['old_url'];
    }
    // Are you guessing with a script that doesn't keep the session id?
    spamProtection('login');
    // Been guessing a lot, haven't we?
    if (isset($_SESSION['failed_login']) && $_SESSION['failed_login'] >= $modSettings['failed_login_threshold'] * 3) {
        fatal_lang_error('login_threshold_fail');
    }
    // Set up the cookie length.  (if it's invalid, just fall through and use the default.)
    if (isset($_POST['cookieneverexp']) || !empty($_POST['cookielength']) && $_POST['cookielength'] == -1) {
        $modSettings['cookieTime'] = 3153600;
    } elseif (!empty($_POST['cookielength']) && ($_POST['cookielength'] >= 1 || $_POST['cookielength'] <= 525600)) {
        $modSettings['cookieTime'] = (int) $_POST['cookielength'];
    }
    // Set things up in case an error occurs.
    if (!empty($maintenance) || empty($modSettings['allow_guestAccess'])) {
        $context['sub_template'] = 'kick_guest';
    }
    loadLanguage('Login');
    // Load the template stuff - wireless or normal.
    if (WIRELESS) {
        $context['sub_template'] = WIRELESS_PROTOCOL . '_login';
    } else {
        loadTemplate('Login');
        $context['sub_template'] = 'login';
    }
    // Set up the default/fallback stuff.
    $context['default_username'] = isset($_REQUEST['user']) ? htmlspecialchars(stripslashes($_REQUEST['user'])) : '';
    $context['default_password'] = '';
    $context['never_expire'] = $modSettings['cookieTime'] == 525600 || $modSettings['cookieTime'] == 3153600;
    $context['login_error'] =& $txt[106];
    $context['page_title'] = $txt[34];
    // You forgot to type your username, dummy!
    if (!isset($_REQUEST['user']) || $_REQUEST['user'] == '') {
        $context['login_error'] =& $txt[37];
        return;
    }
    // Hmm... maybe 'admin' will login with no password. Uhh... NO!
    if ((!isset($_REQUEST['passwrd']) || $_REQUEST['passwrd'] == '') && (!isset($_REQUEST['hash_passwrd']) || strlen($_REQUEST['hash_passwrd']) != 40)) {
        $context['login_error'] =& $txt[38];
        return;
    }
    // No funky symbols either.
    if (preg_match('~[<>&"\'=\\\\]~', $_REQUEST['user']) != 0) {
        $context['login_error'] =& $txt[240];
        return;
    }
    // Are we using any sort of integration to validate the login?
    if (isset($modSettings['integrate_validate_login']) && function_exists($modSettings['integrate_validate_login'])) {
        if (call_user_func($modSettings['integrate_validate_login'], $_REQUEST['user'], isset($_REQUEST['hash_passwrd']) && strlen($_REQUEST['hash_passwrd']) == 40 ? $_REQUEST['hash_passwrd'] : null, $modSettings['cookieTime']) == 'retry') {
            $context['login_error'] = $txt['login_hash_error'];
            $context['disable_login_hashing'] = true;
            return;
        }
    }
    // Load the data up!
    $request = db_query("\n\t\tSELECT passwd, ID_MEMBER, ID_GROUP, lngfile, is_activated, emailAddress, additionalGroups, memberName, passwordSalt\n\t\tFROM {$db_prefix}members\n\t\tWHERE memberName = '{$_REQUEST['user']}'\n\t\tLIMIT 1", __FILE__, __LINE__);
    // Probably mistyped or their email, try it as an email address. (memberName first, though!)
    if (mysql_num_rows($request) == 0) {
        mysql_free_result($request);
        $request = db_query("\n\t\t\tSELECT passwd, ID_MEMBER, ID_GROUP, lngfile, is_activated, emailAddress, additionalGroups, memberName, passwordSalt\n\t\t\tFROM {$db_prefix}members\n\t\t\tWHERE emailAddress = '{$_REQUEST['user']}'\n\t\t\tLIMIT 1", __FILE__, __LINE__);
        // Let them try again, it didn't match anything...
        if (mysql_num_rows($request) == 0) {
            $context['login_error'] =& $txt[40];
            return;
        }
    }
    $user_settings = mysql_fetch_assoc($request);
    mysql_free_result($request);
    // What is the true activation status of this account?
    $activation_status = $user_settings['is_activated'] > 10 ? $user_settings['is_activated'] - 10 : $user_settings['is_activated'];
    // Check if the account is activated - COPPA first...
    if ($activation_status == 5) {
        $context['login_error'] = $txt['coppa_not_completed1'] . ' <a href="' . $scripturl . '?action=coppa;member=' . $user_settings['ID_MEMBER'] . '">' . $txt['coppa_not_completed2'] . '</a>';
        return;
    } elseif ($activation_status == 3) {
        fatal_lang_error('still_awaiting_approval');
    } elseif ($activation_status == 4) {
        // Display an error if we haven't decided to undelete.
        if (!isset($_REQUEST['undelete'])) {
            $context['login_error'] = $txt['awaiting_delete_account'];
            $context['login_show_undelete'] = true;
            return;
        } else {
            updateMemberData($user_settings['ID_MEMBER'], array('is_activated' => 1));
            updateSettings(array('unapprovedMembers' => $modSettings['unapprovedMembers'] > 0 ? $modSettings['unapprovedMembers'] - 1 : 0));
        }
    } elseif ($activation_status != 1) {
        log_error($txt['activate_not_completed1'] . ' - <span class="remove">' . $user_settings['memberName'] . '</span>', false);
        $context['login_error'] = $txt['activate_not_completed1'] . ' <a href="' . $scripturl . '?action=activate;sa=resend;u=' . $user_settings['ID_MEMBER'] . '">' . $txt['activate_not_completed2'] . '</a>';
        return;
    }
    // Figure out the password using SMF's encryption - if what they typed is right.
    if (isset($_REQUEST['hash_passwrd']) && strlen($_REQUEST['hash_passwrd']) == 40) {
        // Needs upgrading?
        if (strlen($user_settings['passwd']) != 40) {
            $context['login_error'] = $txt['login_hash_error'];
            $context['disable_login_hashing'] = true;
            return;
        } elseif ($_REQUEST['hash_passwrd'] == sha1($user_settings['passwd'] . $sc)) {
            $sha_passwd = $user_settings['passwd'];
        } else {
            $_SESSION['failed_login'] = @$_SESSION['failed_login'] + 1;
            if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold']) {
                redirectexit('action=reminder');
            } else {
                log_error($txt[39] . ' - <span class="remove">' . $user_settings['memberName'] . '</span>');
                $context['disable_login_hashing'] = true;
                $context['login_error'] = $txt[39];
                return;
            }
        }
    } else {
        $sha_passwd = sha1(strtolower($user_settings['memberName']) . un_htmlspecialchars(stripslashes($_REQUEST['passwrd'])));
    }
    // Bad password!  Thought you could fool the database?!
    if ($user_settings['passwd'] != $sha_passwd) {
        // Maybe we were too hasty... let's try some other authentication methods.
        $other_passwords = array();
        // None of the below cases will be used most of the time (because the salt is normally set.)
        if ($user_settings['passwordSalt'] == '') {
            // YaBB SE, Discus, MD5 (used a lot), SHA-1 (used some), SMF 1.0.x, IkonBoard, and none at all.
            $other_passwords[] = crypt($_REQUEST['passwrd'], substr($_REQUEST['passwrd'], 0, 2));
            $other_passwords[] = crypt($_REQUEST['passwrd'], substr($user_settings['passwd'], 0, 2));
            $other_passwords[] = md5($_REQUEST['passwrd']);
            $other_passwords[] = sha1($_REQUEST['passwrd']);
            $other_passwords[] = md5_hmac($_REQUEST['passwrd'], strtolower($user_settings['memberName']));
            $other_passwords[] = md5($_REQUEST['passwrd'] . strtolower($user_settings['memberName']));
            $other_passwords[] = $_REQUEST['passwrd'];
            // This one is a strange one... MyPHP, crypt() on the MD5 hash.
            $other_passwords[] = crypt(md5($_REQUEST['passwrd']), md5($_REQUEST['passwrd']));
            // Snitz style - SHA-256.  Technically, this is a downgrade, but most PHP configurations don't support sha256 anyway.
            if (strlen($user_settings['passwd']) == 64 && function_exists('mhash') && defined('MHASH_SHA256')) {
                $other_passwords[] = bin2hex(mhash(MHASH_SHA256, $_REQUEST['passwrd']));
            }
        } elseif (strlen($user_settings['passwd']) == 32) {
            // vBulletin 3 style hashing?  Let's welcome them with open arms \o/.
            $other_passwords[] = md5(md5($_REQUEST['passwrd']) . $user_settings['passwordSalt']);
            // Hmm.. p'raps it's Invision 2 style?
            $other_passwords[] = md5(md5($user_settings['passwordSalt']) . md5($_REQUEST['passwrd']));
        }
        // Maybe they are using a hash from before the password fix.
        $other_passwords[] = sha1(strtolower($user_settings['memberName']) . addslashes(un_htmlspecialchars(stripslashes($_REQUEST['passwrd']))));
        // SMF's sha1 function can give a funny result on Linux (Not our fault!). If we've now got the real one let the old one be valid!
        require_once $sourcedir . '/Subs-Compat.php';
        $other_passwords[] = sha1_smf(strtolower($user_settings['memberName']) . un_htmlspecialchars(stripslashes($_REQUEST['passwrd'])));
        // Whichever encryption it was using, let's make it use SMF's now ;).
        if (in_array($user_settings['passwd'], $other_passwords)) {
            $user_settings['passwd'] = $sha_passwd;
            $user_settings['passwordSalt'] = substr(md5(mt_rand()), 0, 4);
            // Update the password and set up the hash.
            updateMemberData($user_settings['ID_MEMBER'], array('passwd' => '\'' . $user_settings['passwd'] . '\'', 'passwordSalt' => '\'' . $user_settings['passwordSalt'] . '\''));
        } else {
            // They've messed up again - keep a count to see if they need a hand.
            $_SESSION['failed_login'] = @$_SESSION['failed_login'] + 1;
            // Hmm... don't remember it, do you?  Here, try the password reminder ;).
            if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold']) {
                redirectexit('action=reminder');
            } else {
                // Log an error so we know that it didn't go well in the error log.
                log_error($txt[39] . ' - <span class="remove">' . $user_settings['memberName'] . '</span>');
                $context['login_error'] = $txt[39];
                return;
            }
        }
    } elseif ($user_settings['passwordSalt'] == '') {
        $user_settings['passwordSalt'] = substr(md5(mt_rand()), 0, 4);
        updateMemberData($user_settings['ID_MEMBER'], array('passwordSalt' => '\'' . $user_settings['passwordSalt'] . '\''));
    }
    if (isset($modSettings['integrate_login']) && function_exists($modSettings['integrate_login'])) {
        $modSettings['integrate_login']($user_settings['memberName'], isset($_REQUEST['hash_passwrd']) && strlen($_REQUEST['hash_passwrd']) == 40 ? $_REQUEST['hash_passwrd'] : null, $modSettings['cookieTime']);
    }
    // Get ready to set the cookie...
    $username = $user_settings['memberName'];
    $ID_MEMBER = $user_settings['ID_MEMBER'];
    // Bam!  Cookie set.  A session too, just incase.
    setLoginCookie(60 * $modSettings['cookieTime'], $user_settings['ID_MEMBER'], sha1($user_settings['passwd'] . $user_settings['passwordSalt']));
    // Reset the login threshold.
    if (isset($_SESSION['failed_login'])) {
        unset($_SESSION['failed_login']);
    }
    $user_info['is_guest'] = false;
    $user_settings['additionalGroups'] = explode(',', $user_settings['additionalGroups']);
    $user_info['is_admin'] = $user_settings['ID_GROUP'] == 1 || in_array(1, $user_settings['additionalGroups']);
    // Are you banned?
    is_not_banned(true);
    // An administrator, set up the login so they don't have to type it again.
    if ($user_info['is_admin']) {
        $_SESSION['admin_time'] = time();
        unset($_SESSION['just_registered']);
    }
    // Don't stick the language or theme after this point.
    unset($_SESSION['language']);
    unset($_SESSION['ID_THEME']);
    // You've logged in, haven't you?
    updateMemberData($ID_MEMBER, array('lastLogin' => time(), 'memberIP' => '\'' . $user_info['ip'] . '\'', 'memberIP2' => '\'' . $_SERVER['BAN_CHECK_IP'] . '\''));
    // Get rid of the online entry for that old guest....
    db_query("\n\t\tDELETE FROM {$db_prefix}log_online\n\t\tWHERE session = 'ip{$user_info['ip']}'\n\t\tLIMIT 1", __FILE__, __LINE__);
    $_SESSION['log_time'] = 0;
    // Just log you back out if it's in maintenance mode and you AREN'T an admin.
    if (empty($maintenance) || allowedTo('admin_forum')) {
        redirectexit('action=login2;sa=check;member=' . $ID_MEMBER, $context['server']['needs_login_fix']);
    } else {
        redirectexit('action=logout;sesc=' . $sc, $context['server']['needs_login_fix']);
    }
}
示例#12
0
    /**
     * Posts or saves the message composed with Post().
     *
     * requires various permissions depending on the action.
     * handles attachment, post, and calendar saving.
     * sends off notifications, and allows for announcements and moderation.
     * accessed from ?action=post2.
     */
    public function action_post2()
    {
        global $board, $topic, $txt, $modSettings, $context, $user_settings;
        global $user_info, $board_info, $options, $ignore_temp;
        // Sneaking off, are we?
        if (empty($_POST) && empty($topic)) {
            if (empty($_SERVER['CONTENT_LENGTH'])) {
                redirectexit('action=post;board=' . $board . '.0');
            } else {
                fatal_lang_error('post_upload_error', false);
            }
        } elseif (empty($_POST) && !empty($topic)) {
            redirectexit('action=post;topic=' . $topic . '.0');
        }
        // No need!
        $context['robot_no_index'] = true;
        // We are now in post2 action
        $context['current_action'] = 'post2';
        require_once SOURCEDIR . '/AttachmentErrorContext.class.php';
        // No errors as yet.
        $post_errors = Error_Context::context('post', 1);
        $attach_errors = Attachment_Error_Context::context();
        // If the session has timed out, let the user re-submit their form.
        if (checkSession('post', '', false) != '') {
            $post_errors->addError('session_timeout');
            // Disable the preview so that any potentially malicious code is not executed
            $_REQUEST['preview'] = false;
            return $this->action_post();
        }
        // Wrong verification code?
        if (!$user_info['is_admin'] && !$user_info['is_mod'] && !empty($modSettings['posts_require_captcha']) && ($user_info['posts'] < $modSettings['posts_require_captcha'] || $user_info['is_guest'] && $modSettings['posts_require_captcha'] == -1)) {
            require_once SUBSDIR . '/VerificationControls.class.php';
            $verificationOptions = array('id' => 'post');
            $context['require_verification'] = create_control_verification($verificationOptions, true);
            if (is_array($context['require_verification'])) {
                foreach ($context['require_verification'] as $verification_error) {
                    $post_errors->addError($verification_error);
                }
            }
        }
        require_once SUBSDIR . '/Boards.subs.php';
        require_once SUBSDIR . '/Post.subs.php';
        loadLanguage('Post');
        // Drafts enabled and needed?
        if (!empty($modSettings['drafts_enabled']) && (isset($_POST['save_draft']) || isset($_POST['id_draft']))) {
            require_once SUBSDIR . '/Drafts.subs.php';
        }
        // First check to see if they are trying to delete any current attachments.
        if (isset($_POST['attach_del'])) {
            $keep_temp = array();
            $keep_ids = array();
            foreach ($_POST['attach_del'] as $dummy) {
                if (strpos($dummy, 'post_tmp_' . $user_info['id']) !== false) {
                    $keep_temp[] = $dummy;
                } else {
                    $keep_ids[] = (int) $dummy;
                }
            }
            if (isset($_SESSION['temp_attachments'])) {
                foreach ($_SESSION['temp_attachments'] as $attachID => $attachment) {
                    if (isset($_SESSION['temp_attachments']['post']['files'], $attachment['name']) && in_array($attachment['name'], $_SESSION['temp_attachments']['post']['files']) || in_array($attachID, $keep_temp) || strpos($attachID, 'post_tmp_' . $user_info['id']) === false) {
                        continue;
                    }
                    unset($_SESSION['temp_attachments'][$attachID]);
                    @unlink($attachment['tmp_name']);
                }
            }
            if (!empty($_REQUEST['msg'])) {
                require_once SUBSDIR . '/ManageAttachments.subs.php';
                $attachmentQuery = array('attachment_type' => 0, 'id_msg' => (int) $_REQUEST['msg'], 'not_id_attach' => $keep_ids);
                removeAttachments($attachmentQuery);
            }
        }
        // Then try to upload any attachments.
        $context['attachments']['can']['post'] = !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1 && (allowedTo('post_attachment') || $modSettings['postmod_active'] && allowedTo('post_unapproved_attachments'));
        if ($context['attachments']['can']['post'] && empty($_POST['from_qr'])) {
            require_once SUBSDIR . '/Attachments.subs.php';
            if (isset($_REQUEST['msg'])) {
                processAttachments((int) $_REQUEST['msg']);
            } else {
                processAttachments();
            }
        }
        // Previewing? Go back to start.
        if (isset($_REQUEST['preview'])) {
            return $this->action_post();
        }
        // Prevent double submission of this form.
        checkSubmitOnce('check');
        // If this isn't a new topic load the topic info that we need.
        if (!empty($topic)) {
            require_once SUBSDIR . '/Topic.subs.php';
            $topic_info = getTopicInfo($topic);
            // Though the topic should be there, it might have vanished.
            if (empty($topic_info)) {
                fatal_lang_error('topic_doesnt_exist');
            }
            // Did this topic suddenly move? Just checking...
            if ($topic_info['id_board'] != $board) {
                fatal_lang_error('not_a_topic');
            }
        }
        // Replying to a topic?
        if (!empty($topic) && !isset($_REQUEST['msg'])) {
            // Don't allow a post if it's locked.
            if ($topic_info['locked'] != 0 && !allowedTo('moderate_board')) {
                fatal_lang_error('topic_locked', false);
            }
            // Sorry, multiple polls aren't allowed... yet.  You should stop giving me ideas :P.
            if (isset($_REQUEST['poll']) && $topic_info['id_poll'] > 0) {
                unset($_REQUEST['poll']);
            }
            // Do the permissions and approval stuff...
            $becomesApproved = true;
            if ($topic_info['id_member_started'] != $user_info['id']) {
                if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_any') && !allowedTo('post_reply_any')) {
                    $becomesApproved = false;
                } else {
                    isAllowedTo('post_reply_any');
                }
            } elseif (!allowedTo('post_reply_any')) {
                if ($modSettings['postmod_active']) {
                    if (allowedTo('post_unapproved_replies_own') && !allowedTo('post_reply_own')) {
                        $becomesApproved = false;
                    } elseif ($user_info['is_guest'] && allowedTo('post_unapproved_replies_any')) {
                        $becomesApproved = false;
                    } else {
                        isAllowedTo('post_reply_own');
                    }
                }
            }
            if (isset($_POST['lock'])) {
                // Nothing is changed to the lock.
                if (empty($topic_info['locked']) && empty($_POST['lock']) || !empty($_POST['lock']) && !empty($topic_info['locked'])) {
                    unset($_POST['lock']);
                } elseif (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']) {
                    unset($_POST['lock']);
                } elseif (!allowedTo('lock_any')) {
                    // You cannot override a moderator lock.
                    if ($topic_info['locked'] == 1) {
                        unset($_POST['lock']);
                    } else {
                        $_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
                    }
                } else {
                    $_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
                }
            }
            // So you wanna (un)sticky this...let's see.
            if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || $_POST['sticky'] == $topic_info['is_sticky'] || !allowedTo('make_sticky'))) {
                unset($_POST['sticky']);
            }
            // If drafts are enabled, then pass this off
            if (!empty($modSettings['drafts_enabled']) && isset($_POST['save_draft'])) {
                saveDraft();
                return $this->action_post();
            }
            // If the number of replies has changed, if the setting is enabled, go back to action_post() - which handles the error.
            if (empty($options['no_new_reply_warning']) && isset($_POST['last_msg']) && $topic_info['id_last_msg'] > $_POST['last_msg']) {
                addInlineJavascript('
					$(document).ready(function () {
						$("html,body").scrollTop($(\'.category_header:visible:first\').offset().top);
					});');
                return $this->action_post();
            }
            $posterIsGuest = $user_info['is_guest'];
        } elseif (empty($topic)) {
            // Now don't be silly, new topics will get their own id_msg soon enough.
            unset($_REQUEST['msg'], $_POST['msg'], $_GET['msg']);
            // Do like, the permissions, for safety and stuff...
            $becomesApproved = true;
            if ($modSettings['postmod_active'] && !allowedTo('post_new') && allowedTo('post_unapproved_topics')) {
                $becomesApproved = false;
            } else {
                isAllowedTo('post_new');
            }
            if (isset($_POST['lock'])) {
                // New topics are by default not locked.
                if (empty($_POST['lock'])) {
                    unset($_POST['lock']);
                } elseif (!allowedTo(array('lock_any', 'lock_own'))) {
                    unset($_POST['lock']);
                } else {
                    $_POST['lock'] = allowedTo('lock_any') ? 1 : 2;
                }
            }
            if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || empty($_POST['sticky']) || !allowedTo('make_sticky'))) {
                unset($_POST['sticky']);
            }
            // Saving your new topic as a draft first?
            if (!empty($modSettings['drafts_enabled']) && isset($_POST['save_draft'])) {
                saveDraft();
                return $this->action_post();
            }
            $posterIsGuest = $user_info['is_guest'];
        } elseif (isset($_REQUEST['msg']) && !empty($topic)) {
            $_REQUEST['msg'] = (int) $_REQUEST['msg'];
            require_once SUBSDIR . '/Messages.subs.php';
            $msgInfo = basicMessageInfo($_REQUEST['msg'], true);
            if (empty($msgInfo)) {
                fatal_lang_error('cant_find_messages', false);
            }
            if (!empty($topic_info['locked']) && !allowedTo('moderate_board')) {
                fatal_lang_error('topic_locked', false);
            }
            if (isset($_POST['lock'])) {
                // Nothing changes to the lock status.
                if (empty($_POST['lock']) && empty($topic_info['locked']) || !empty($_POST['lock']) && !empty($topic_info['locked'])) {
                    unset($_POST['lock']);
                } elseif (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']) {
                    unset($_POST['lock']);
                } elseif (!allowedTo('lock_any')) {
                    // You're not allowed to break a moderator's lock.
                    if ($topic_info['locked'] == 1) {
                        unset($_POST['lock']);
                    } else {
                        $_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
                    }
                } else {
                    $_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
                }
            }
            // Change the sticky status of this topic?
            if (isset($_POST['sticky']) && (!allowedTo('make_sticky') || $_POST['sticky'] == $topic_info['is_sticky'])) {
                unset($_POST['sticky']);
            }
            if ($msgInfo['id_member'] == $user_info['id'] && !allowedTo('modify_any')) {
                if ((!$modSettings['postmod_active'] || $msgInfo['approved']) && !empty($modSettings['edit_disable_time']) && $msgInfo['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time()) {
                    fatal_lang_error('modify_post_time_passed', false);
                } elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_own')) {
                    isAllowedTo('modify_replies');
                } else {
                    isAllowedTo('modify_own');
                }
            } elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_any')) {
                isAllowedTo('modify_replies');
                // If you're modifying a reply, I say it better be logged...
                $moderationAction = true;
            } else {
                isAllowedTo('modify_any');
                // Log it, assuming you're not modifying your own post.
                if ($msgInfo['id_member'] != $user_info['id']) {
                    $moderationAction = true;
                }
            }
            // If drafts are enabled, then lets send this off to save
            if (!empty($modSettings['drafts_enabled']) && isset($_POST['save_draft'])) {
                saveDraft();
                return $this->action_post();
            }
            $posterIsGuest = empty($msgInfo['id_member']);
            // Can they approve it?
            $can_approve = allowedTo('approve_posts');
            $becomesApproved = $modSettings['postmod_active'] ? $can_approve && !$msgInfo['approved'] ? !empty($_REQUEST['approve']) ? 1 : 0 : $msgInfo['approved'] : 1;
            $approve_has_changed = $msgInfo['approved'] != $becomesApproved;
            if (!allowedTo('moderate_forum') || !$posterIsGuest) {
                $_POST['guestname'] = $msgInfo['poster_name'];
                $_POST['email'] = $msgInfo['poster_email'];
            }
        }
        // In case we want to override
        if (allowedTo('approve_posts')) {
            $becomesApproved = !isset($_REQUEST['approve']) || !empty($_REQUEST['approve']) ? 1 : 0;
            $approve_has_changed = isset($msgInfo['approved']) ? $msgInfo['approved'] != $becomesApproved : false;
        }
        // If the poster is a guest evaluate the legality of name and email.
        if ($posterIsGuest) {
            $_POST['guestname'] = !isset($_POST['guestname']) ? '' : Util::htmlspecialchars(trim($_POST['guestname']));
            $_POST['email'] = !isset($_POST['email']) ? '' : Util::htmlspecialchars(trim($_POST['email']));
            if ($_POST['guestname'] == '' || $_POST['guestname'] == '_') {
                $post_errors->addError('no_name');
            }
            if (Util::strlen($_POST['guestname']) > 25) {
                $post_errors->addError('long_name');
            }
            if (empty($modSettings['guest_post_no_email'])) {
                // Only check if they changed it!
                if (!isset($msgInfo) || $msgInfo['poster_email'] != $_POST['email']) {
                    require_once SUBSDIR . '/DataValidator.class.php';
                    if (!allowedTo('moderate_forum') && !Data_Validator::is_valid($_POST, array('email' => 'valid_email|required'), array('email' => 'trim'))) {
                        empty($_POST['email']) ? $post_errors->addError('no_email') : $post_errors->addError('bad_email');
                    }
                }
                // Now make sure this email address is not banned from posting.
                isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt['guest_title']));
            }
            // In case they are making multiple posts this visit, help them along by storing their name.
            if (!$post_errors->hasErrors()) {
                $_SESSION['guest_name'] = $_POST['guestname'];
                $_SESSION['guest_email'] = $_POST['email'];
            }
        }
        // Check the subject and message.
        if (!isset($_POST['subject']) || Util::htmltrim(Util::htmlspecialchars($_POST['subject'])) === '') {
            $post_errors->addError('no_subject');
        }
        if (!isset($_POST['message']) || Util::htmltrim(Util::htmlspecialchars($_POST['message'], ENT_QUOTES)) === '') {
            $post_errors->addError('no_message');
        } elseif (!empty($modSettings['max_messageLength']) && Util::strlen($_POST['message']) > $modSettings['max_messageLength']) {
            $post_errors->addError(array('long_message', array($modSettings['max_messageLength'])));
        } else {
            // Prepare the message a bit for some additional testing.
            $_POST['message'] = Util::htmlspecialchars($_POST['message'], ENT_QUOTES);
            // Preparse code. (Zef)
            if ($user_info['is_guest']) {
                $user_info['name'] = $_POST['guestname'];
            }
            preparsecode($_POST['message']);
            // Let's see if there's still some content left without the tags.
            if (Util::htmltrim(strip_tags(parse_bbc($_POST['message'], false), '<img>')) === '' && (!allowedTo('admin_forum') || strpos($_POST['message'], '[html]') === false)) {
                $post_errors->addError('no_message');
            }
        }
        if (isset($_POST['calendar']) && !isset($_REQUEST['deleteevent']) && Util::htmltrim($_POST['evtitle']) === '') {
            $post_errors->addError('no_event');
        }
        // Validate the poll...
        if (isset($_REQUEST['poll']) && !empty($modSettings['pollMode'])) {
            if (!empty($topic) && !isset($_REQUEST['msg'])) {
                fatal_lang_error('no_access', false);
            }
            // This is a new topic... so it's a new poll.
            if (empty($topic)) {
                isAllowedTo('poll_post');
            } elseif ($user_info['id'] == $topic_info['id_member_started'] && !allowedTo('poll_add_any')) {
                isAllowedTo('poll_add_own');
            } else {
                isAllowedTo('poll_add_any');
            }
            if (!isset($_POST['question']) || trim($_POST['question']) == '') {
                $post_errors->addError('no_question');
            }
            $_POST['options'] = empty($_POST['options']) ? array() : htmltrim__recursive($_POST['options']);
            // Get rid of empty ones.
            foreach ($_POST['options'] as $k => $option) {
                if ($option == '') {
                    unset($_POST['options'][$k], $_POST['options'][$k]);
                }
            }
            // What are you going to vote between with one choice?!?
            if (count($_POST['options']) < 2) {
                $post_errors->addError('poll_few');
            } elseif (count($_POST['options']) > 256) {
                $post_errors->addError('poll_many');
            }
        }
        if ($posterIsGuest) {
            // If user is a guest, make sure the chosen name isn't taken.
            require_once SUBSDIR . '/Members.subs.php';
            if (isReservedName($_POST['guestname'], 0, true, false) && (!isset($msgInfo['poster_name']) || $_POST['guestname'] != $msgInfo['poster_name'])) {
                $post_errors->addError('bad_name');
            }
        } elseif (!isset($_REQUEST['msg'])) {
            $_POST['guestname'] = $user_info['username'];
            $_POST['email'] = $user_info['email'];
        }
        // Posting somewhere else? Are we sure you can?
        if (!empty($_REQUEST['post_in_board'])) {
            $new_board = (int) $_REQUEST['post_in_board'];
            if (!allowedTo('post_new', $new_board)) {
                $post_in_board = boardInfo($new_board);
                if (!empty($post_in_board)) {
                    $post_errors->addError(array('post_new_board', array($post_in_board['name'])));
                } else {
                    $post_errors->addError('post_new');
                }
            }
        }
        // Any mistakes?
        if ($post_errors->hasErrors() || $attach_errors->hasErrors()) {
            addInlineJavascript('
				$(document).ready(function () {
					$("html,body").scrollTop($(\'.category_header:visible:first\').offset().top);
				});');
            return $this->action_post();
        }
        // Make sure the user isn't spamming the board.
        if (!isset($_REQUEST['msg'])) {
            spamProtection('post');
        }
        // At about this point, we're posting and that's that.
        ignore_user_abort(true);
        @set_time_limit(300);
        // Add special html entities to the subject, name, and email.
        $_POST['subject'] = strtr(Util::htmlspecialchars($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
        $_POST['guestname'] = htmlspecialchars($_POST['guestname'], ENT_COMPAT, 'UTF-8');
        $_POST['email'] = htmlspecialchars($_POST['email'], ENT_COMPAT, 'UTF-8');
        // At this point, we want to make sure the subject isn't too long.
        if (Util::strlen($_POST['subject']) > 100) {
            $_POST['subject'] = Util::substr($_POST['subject'], 0, 100);
        }
        if (!empty($modSettings['mentions_enabled']) && !empty($_REQUEST['uid'])) {
            $query_params = array();
            $query_params['member_ids'] = array_unique(array_map('intval', $_REQUEST['uid']));
            require_once SUBSDIR . '/Members.subs.php';
            $mentioned_members = membersBy('member_ids', $query_params, true);
            $replacements = 0;
            $actually_mentioned = array();
            foreach ($mentioned_members as $member) {
                $_POST['message'] = str_replace('@' . $member['real_name'], '[member=' . $member['id_member'] . ']' . $member['real_name'] . '[/member]', $_POST['message'], $replacements);
                if ($replacements > 0) {
                    $actually_mentioned[] = $member['id_member'];
                }
            }
        }
        // Make the poll...
        if (isset($_REQUEST['poll'])) {
            // Make sure that the user has not entered a ridiculous number of options..
            if (empty($_POST['poll_max_votes']) || $_POST['poll_max_votes'] <= 0) {
                $_POST['poll_max_votes'] = 1;
            } elseif ($_POST['poll_max_votes'] > count($_POST['options'])) {
                $_POST['poll_max_votes'] = count($_POST['options']);
            } else {
                $_POST['poll_max_votes'] = (int) $_POST['poll_max_votes'];
            }
            $_POST['poll_expire'] = (int) $_POST['poll_expire'];
            $_POST['poll_expire'] = $_POST['poll_expire'] > 9999 ? 9999 : ($_POST['poll_expire'] < 0 ? 0 : $_POST['poll_expire']);
            // Just set it to zero if it's not there..
            if (!isset($_POST['poll_hide'])) {
                $_POST['poll_hide'] = 0;
            } else {
                $_POST['poll_hide'] = (int) $_POST['poll_hide'];
            }
            $_POST['poll_change_vote'] = isset($_POST['poll_change_vote']) ? 1 : 0;
            $_POST['poll_guest_vote'] = isset($_POST['poll_guest_vote']) ? 1 : 0;
            // Make sure guests are actually allowed to vote generally.
            if ($_POST['poll_guest_vote']) {
                require_once SUBSDIR . '/Members.subs.php';
                $allowedVoteGroups = groupsAllowedTo('poll_vote', $board);
                if (!in_array(-1, $allowedVoteGroups['allowed'])) {
                    $_POST['poll_guest_vote'] = 0;
                }
            }
            // If the user tries to set the poll too far in advance, don't let them.
            if (!empty($_POST['poll_expire']) && $_POST['poll_expire'] < 1) {
                fatal_lang_error('poll_range_error', false);
            } elseif (empty($_POST['poll_expire']) && $_POST['poll_hide'] == 2) {
                $_POST['poll_hide'] = 1;
            }
            // Clean up the question and answers.
            $_POST['question'] = htmlspecialchars($_POST['question'], ENT_COMPAT, 'UTF-8');
            $_POST['question'] = Util::substr($_POST['question'], 0, 255);
            $_POST['question'] = preg_replace('~&amp;#(\\d{4,5}|[2-9]\\d{2,4}|1[2-9]\\d);~', '&#$1;', $_POST['question']);
            $_POST['options'] = htmlspecialchars__recursive($_POST['options']);
            // Finally, make the poll.
            require_once SUBSDIR . '/Poll.subs.php';
            $id_poll = createPoll($_POST['question'], $user_info['id'], $_POST['guestname'], $_POST['poll_max_votes'], $_POST['poll_hide'], $_POST['poll_expire'], $_POST['poll_change_vote'], $_POST['poll_guest_vote'], $_POST['options']);
        } else {
            $id_poll = 0;
        }
        // ...or attach a new file...
        if (empty($ignore_temp) && $context['attachments']['can']['post'] && !empty($_SESSION['temp_attachments']) && empty($_POST['from_qr'])) {
            $attachIDs = array();
            foreach ($_SESSION['temp_attachments'] as $attachID => $attachment) {
                if ($attachID != 'initial_error' && strpos($attachID, 'post_tmp_' . $user_info['id']) === false) {
                    continue;
                }
                // If there was an initial error just show that message.
                if ($attachID == 'initial_error') {
                    unset($_SESSION['temp_attachments']);
                    break;
                }
                // No errors, then try to create the attachment
                if (empty($attachment['errors'])) {
                    // Load the attachmentOptions array with the data needed to create an attachment
                    $attachmentOptions = array('post' => isset($_REQUEST['msg']) ? $_REQUEST['msg'] : 0, 'poster' => $user_info['id'], 'name' => $attachment['name'], 'tmp_name' => $attachment['tmp_name'], 'size' => isset($attachment['size']) ? $attachment['size'] : 0, 'mime_type' => isset($attachment['type']) ? $attachment['type'] : '', 'id_folder' => isset($attachment['id_folder']) ? $attachment['id_folder'] : 0, 'approved' => !$modSettings['postmod_active'] || allowedTo('post_attachment'), 'errors' => array());
                    if (createAttachment($attachmentOptions)) {
                        $attachIDs[] = $attachmentOptions['id'];
                        if (!empty($attachmentOptions['thumb'])) {
                            $attachIDs[] = $attachmentOptions['thumb'];
                        }
                    }
                } else {
                    @unlink($attachment['tmp_name']);
                }
            }
            unset($_SESSION['temp_attachments']);
        }
        // Creating a new topic?
        $newTopic = empty($_REQUEST['msg']) && empty($topic);
        $_POST['icon'] = !empty($attachIDs) && $_POST['icon'] == 'xx' ? 'clip' : $_POST['icon'];
        // Collect all parameters for the creation or modification of a post.
        $msgOptions = array('id' => empty($_REQUEST['msg']) ? 0 : (int) $_REQUEST['msg'], 'subject' => $_POST['subject'], 'body' => $_POST['message'], 'icon' => preg_replace('~[\\./\\\\*:"\'<>]~', '', $_POST['icon']), 'smileys_enabled' => !isset($_POST['ns']), 'attachments' => empty($attachIDs) ? array() : $attachIDs, 'approved' => $becomesApproved);
        $topicOptions = array('id' => empty($topic) ? 0 : $topic, 'board' => $board, 'poll' => isset($_REQUEST['poll']) ? $id_poll : null, 'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null, 'sticky_mode' => isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics']) ? (int) $_POST['sticky'] : null, 'mark_as_read' => true, 'is_approved' => !$modSettings['postmod_active'] || empty($topic) || !empty($board_info['cur_topic_approved']));
        $posterOptions = array('id' => $user_info['id'], 'name' => $_POST['guestname'], 'email' => $_POST['email'], 'update_post_count' => !$user_info['is_guest'] && !isset($_REQUEST['msg']) && $board_info['posts_count']);
        // This is an already existing message. Edit it.
        if (!empty($_REQUEST['msg'])) {
            // Have admins allowed people to hide their screwups?
            if (time() - $msgInfo['poster_time'] > $modSettings['edit_wait_time'] || $user_info['id'] != $msgInfo['id_member']) {
                $msgOptions['modify_time'] = time();
                $msgOptions['modify_name'] = $user_info['name'];
            }
            // This will save some time...
            if (empty($approve_has_changed)) {
                unset($msgOptions['approved']);
            }
            modifyPost($msgOptions, $topicOptions, $posterOptions);
        } else {
            if (!empty($modSettings['enableFollowup']) && !empty($_REQUEST['followup'])) {
                $original_post = (int) $_REQUEST['followup'];
            }
            // We also have to fake the board:
            // if it's valid and it's not the current, let's forget about the "current" and load the new one
            if (!empty($new_board) && $board !== $new_board) {
                $board = $new_board;
                loadBoard();
                // Some details changed
                $topicOptions['board'] = $board;
                $topicOptions['is_approved'] = !$modSettings['postmod_active'] || empty($topic) || !empty($board_info['cur_topic_approved']);
                $posterOptions['update_post_count'] = !$user_info['is_guest'] && !isset($_REQUEST['msg']) && $board_info['posts_count'];
            }
            createPost($msgOptions, $topicOptions, $posterOptions);
            if (isset($topicOptions['id'])) {
                $topic = $topicOptions['id'];
            }
            if (!empty($modSettings['enableFollowup'])) {
                require_once SUBSDIR . '/FollowUps.subs.php';
                require_once SUBSDIR . '/Messages.subs.php';
                // Time to update the original message with a pointer to the new one
                if (!empty($original_post) && canAccessMessage($original_post)) {
                    linkMessages($original_post, $topic);
                }
            }
        }
        // If we had a draft for this, its time to remove it since it was just posted
        if (!empty($modSettings['drafts_enabled']) && !empty($_POST['id_draft'])) {
            deleteDrafts($_POST['id_draft'], $user_info['id']);
        }
        // Editing or posting an event?
        if (isset($_POST['calendar']) && (!isset($_REQUEST['eventid']) || $_REQUEST['eventid'] == -1)) {
            require_once SUBSDIR . '/Calendar.subs.php';
            // Make sure they can link an event to this post.
            canLinkEvent();
            // Insert the event.
            $eventOptions = array('id_board' => $board, 'id_topic' => $topic, 'title' => $_POST['evtitle'], 'member' => $user_info['id'], 'start_date' => sprintf('%04d-%02d-%02d', $_POST['year'], $_POST['month'], $_POST['day']), 'span' => isset($_POST['span']) && $_POST['span'] > 0 ? min((int) $modSettings['cal_maxspan'], (int) $_POST['span'] - 1) : 0);
            insertEvent($eventOptions);
        } elseif (isset($_POST['calendar'])) {
            $_REQUEST['eventid'] = (int) $_REQUEST['eventid'];
            // Validate the post...
            require_once SUBSDIR . '/Calendar.subs.php';
            validateEventPost();
            // If you're not allowed to edit any events, you have to be the poster.
            if (!allowedTo('calendar_edit_any')) {
                $event_poster = getEventPoster($_REQUEST['eventid']);
                // Silly hacker, Trix are for kids. ...probably trademarked somewhere, this is FAIR USE! (parody...)
                isAllowedTo('calendar_edit_' . ($event_poster == $user_info['id'] ? 'own' : 'any'));
            }
            // Delete it?
            if (isset($_REQUEST['deleteevent'])) {
                removeEvent($_REQUEST['eventid']);
            } else {
                $span = !empty($modSettings['cal_allowspan']) && !empty($_REQUEST['span']) ? min((int) $modSettings['cal_maxspan'], (int) $_REQUEST['span'] - 1) : 0;
                $start_time = mktime(0, 0, 0, (int) $_REQUEST['month'], (int) $_REQUEST['day'], (int) $_REQUEST['year']);
                $eventOptions = array('start_date' => strftime('%Y-%m-%d', $start_time), 'end_date' => strftime('%Y-%m-%d', $start_time + $span * 86400), 'title' => $_REQUEST['evtitle']);
                modifyEvent($_REQUEST['eventid'], $eventOptions);
            }
        }
        // Marking boards as read.
        // (You just posted and they will be unread.)
        if (!$user_info['is_guest']) {
            $board_list = !empty($board_info['parent_boards']) ? array_keys($board_info['parent_boards']) : array();
            // Returning to the topic?
            if (!empty($_REQUEST['goback'])) {
                $board_list[] = $board;
            }
            if (!empty($board_list)) {
                markBoardsRead($board_list, false, false);
            }
        }
        // Turn notification on or off.
        if (!empty($_POST['notify']) && allowedTo('mark_any_notify')) {
            setTopicNotification($user_info['id'], $topic, true);
        } elseif (!$newTopic) {
            setTopicNotification($user_info['id'], $topic, false);
        }
        // Log an act of moderation - modifying.
        if (!empty($moderationAction)) {
            logAction('modify', array('topic' => $topic, 'message' => (int) $_REQUEST['msg'], 'member' => $msgInfo['id_member'], 'board' => $board));
        }
        if (isset($_POST['lock']) && $_POST['lock'] != 2) {
            logAction(empty($_POST['lock']) ? 'unlock' : 'lock', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board']));
        }
        if (isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics'])) {
            logAction(empty($_POST['sticky']) ? 'unsticky' : 'sticky', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board']));
        }
        // Notify any members who have notification turned on for this topic/board - only do this if it's going to be approved(!)
        if ($becomesApproved) {
            require_once SUBSDIR . '/Notification.subs.php';
            if ($newTopic) {
                $notifyData = array('body' => $_POST['message'], 'subject' => $_POST['subject'], 'name' => $user_info['name'], 'poster' => $user_info['id'], 'msg' => $msgOptions['id'], 'board' => $board, 'topic' => $topic, 'signature' => isset($user_settings['signature']) ? $user_settings['signature'] : '');
                sendBoardNotifications($notifyData);
            } elseif (empty($_REQUEST['msg'])) {
                // Only send it to everyone if the topic is approved, otherwise just to the topic starter if they want it.
                if ($topic_info['approved']) {
                    sendNotifications($topic, 'reply');
                } else {
                    sendNotifications($topic, 'reply', array(), $topic_info['id_member_started']);
                }
            }
        }
        if (!empty($modSettings['mentions_enabled']) && !empty($actually_mentioned)) {
            require_once CONTROLLERDIR . '/Mentions.controller.php';
            $mentions = new Mentions_Controller();
            $mentions->setData(array('id_member' => $actually_mentioned, 'type' => 'men', 'id_msg' => $msgOptions['id'], 'status' => $becomesApproved ? 'new' : 'unapproved'));
            $mentions->action_add();
        }
        if ($board_info['num_topics'] == 0) {
            cache_put_data('board-' . $board, null, 120);
        }
        if (!empty($_POST['announce_topic'])) {
            redirectexit('action=announce;sa=selectgroup;topic=' . $topic . (!empty($_POST['move']) && allowedTo('move_any') ? ';move' : '') . (empty($_REQUEST['goback']) ? '' : ';goback'));
        }
        if (!empty($_POST['move']) && allowedTo('move_any')) {
            redirectexit('action=movetopic;topic=' . $topic . '.0' . (empty($_REQUEST['goback']) ? '' : ';goback'));
        }
        // Return to post if the mod is on.
        if (isset($_REQUEST['msg']) && !empty($_REQUEST['goback'])) {
            redirectexit('topic=' . $topic . '.msg' . $_REQUEST['msg'] . '#msg' . $_REQUEST['msg'], isBrowser('ie'));
        } elseif (!empty($_REQUEST['goback'])) {
            redirectexit('topic=' . $topic . '.new#new', isBrowser('ie'));
        } else {
            redirectexit('board=' . $board . '.0');
        }
    }
 /**
  * Send a personal message.
  */
 public function action_send2()
 {
     global $txt, $context, $user_info, $modSettings;
     // All the helpers we need
     require_once SUBSDIR . '/Auth.subs.php';
     require_once SUBSDIR . '/Post.subs.php';
     // PM Drafts enabled and needed?
     if ($context['drafts_pm_save'] && (isset($_POST['save_draft']) || isset($_POST['id_pm_draft']))) {
         require_once SUBSDIR . '/Drafts.subs.php';
     }
     loadLanguage('PersonalMessage', '', false);
     // Extract out the spam settings - it saves database space!
     list($modSettings['max_pm_recipients'], $modSettings['pm_posts_verification'], $modSettings['pm_posts_per_hour']) = explode(',', $modSettings['pm_spam_settings']);
     // Initialize the errors we're about to make.
     $post_errors = Error_Context::context('pm', 1);
     // Check whether we've gone over the limit of messages we can send per hour - fatal error if fails!
     if (!empty($modSettings['pm_posts_per_hour']) && !allowedTo(array('admin_forum', 'moderate_forum', 'send_mail')) && $user_info['mod_cache']['bq'] == '0=1' && $user_info['mod_cache']['gq'] == '0=1') {
         // How many have they sent this last hour?
         $pmCount = pmCount($user_info['id'], 3600);
         if (!empty($pmCount) && $pmCount >= $modSettings['pm_posts_per_hour']) {
             if (!isset($_REQUEST['xml'])) {
                 fatal_lang_error('pm_too_many_per_hour', true, array($modSettings['pm_posts_per_hour']));
             } else {
                 $post_errors->addError('pm_too_many_per_hour');
             }
         }
     }
     // If your session timed out, show an error, but do allow to re-submit.
     if (!isset($_REQUEST['xml']) && checkSession('post', '', false) != '') {
         $post_errors->addError('session_timeout');
     }
     $_REQUEST['subject'] = isset($_REQUEST['subject']) ? strtr(Util::htmltrim($_POST['subject']), array("\r" => '', "\n" => '', "\t" => '')) : '';
     $_REQUEST['to'] = empty($_POST['to']) ? empty($_GET['to']) ? '' : $_GET['to'] : $_POST['to'];
     $_REQUEST['bcc'] = empty($_POST['bcc']) ? empty($_GET['bcc']) ? '' : $_GET['bcc'] : $_POST['bcc'];
     // Route the input from the 'u' parameter to the 'to'-list.
     if (!empty($_POST['u'])) {
         $_POST['recipient_to'] = explode(',', $_POST['u']);
     }
     // Construct the list of recipients.
     $recipientList = array();
     $namedRecipientList = array();
     $namesNotFound = array();
     foreach (array('to', 'bcc') as $recipientType) {
         // First, let's see if there's user ID's given.
         $recipientList[$recipientType] = array();
         if (!empty($_POST['recipient_' . $recipientType]) && is_array($_POST['recipient_' . $recipientType])) {
             foreach ($_POST['recipient_' . $recipientType] as $recipient) {
                 $recipientList[$recipientType][] = (int) $recipient;
             }
         }
         // Are there also literal names set?
         if (!empty($_REQUEST[$recipientType])) {
             // We're going to take out the "s anyway ;).
             $recipientString = strtr($_REQUEST[$recipientType], array('\\"' => '"'));
             preg_match_all('~"([^"]+)"~', $recipientString, $matches);
             $namedRecipientList[$recipientType] = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $recipientString))));
             // Clean any literal names entered
             foreach ($namedRecipientList[$recipientType] as $index => $recipient) {
                 if (strlen(trim($recipient)) > 0) {
                     $namedRecipientList[$recipientType][$index] = Util::htmlspecialchars(Util::strtolower(trim($recipient)));
                 } else {
                     unset($namedRecipientList[$recipientType][$index]);
                 }
             }
             // Now see if we can resolove the entered name to an actual user
             if (!empty($namedRecipientList[$recipientType])) {
                 $foundMembers = findMembers($namedRecipientList[$recipientType]);
                 // Assume all are not found, until proven otherwise.
                 $namesNotFound[$recipientType] = $namedRecipientList[$recipientType];
                 // Make sure we only have each member listed once, incase they did not use the select list
                 foreach ($foundMembers as $member) {
                     $testNames = array(Util::strtolower($member['username']), Util::strtolower($member['name']), Util::strtolower($member['email']));
                     if (count(array_intersect($testNames, $namedRecipientList[$recipientType])) !== 0) {
                         $recipientList[$recipientType][] = $member['id'];
                         // Get rid of this username, since we found it.
                         $namesNotFound[$recipientType] = array_diff($namesNotFound[$recipientType], $testNames);
                     }
                 }
             }
         }
         // Selected a recipient to be deleted? Remove them now.
         if (!empty($_POST['delete_recipient'])) {
             $recipientList[$recipientType] = array_diff($recipientList[$recipientType], array((int) $_POST['delete_recipient']));
         }
         // Make sure we don't include the same name twice
         $recipientList[$recipientType] = array_unique($recipientList[$recipientType]);
     }
     // Are we changing the recipients some how?
     $is_recipient_change = !empty($_POST['delete_recipient']) || !empty($_POST['to_submit']) || !empty($_POST['bcc_submit']);
     // Check if there's at least one recipient.
     if (empty($recipientList['to']) && empty($recipientList['bcc'])) {
         $post_errors->addError('no_to');
     }
     // Make sure that we remove the members who did get it from the screen.
     if (!$is_recipient_change) {
         foreach (array_keys($recipientList) as $recipientType) {
             if (!empty($namesNotFound[$recipientType])) {
                 $post_errors->addError('bad_' . $recipientType);
                 // Since we already have a post error, remove the previous one.
                 $post_errors->removeError('no_to');
                 foreach ($namesNotFound[$recipientType] as $name) {
                     $context['send_log']['failed'][] = sprintf($txt['pm_error_user_not_found'], $name);
                 }
             }
         }
     }
     // Did they make any mistakes like no subject or message?
     if ($_REQUEST['subject'] == '') {
         $post_errors->addError('no_subject');
     }
     if (!isset($_REQUEST['message']) || $_REQUEST['message'] == '') {
         $post_errors->addError('no_message');
     } elseif (!empty($modSettings['max_messageLength']) && Util::strlen($_REQUEST['message']) > $modSettings['max_messageLength']) {
         $post_errors->addError('long_message');
     } else {
         // Preparse the message.
         $message = $_REQUEST['message'];
         preparsecode($message);
         // Make sure there's still some content left without the tags.
         if (Util::htmltrim(strip_tags(parse_bbc(Util::htmlspecialchars($message, ENT_QUOTES), false), '<img>')) === '' && (!allowedTo('admin_forum') || strpos($message, '[html]') === false)) {
             $post_errors->addError('no_message');
         }
     }
     // Wrong verification code?
     if (!$user_info['is_admin'] && !isset($_REQUEST['xml']) && !empty($modSettings['pm_posts_verification']) && $user_info['posts'] < $modSettings['pm_posts_verification']) {
         require_once SUBSDIR . '/VerificationControls.class.php';
         $verificationOptions = array('id' => 'pm');
         $context['require_verification'] = create_control_verification($verificationOptions, true);
         if (is_array($context['require_verification'])) {
             foreach ($context['require_verification'] as $error) {
                 $post_errors->addError($error);
             }
         }
     }
     // If they made any errors, give them a chance to make amends.
     if ($post_errors->hasErrors() && !$is_recipient_change && !isset($_REQUEST['preview']) && !isset($_REQUEST['xml'])) {
         return messagePostError($namedRecipientList, $recipientList);
     }
     // Want to take a second glance before you send?
     if (isset($_REQUEST['preview'])) {
         // Set everything up to be displayed.
         $context['preview_subject'] = Util::htmlspecialchars($_REQUEST['subject']);
         $context['preview_message'] = Util::htmlspecialchars($_REQUEST['message'], ENT_QUOTES, 'UTF-8', true);
         preparsecode($context['preview_message'], true);
         // Parse out the BBC if it is enabled.
         $context['preview_message'] = parse_bbc($context['preview_message']);
         // Censor, as always.
         censorText($context['preview_subject']);
         censorText($context['preview_message']);
         // Set a descriptive title.
         $context['page_title'] = $txt['preview'] . ' - ' . $context['preview_subject'];
         // Pretend they messed up but don't ignore if they really did :P.
         return messagePostError($namedRecipientList, $recipientList);
     } elseif ($is_recipient_change) {
         // Maybe we couldn't find one?
         foreach ($namesNotFound as $recipientType => $names) {
             $post_errors->addError('bad_' . $recipientType);
             foreach ($names as $name) {
                 $context['send_log']['failed'][] = sprintf($txt['pm_error_user_not_found'], $name);
             }
         }
         return messagePostError($namedRecipientList, $recipientList);
     }
     // Want to save this as a draft and think about it some more?
     if ($context['drafts_pm_save'] && isset($_POST['save_draft'])) {
         savePMDraft($recipientList);
         return messagePostError($namedRecipientList, $recipientList);
     } elseif (!empty($modSettings['max_pm_recipients']) && count($recipientList['to']) + count($recipientList['bcc']) > $modSettings['max_pm_recipients'] && !allowedTo(array('moderate_forum', 'send_mail', 'admin_forum'))) {
         $context['send_log'] = array('sent' => array(), 'failed' => array(sprintf($txt['pm_too_many_recipients'], $modSettings['max_pm_recipients'])));
         return messagePostError($namedRecipientList, $recipientList);
     }
     // Protect from message spamming.
     spamProtection('pm');
     // Prevent double submission of this form.
     checkSubmitOnce('check');
     // Finally do the actual sending of the PM.
     if (!empty($recipientList['to']) || !empty($recipientList['bcc'])) {
         $context['send_log'] = sendpm($recipientList, $_REQUEST['subject'], $_REQUEST['message'], true, null, !empty($_REQUEST['pm_head']) ? (int) $_REQUEST['pm_head'] : 0);
     } else {
         $context['send_log'] = array('sent' => array(), 'failed' => array());
     }
     // Mark the message as "replied to".
     if (!empty($context['send_log']['sent']) && !empty($_REQUEST['replied_to']) && isset($_REQUEST['f']) && $_REQUEST['f'] == 'inbox') {
         require_once SUBSDIR . '/PersonalMessage.subs.php';
         setPMRepliedStatus($user_info['id'], (int) $_REQUEST['replied_to']);
     }
     // If one or more of the recipients were invalid, go back to the post screen with the failed usernames.
     if (!empty($context['send_log']['failed'])) {
         return messagePostError($namesNotFound, array('to' => array_intersect($recipientList['to'], $context['send_log']['failed']), 'bcc' => array_intersect($recipientList['bcc'], $context['send_log']['failed'])));
     }
     // Message sent successfully?
     if (!empty($context['send_log']) && empty($context['send_log']['failed'])) {
         $context['current_label_redirect'] = $context['current_label_redirect'] . ';done=sent';
         // If we had a PM draft for this one, then its time to remove it since it was just sent
         if ($context['drafts_pm_save'] && !empty($_POST['id_pm_draft'])) {
             deleteDrafts($_POST['id_pm_draft'], $user_info['id']);
         }
     }
     // Go back to the where they sent from, if possible...
     redirectexit($context['current_label_redirect']);
 }
示例#14
0
 /**
  * Actually logs you in.
  *
  * What it does:
  * - checks credentials and checks that login was successful.
  * - it employs protection against a specific IP or user trying to brute force
  *   a login to an account.
  * - upgrades password encryption on login, if necessary.
  * - after successful login, redirects you to $_SESSION['login_url'].
  * - accessed from ?action=login2, by forms.
  *
  * On error, uses the same templates action_login() uses.
  */
 public function action_login2()
 {
     global $txt, $scripturl, $user_info, $user_settings, $modSettings, $context, $sc;
     // Load cookie authentication and all stuff.
     require_once SUBSDIR . '/Auth.subs.php';
     // Beyond this point you are assumed to be a guest trying to login.
     if (!$user_info['is_guest']) {
         redirectexit();
     }
     // Are you guessing with a script?
     checkSession('post');
     validateToken('login');
     spamProtection('login');
     // Set the login_url if it's not already set (but careful not to send us to an attachment).
     if (empty($_SESSION['login_url']) && isset($_SESSION['old_url']) && strpos($_SESSION['old_url'], 'dlattach') === false && preg_match('~(board|topic)[=,]~', $_SESSION['old_url']) != 0 || isset($_GET['quicklogin']) && isset($_SESSION['old_url']) && strpos($_SESSION['old_url'], 'login') === false) {
         $_SESSION['login_url'] = $_SESSION['old_url'];
     }
     // Been guessing a lot, haven't we?
     if (isset($_SESSION['failed_login']) && $_SESSION['failed_login'] >= $modSettings['failed_login_threshold'] * 3) {
         fatal_lang_error('login_threshold_fail', 'critical');
     }
     // Set up the cookie length.  (if it's invalid, just fall through and use the default.)
     if (isset($_POST['cookieneverexp']) || !empty($_POST['cookielength']) && $_POST['cookielength'] == -1) {
         $modSettings['cookieTime'] = 3153600;
     } elseif (!empty($_POST['cookielength']) && ($_POST['cookielength'] >= 1 || $_POST['cookielength'] <= 525600)) {
         $modSettings['cookieTime'] = (int) $_POST['cookielength'];
     }
     loadLanguage('Login');
     // Load the template stuff
     loadTemplate('Login');
     loadJavascriptFile('sha256.js', array('defer' => true));
     $context['sub_template'] = 'login';
     // Set up the default/fallback stuff.
     $context['default_username'] = isset($_POST['user']) ? preg_replace('~&amp;#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', htmlspecialchars($_POST['user'], ENT_COMPAT, 'UTF-8')) : '';
     $context['default_password'] = '';
     $context['never_expire'] = $modSettings['cookieTime'] == 525600 || $modSettings['cookieTime'] == 3153600;
     $context['login_errors'] = array($txt['error_occurred']);
     $context['page_title'] = $txt['login'];
     // Add the login chain to the link tree.
     $context['linktree'][] = array('url' => $scripturl . '?action=login', 'name' => $txt['login']);
     // This is an OpenID login. Let's validate...
     if (!empty($_POST['openid_identifier']) && !empty($modSettings['enableOpenID'])) {
         require_once SUBSDIR . '/OpenID.subs.php';
         $open_id = new OpenID();
         if ($open_id->validate($_POST['openid_identifier']) !== 'no_data') {
             return $open_id;
         } else {
             $context['login_errors'] = array($txt['openid_not_found']);
             return;
         }
     }
     // You forgot to type your username, dummy!
     if (!isset($_POST['user']) || $_POST['user'] == '') {
         $context['login_errors'] = array($txt['need_username']);
         return;
     }
     // No one needs a username that long, plus we only support 80 chars in the db
     if (Util::strlen($_POST['user']) > 80) {
         $_POST['user'] = Util::substr($_POST['user'], 0, 80);
     }
     // Can't use a password > 64 characters sorry, to long and only good for a DoS attack
     // Plus we expect a 64 character one from SHA-256
     if (isset($_POST['passwrd']) && strlen($_POST['passwrd']) > 64 || isset($_POST['hash_passwrd']) && strlen($_POST['hash_passwrd']) > 64) {
         $context['login_errors'] = array($txt['improper_password']);
         return;
     }
     // Hmm... maybe 'admin' will login with no password. Uhh... NO!
     if ((!isset($_POST['passwrd']) || $_POST['passwrd'] == '') && (!isset($_POST['hash_passwrd']) || strlen($_POST['hash_passwrd']) != 64)) {
         $context['login_errors'] = array($txt['no_password']);
         return;
     }
     // No funky symbols either.
     if (preg_match('~[<>&"\'=\\\\]~', preg_replace('~(&#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~', '', $_POST['user'])) != 0) {
         $context['login_errors'] = array($txt['error_invalid_characters_username']);
         return;
     }
     // Are we using any sort of integration to validate the login?
     if (in_array('retry', call_integration_hook('integrate_validate_login', array($_POST['user'], isset($_POST['hash_passwrd']) && strlen($_POST['hash_passwrd']) == 40 ? $_POST['hash_passwrd'] : null, $modSettings['cookieTime'])), true)) {
         $context['login_errors'] = array($txt['login_hash_error']);
         $context['disable_login_hashing'] = true;
         return;
     }
     // Find them... if we can
     $user_settings = loadExistingMember($_POST['user']);
     // Let them try again, it didn't match anything...
     if (empty($user_settings)) {
         $context['login_errors'] = array($txt['username_no_exist']);
         return;
     }
     // Figure out if the password is using Elk's encryption - if what they typed is right.
     if (isset($_POST['hash_passwrd']) && strlen($_POST['hash_passwrd']) === 64) {
         // Challenge what was passed
         $valid_password = validateLoginPassword($_POST['hash_passwrd'], $user_settings['passwd']);
         // Let them in
         if ($valid_password) {
             $sha_passwd = $_POST['hash_passwrd'];
             $valid_password = true;
         } elseif (preg_match('/^[0-9a-f]{40}$/i', $user_settings['passwd']) && isset($_POST['old_hash_passwrd']) && $_POST['old_hash_passwrd'] === hash('sha1', $user_settings['passwd'] . $sc)) {
             // Old password passed, turn off hashing and ask for it again so we can update the db to something more secure.
             $context['login_errors'] = array($txt['login_hash_error']);
             $context['disable_login_hashing'] = true;
             unset($user_settings);
             return;
         } else {
             // Don't allow this!
             validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood']);
             $_SESSION['failed_login'] = isset($_SESSION['failed_login']) ? $_SESSION['failed_login'] + 1 : 1;
             // To many tries, maybe they need a reminder
             if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold']) {
                 redirectexit('action=reminder');
             } else {
                 log_error($txt['incorrect_password'] . ' - <span class="remove">' . $user_settings['member_name'] . '</span>', 'user');
                 // Wrong password, lets enable plain text responses in case form hashing is causing problems
                 $context['disable_login_hashing'] = true;
                 $context['login_errors'] = array($txt['incorrect_password']);
                 unset($user_settings);
                 return;
             }
         }
     } else {
         // validateLoginPassword will hash this like the form normally would and check its valid
         $sha_passwd = $_POST['passwrd'];
         $valid_password = validateLoginPassword($sha_passwd, $user_settings['passwd'], $user_settings['member_name']);
     }
     // Bad password!  Thought you could fool the database?!
     if ($valid_password === false) {
         // Let's be cautious, no hacking please. thanx.
         validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood']);
         // Maybe we were too hasty... let's try some other authentication methods.
         $other_passwords = $this->_other_passwords($user_settings);
         // Whichever encryption it was using, let's make it use ElkArte's now ;).
         if (in_array($user_settings['passwd'], $other_passwords)) {
             $user_settings['passwd'] = validateLoginPassword($sha_passwd, '', '', true);
             $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4);
             // Update the password hash and set up the salt.
             updateMemberData($user_settings['id_member'], array('passwd' => $user_settings['passwd'], 'password_salt' => $user_settings['password_salt'], 'passwd_flood' => ''));
         } else {
             // They've messed up again - keep a count to see if they need a hand.
             $_SESSION['failed_login'] = isset($_SESSION['failed_login']) ? $_SESSION['failed_login'] + 1 : 1;
             // Hmm... don't remember it, do you?  Here, try the password reminder ;).
             if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold']) {
                 redirectexit('action=reminder');
             } else {
                 // Log an error so we know that it didn't go well in the error log.
                 log_error($txt['incorrect_password'] . ' - <span class="remove">' . $user_settings['member_name'] . '</span>', 'user');
                 $context['login_errors'] = array($txt['incorrect_password']);
                 return;
             }
         }
     } elseif (!empty($user_settings['passwd_flood'])) {
         // Let's be sure they weren't a little hacker.
         validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood'], true);
         // If we got here then we can reset the flood counter.
         updateMemberData($user_settings['id_member'], array('passwd_flood' => ''));
     }
     // Correct password, but they've got no salt; fix it!
     if ($user_settings['password_salt'] == '') {
         $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4);
         updateMemberData($user_settings['id_member'], array('password_salt' => $user_settings['password_salt']));
     }
     // Check their activation status.
     if (!checkActivation()) {
         return;
     }
     doLogin();
 }
示例#15
0
function registerMember(&$regOptions)
{
    global $scripturl, $txt, $modSettings, $db_prefix, $context, $sourcedir;
    global $user_info, $options, $settings, $func;
    loadLanguage('Login');
    // We'll need some external functions.
    require_once $sourcedir . '/Subs-Auth.php';
    require_once $sourcedir . '/Subs-Post.php';
    // Registration from the admin center, let them sweat a little more.
    if ($regOptions['interface'] == 'admin') {
        is_not_guest();
        isAllowedTo('moderate_forum');
    } elseif ($regOptions['interface'] == 'guest') {
        spamProtection('register');
        // You cannot register twice...
        if (empty($user_info['is_guest'])) {
            redirectexit();
        }
        // Make sure they didn't just register with this session.
        if (!empty($_SESSION['just_registered']) && empty($modSettings['disableRegisterCheck'])) {
            fatal_lang_error('register_only_once', false);
        }
    }
    // No name?!  How can you register with no name?
    if (empty($regOptions['username'])) {
        fatal_lang_error(37, false);
    }
    // Spaces and other odd characters are evil...
    $regOptions['username'] = preg_replace('~[\\t\\n\\r\\x0B\\0' . ($context['utf8'] ? $context['server']['complex_preg_chars'] ? '\\x{A0}' : pack('C*', 0xc2, 0xa0) : '\\xA0') . ']+~' . ($context['utf8'] ? 'u' : ''), ' ', $regOptions['username']);
    // Don't use too long a name.
    if ($func['strlen']($regOptions['username']) > 25) {
        $regOptions['username'] = $func['htmltrim']($func['substr']($regOptions['username'], 0, 25));
    }
    // Only these characters are permitted.
    if (preg_match('~[<>&"\'=\\\\]~', $regOptions['username']) != 0 || $regOptions['username'] == '_' || $regOptions['username'] == '|' || strpos($regOptions['username'], '[code') !== false || strpos($regOptions['username'], '[/code') !== false) {
        fatal_lang_error(240, false);
    }
    if (stristr($regOptions['username'], $txt[28]) !== false) {
        fatal_lang_error(244, true, array($txt[28]));
    }
    // !!! Separate the sprintf?
    if (empty($regOptions['email']) || preg_match('~^[0-9A-Za-z=_+\\-/][0-9A-Za-z=_\'+\\-/\\.]*@[\\w\\-]+(\\.[\\w\\-]+)*(\\.[\\w]{2,6})$~', stripslashes($regOptions['email'])) === 0 || strlen(stripslashes($regOptions['email'])) > 255) {
        fatal_error(sprintf($txt[500], $regOptions['username']), false);
    }
    if (!empty($regOptions['check_reserved_name']) && isReservedName($regOptions['username'], 0, false)) {
        if ($regOptions['password'] == 'chocolate cake') {
            fatal_error('Sorry, I don\'t take bribes... you\'ll need to come up with a different name.', false);
        }
        fatal_error('(' . htmlspecialchars($regOptions['username']) . ') ' . $txt[473], false);
    }
    // Generate a validation code if it's supposed to be emailed.
    $validation_code = '';
    if ($regOptions['require'] == 'activation') {
        $validation_code = generateValidationCode();
    }
    // If you haven't put in a password generated one.
    if ($regOptions['interface'] == 'admin' && $regOptions['password'] == '') {
        mt_srand(time() + 1277);
        $regOptions['password'] = generateValidationCode();
        $regOptions['password_check'] = $regOptions['password'];
    } elseif ($regOptions['password'] != $regOptions['password_check']) {
        fatal_lang_error(213, false);
    }
    // That's kind of easy to guess...
    if ($regOptions['password'] == '') {
        fatal_lang_error(91, false);
    }
    // Now perform hard password validation as required.
    if (!empty($regOptions['check_password_strength'])) {
        $passwordError = validatePassword($regOptions['password'], $regOptions['username'], array($regOptions['email']));
        // Password isn't legal?
        if ($passwordError != null) {
            fatal_lang_error('profile_error_password_' . $passwordError, false);
        }
    }
    // You may not be allowed to register this email.
    if (!empty($regOptions['check_email_ban'])) {
        isBannedEmail($regOptions['email'], 'cannot_register', $txt['ban_register_prohibited']);
    }
    // Check if the email address is in use.
    $request = db_query("\n\t\tSELECT ID_MEMBER\n\t\tFROM {$db_prefix}members\n\t\tWHERE emailAddress = '{$regOptions['email']}'\n\t\t\tOR emailAddress = '{$regOptions['username']}'\n\t\tLIMIT 1", __FILE__, __LINE__);
    // !!! Separate the sprintf?
    if (mysql_num_rows($request) != 0) {
        fatal_error(sprintf($txt[730], htmlspecialchars($regOptions['email'])), false);
    }
    mysql_free_result($request);
    // Some of these might be overwritten. (the lower ones that are in the arrays below.)
    $regOptions['register_vars'] = array('memberName' => "'{$regOptions['username']}'", 'emailAddress' => "'{$regOptions['email']}'", 'passwd' => '\'' . sha1(strtolower($regOptions['username']) . $regOptions['password']) . '\'', 'passwordSalt' => '\'' . substr(md5(mt_rand()), 0, 4) . '\'', 'posts' => 0, 'dateRegistered' => time(), 'memberIP' => "'{$user_info['ip']}'", 'memberIP2' => "'{$_SERVER['BAN_CHECK_IP']}'", 'validation_code' => "'{$validation_code}'", 'realName' => "'{$regOptions['username']}'", 'personalText' => '\'' . addslashes($modSettings['default_personalText']) . '\'', 'pm_email_notify' => 1, 'ID_THEME' => 0, 'ID_POST_GROUP' => 4, 'lngfile' => "''", 'buddy_list' => "''", 'pm_ignore_list' => "''", 'messageLabels' => "''", 'personalText' => "''", 'websiteTitle' => "''", 'websiteUrl' => "''", 'location' => "''", 'ICQ' => "''", 'AIM' => "''", 'YIM' => "''", 'MSN' => "''", 'timeFormat' => "''", 'signature' => "''", 'avatar' => "''", 'usertitle' => "''", 'secretQuestion' => "''", 'secretAnswer' => "''", 'additionalGroups' => "''", 'smileySet' => "''");
    // Setup the activation status on this new account so it is correct - firstly is it an under age account?
    if ($regOptions['require'] == 'coppa') {
        $regOptions['register_vars']['is_activated'] = 5;
        // !!! This should be changed.  To what should be it be changed??
        $regOptions['register_vars']['validation_code'] = "''";
    } elseif ($regOptions['require'] == 'nothing') {
        $regOptions['register_vars']['is_activated'] = 1;
    } elseif ($regOptions['require'] == 'activation') {
        $regOptions['register_vars']['is_activated'] = 0;
    } else {
        $regOptions['register_vars']['is_activated'] = 3;
    }
    if (isset($regOptions['memberGroup'])) {
        // Make sure the ID_GROUP will be valid, if this is an administator.
        $regOptions['register_vars']['ID_GROUP'] = $regOptions['memberGroup'] == 1 && !allowedTo('admin_forum') ? 0 : $regOptions['memberGroup'];
        // Check if this group is assignable.
        $unassignableGroups = array(-1, 3);
        $request = db_query("\n\t\t\tSELECT ID_GROUP\n\t\t\tFROM {$db_prefix}membergroups\n\t\t\tWHERE minPosts != -1", __FILE__, __LINE__);
        while ($row = mysql_fetch_assoc($request)) {
            $unassignableGroups[] = $row['ID_GROUP'];
        }
        mysql_free_result($request);
        if (in_array($regOptions['register_vars']['ID_GROUP'], $unassignableGroups)) {
            $regOptions['register_vars']['ID_GROUP'] = 0;
        }
    }
    // Integrate optional member settings to be set.
    if (!empty($regOptions['extra_register_vars'])) {
        foreach ($regOptions['extra_register_vars'] as $var => $value) {
            $regOptions['register_vars'][$var] = $value;
        }
    }
    // Integrate optional user theme options to be set.
    $theme_vars = array();
    if (!empty($regOptions['theme_vars'])) {
        foreach ($regOptions['theme_vars'] as $var => $value) {
            $theme_vars[$var] = $value;
        }
    }
    // Call an optional function to validate the users' input.
    if (isset($modSettings['integrate_register']) && function_exists($modSettings['integrate_register'])) {
        $modSettings['integrate_register']($regOptions, $theme_vars);
    }
    // Register them into the database.
    db_query("\n\t\tINSERT INTO {$db_prefix}members\n\t\t\t(" . implode(', ', array_keys($regOptions['register_vars'])) . ")\n\t\tVALUES (" . implode(', ', $regOptions['register_vars']) . ')', __FILE__, __LINE__);
    $memberID = db_insert_id();
    // Grab their real name and send emails using it.
    $realName = substr($regOptions['register_vars']['realName'], 1, -1);
    // Update the number of members and latest member's info - and pass the name, but remove the 's.
    updateStats('member', $memberID, $realName);
    // Theme variables too?
    if (!empty($theme_vars)) {
        $setString = '';
        foreach ($theme_vars as $var => $val) {
            $setString .= "\n\t\t\t\t({$memberID}, SUBSTRING('{$var}', 1, 255), SUBSTRING('{$val}', 1, 65534)),";
        }
        db_query("\n\t\t\tINSERT INTO {$db_prefix}themes\n\t\t\t\t(ID_MEMBER, variable, value)\n\t\t\tVALUES " . substr($setString, 0, -1), __FILE__, __LINE__);
    }
    // If it's enabled, increase the registrations for today.
    trackStats(array('registers' => '+'));
    // Administrative registrations are a bit different...
    if ($regOptions['interface'] == 'admin') {
        if ($regOptions['require'] == 'activation') {
            $email_message = 'register_activate_message';
        } elseif (!empty($regOptions['send_welcome_email'])) {
            $email_message = 'register_immediate_message';
        }
        if (isset($email_message)) {
            sendmail($regOptions['email'], $txt['register_subject'], sprintf($txt[$email_message], $realName, $regOptions['username'], $regOptions['password'], $validation_code, $scripturl . '?action=activate;u=' . $memberID . ';code=' . $validation_code));
        }
        // All admins are finished here.
        return $memberID;
    }
    // Can post straight away - welcome them to your fantastic community...
    if ($regOptions['require'] == 'nothing') {
        if (!empty($regOptions['send_welcome_email'])) {
            sendmail($regOptions['email'], $txt['register_subject'], sprintf($txt['register_immediate_message'], $realName, $regOptions['username'], $regOptions['password']));
        }
        // Send admin their notification.
        adminNotify('standard', $memberID, $regOptions['username']);
    } elseif ($regOptions['require'] == 'activation' || $regOptions['require'] == 'coppa') {
        sendmail($regOptions['email'], $txt['register_subject'], sprintf($txt['register_activate_message'], $realName, $regOptions['username'], $regOptions['password'], $validation_code, $scripturl . '?action=activate;u=' . $memberID . ';code=' . $validation_code));
    } else {
        sendmail($regOptions['email'], $txt['register_subject'], sprintf($txt['register_pending_message'], $realName, $regOptions['username'], $regOptions['password']));
        // Admin gets informed here...
        adminNotify('approval', $memberID, $regOptions['username']);
    }
    // Okay, they're for sure registered... make sure the session is aware of this for security. (Just married :P!)
    $_SESSION['just_registered'] = 1;
    return $memberID;
}
示例#16
0
文件: Post.php 项目: alencarmo/OCF
function Post2()
{
    global $board, $topic, $txt, $db_prefix, $modSettings, $sourcedir, $context;
    global $ID_MEMBER, $user_info, $board_info, $options, $func;
    // Previewing? Go back to start.
    if (isset($_REQUEST['preview'])) {
        return Post();
    }
    // Prevent double submission of this form.
    checkSubmitOnce('check');
    // No errors as yet.
    $post_errors = array();
    // If the session has timed out, let the user re-submit their form.
    if (checkSession('post', '', false) != '') {
        $post_errors[] = 'session_timeout';
    }
    require_once $sourcedir . '/Subs-Post.php';
    loadLanguage('Post');
    // Replying to a topic?
    if (!empty($topic) && !isset($_REQUEST['msg'])) {
        $request = db_query("\n\t\t\tSELECT t.locked, t.isSticky, t.ID_POLL, t.numReplies, m.ID_MEMBER\n\t\t\tFROM ({$db_prefix}topics AS t, {$db_prefix}messages AS m)\n\t\t\tWHERE t.ID_TOPIC = {$topic}\n\t\t\t\tAND m.ID_MSG = t.ID_FIRST_MSG\n\t\t\tLIMIT 1", __FILE__, __LINE__);
        list($tmplocked, $tmpstickied, $pollID, $numReplies, $ID_MEMBER_POSTER) = mysql_fetch_row($request);
        mysql_free_result($request);
        // Don't allow a post if it's locked.
        if ($tmplocked != 0 && !allowedTo('moderate_board')) {
            fatal_lang_error(90, false);
        }
        // Sorry, multiple polls aren't allowed... yet.  You should stop giving me ideas :P.
        if (isset($_REQUEST['poll']) && $pollID > 0) {
            unset($_REQUEST['poll']);
        }
        if ($ID_MEMBER_POSTER != $ID_MEMBER) {
            isAllowedTo('post_reply_any');
        } elseif (!allowedTo('post_reply_any')) {
            isAllowedTo('post_reply_own');
        }
        if (isset($_POST['lock'])) {
            // Nothing is changed to the lock.
            if (empty($tmplocked) && empty($_POST['lock']) || !empty($_POST['lock']) && !empty($tmplocked)) {
                unset($_POST['lock']);
            } elseif (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $ID_MEMBER != $ID_MEMBER_POSTER) {
                unset($_POST['lock']);
            } elseif (!allowedTo('lock_any')) {
                // You cannot override a moderator lock.
                if ($tmplocked == 1) {
                    unset($_POST['lock']);
                } else {
                    $_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
                }
            } else {
                $_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
            }
        }
        // So you wanna (un)sticky this...let's see.
        if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || $_POST['sticky'] == $tmpstickied || !allowedTo('make_sticky'))) {
            unset($_POST['sticky']);
        }
        // If the number of replies has changed, if the setting is enabled, go back to Post() - which handles the error.
        $newReplies = isset($_POST['num_replies']) && $numReplies > $_POST['num_replies'] ? $numReplies - $_POST['num_replies'] : 0;
        if (empty($options['no_new_reply_warning']) && !empty($newReplies)) {
            $_REQUEST['preview'] = true;
            return Post();
        }
        $posterIsGuest = $user_info['is_guest'];
    } elseif (empty($topic)) {
        if (!isset($_REQUEST['poll']) || $modSettings['pollMode'] != '1') {
            isAllowedTo('post_new');
        }
        if (isset($_POST['lock'])) {
            // New topics are by default not locked.
            if (empty($_POST['lock'])) {
                unset($_POST['lock']);
            } elseif (!allowedTo(array('lock_any', 'lock_own'))) {
                unset($_POST['lock']);
            } else {
                $_POST['lock'] = allowedTo('lock_any') ? 1 : 2;
            }
        }
        if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || empty($_POST['sticky']) || !allowedTo('make_sticky'))) {
            unset($_POST['sticky']);
        }
        $posterIsGuest = $user_info['is_guest'];
    } elseif (isset($_REQUEST['msg']) && !empty($topic)) {
        $_REQUEST['msg'] = (int) $_REQUEST['msg'];
        $request = db_query("\n\t\t\tSELECT\n\t\t\t\tm.ID_MEMBER, m.posterName, m.posterEmail, m.posterTime, \n\t\t\t\tt.ID_FIRST_MSG, t.locked, t.isSticky, t.ID_MEMBER_STARTED AS ID_MEMBER_POSTER\n\t\t\tFROM ({$db_prefix}messages AS m, {$db_prefix}topics AS t)\n\t\t\tWHERE m.ID_MSG = {$_REQUEST['msg']}\n\t\t\t\tAND t.ID_TOPIC = {$topic}\n\t\t\tLIMIT 1", __FILE__, __LINE__);
        if (mysql_num_rows($request) == 0) {
            fatal_lang_error('smf272', false);
        }
        $row = mysql_fetch_assoc($request);
        mysql_free_result($request);
        if (!empty($row['locked']) && !allowedTo('moderate_board')) {
            fatal_lang_error(90, false);
        }
        if (isset($_POST['lock'])) {
            // Nothing changes to the lock status.
            if (empty($_POST['lock']) && empty($row['locked']) || !empty($_POST['lock']) && !empty($row['locked'])) {
                unset($_POST['lock']);
            } elseif (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $ID_MEMBER != $row['ID_MEMBER_POSTER']) {
                unset($_POST['lock']);
            } elseif (!allowedTo('lock_any')) {
                // You're not allowed to break a moderator's lock.
                if ($row['locked'] == 1) {
                    unset($_POST['lock']);
                } else {
                    $_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
                }
            } else {
                $_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
            }
        }
        // Change the sticky status of this topic?
        if (isset($_POST['sticky']) && (!allowedTo('make_sticky') || $_POST['sticky'] == $row['isSticky'])) {
            unset($_POST['sticky']);
        }
        if ($row['ID_MEMBER'] == $ID_MEMBER && !allowedTo('modify_any')) {
            if (!empty($modSettings['edit_disable_time']) && $row['posterTime'] + ($modSettings['edit_disable_time'] + 5) * 60 < time()) {
                fatal_lang_error('modify_post_time_passed', false);
            } elseif ($row['ID_MEMBER_POSTER'] == $ID_MEMBER && !allowedTo('modify_own')) {
                isAllowedTo('modify_replies');
            } else {
                isAllowedTo('modify_own');
            }
        } elseif ($row['ID_MEMBER_POSTER'] == $ID_MEMBER && !allowedTo('modify_any')) {
            isAllowedTo('modify_replies');
            // If you're modifying a reply, I say it better be logged...
            $moderationAction = true;
        } else {
            isAllowedTo('modify_any');
            // Log it, assuming you're not modifying your own post.
            if ($row['ID_MEMBER'] != $ID_MEMBER) {
                $moderationAction = true;
            }
        }
        $posterIsGuest = empty($row['ID_MEMBER']);
        if (!allowedTo('moderate_forum') || !$posterIsGuest) {
            $_POST['guestname'] = addslashes($row['posterName']);
            $_POST['email'] = addslashes($row['posterEmail']);
        }
    }
    // If the poster is a guest evaluate the legality of name and email.
    if ($posterIsGuest) {
        $_POST['guestname'] = !isset($_POST['guestname']) ? '' : trim($_POST['guestname']);
        $_POST['email'] = !isset($_POST['email']) ? '' : trim($_POST['email']);
        if ($_POST['guestname'] == '' || $_POST['guestname'] == '_') {
            $post_errors[] = 'no_name';
        }
        if ($func['strlen']($_POST['guestname']) > 25) {
            $post_errors[] = 'long_name';
        }
        if (empty($modSettings['guest_post_no_email'])) {
            // Only check if they changed it!
            if (!isset($row) || $row['posterEmail'] != $_POST['email']) {
                if (!allowedTo('moderate_forum') && (!isset($_POST['email']) || $_POST['email'] == '')) {
                    $post_errors[] = 'no_email';
                }
                if (!allowedTo('moderate_forum') && preg_match('~^[0-9A-Za-z=_+\\-/][0-9A-Za-z=_\'+\\-/\\.]*@[\\w\\-]+(\\.[\\w\\-]+)*(\\.[\\w]{2,6})$~', stripslashes($_POST['email'])) == 0) {
                    $post_errors[] = 'bad_email';
                }
            }
            // Now make sure this email address is not banned from posting.
            isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt[28]));
        }
    }
    // Check the subject and message.
    if (!isset($_POST['subject']) || $func['htmltrim']($_POST['subject']) === '') {
        $post_errors[] = 'no_subject';
    }
    if (!isset($_POST['message']) || $func['htmltrim']($_POST['message']) === '') {
        $post_errors[] = 'no_message';
    } elseif (!empty($modSettings['max_messageLength']) && $func['strlen']($_POST['message']) > $modSettings['max_messageLength']) {
        $post_errors[] = 'long_message';
    } else {
        // Prepare the message a bit for some additional testing.
        $_POST['message'] = $func['htmlspecialchars']($_POST['message'], ENT_QUOTES);
        // Preparse code. (Zef)
        if ($user_info['is_guest']) {
            $user_info['name'] = $_POST['guestname'];
        }
        preparsecode($_POST['message']);
        // Let's see if there's still some content left without the tags.
        if ($func['htmltrim'](strip_tags(parse_bbc($_POST['message'], false), '<img>')) === '') {
            $post_errors[] = 'no_message';
        }
    }
    if (isset($_POST['calendar']) && !isset($_REQUEST['deleteevent']) && $func['htmltrim']($_POST['evtitle']) === '') {
        $post_errors[] = 'no_event';
    }
    // You are not!
    if (isset($_POST['message']) && strtolower($_POST['message']) == 'i am the administrator.' && !$user_info['is_admin']) {
        fatal_error('Knave! Masquerader! Charlatan!', false);
    }
    // Validate the poll...
    if (isset($_REQUEST['poll']) && $modSettings['pollMode'] == '1') {
        if (!empty($topic) && !isset($_REQUEST['msg'])) {
            fatal_lang_error(1, false);
        }
        // This is a new topic... so it's a new poll.
        if (empty($topic)) {
            isAllowedTo('poll_post');
        } elseif ($ID_MEMBER == $row['ID_MEMBER_POSTER'] && !allowedTo('poll_add_any')) {
            isAllowedTo('poll_add_own');
        } else {
            isAllowedTo('poll_add_any');
        }
        if (!isset($_POST['question']) || trim($_POST['question']) == '') {
            $post_errors[] = 'no_question';
        }
        $_POST['options'] = empty($_POST['options']) ? array() : htmltrim__recursive($_POST['options']);
        // Get rid of empty ones.
        foreach ($_POST['options'] as $k => $option) {
            if ($option == '') {
                unset($_POST['options'][$k], $_POST['options'][$k]);
            }
        }
        // What are you going to vote between with one choice?!?
        if (count($_POST['options']) < 2) {
            $post_errors[] = 'poll_few';
        }
    }
    if ($posterIsGuest) {
        // If user is a guest, make sure the chosen name isn't taken.
        require_once $sourcedir . '/Subs-Members.php';
        if (isReservedName($_POST['guestname'], 0, true, false) && (!isset($row['posterName']) || $_POST['guestname'] != $row['posterName'])) {
            $post_errors[] = 'bad_name';
        }
    } elseif (!isset($_REQUEST['msg'])) {
        $_POST['guestname'] = addslashes($user_info['username']);
        $_POST['email'] = addslashes($user_info['email']);
    }
    // Any mistakes?
    if (!empty($post_errors)) {
        loadLanguage('Errors');
        // Previewing.
        $_REQUEST['preview'] = true;
        $context['post_error'] = array('messages' => array());
        foreach ($post_errors as $post_error) {
            $context['post_error'][$post_error] = true;
            $context['post_error']['messages'][] = $txt['error_' . $post_error];
        }
        return Post();
    }
    // Make sure the user isn't spamming the board.
    if (!isset($_REQUEST['msg'])) {
        spamProtection('spam');
    }
    // At about this point, we're posting and that's that.
    ignore_user_abort(true);
    @set_time_limit(300);
    // Add special html entities to the subject, name, and email.
    $_POST['subject'] = strtr($func['htmlspecialchars']($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
    $_POST['guestname'] = htmlspecialchars($_POST['guestname']);
    $_POST['email'] = htmlspecialchars($_POST['email']);
    // At this point, we want to make sure the subject isn't too long.
    if ($func['strlen']($_POST['subject']) > 100) {
        $_POST['subject'] = addslashes($func['substr'](stripslashes($_POST['subject']), 0, 100));
    }
    // Make the poll...
    if (isset($_REQUEST['poll'])) {
        // Make sure that the user has not entered a ridiculous number of options..
        if (empty($_POST['poll_max_votes']) || $_POST['poll_max_votes'] <= 0) {
            $_POST['poll_max_votes'] = 1;
        } elseif ($_POST['poll_max_votes'] > count($_POST['options'])) {
            $_POST['poll_max_votes'] = count($_POST['options']);
        } else {
            $_POST['poll_max_votes'] = (int) $_POST['poll_max_votes'];
        }
        // Just set it to zero if it's not there..
        if (!isset($_POST['poll_hide'])) {
            $_POST['poll_hide'] = 0;
        } else {
            $_POST['poll_hide'] = (int) $_POST['poll_hide'];
        }
        $_POST['poll_change_vote'] = isset($_POST['poll_change_vote']) ? 1 : 0;
        // If the user tries to set the poll too far in advance, don't let them.
        if (!empty($_POST['poll_expire']) && $_POST['poll_expire'] < 1) {
            fatal_lang_error('poll_range_error', false);
        } elseif (empty($_POST['poll_expire']) && $_POST['poll_hide'] == 2) {
            $_POST['poll_hide'] = 1;
        }
        // Clean up the question and answers.
        $_POST['question'] = $func['htmlspecialchars']($_POST['question']);
        $_POST['options'] = htmlspecialchars__recursive($_POST['options']);
    }
    // Check if they are trying to delete any current attachments....
    if (isset($_REQUEST['msg'], $_POST['attach_del']) && allowedTo('post_attachment')) {
        $del_temp = array();
        foreach ($_POST['attach_del'] as $i => $dummy) {
            $del_temp[$i] = (int) $dummy;
        }
        require_once $sourcedir . '/ManageAttachments.php';
        removeAttachments('a.attachmentType = 0 AND a.ID_MSG = ' . (int) $_REQUEST['msg'] . ' AND a.ID_ATTACH NOT IN (' . implode(', ', $del_temp) . ')');
    }
    // ...or attach a new file...
    if (isset($_FILES['attachment']['name']) || !empty($_SESSION['temp_attachments'])) {
        isAllowedTo('post_attachment');
        // If this isn't a new post, check the current attachments.
        if (isset($_REQUEST['msg'])) {
            $request = db_query("\n\t\t\t\tSELECT COUNT(*), SUM(size)\n\t\t\t\tFROM {$db_prefix}attachments\n\t\t\t\tWHERE ID_MSG = " . (int) $_REQUEST['msg'] . "\n\t\t\t\t\tAND attachmentType = 0", __FILE__, __LINE__);
            list($quantity, $total_size) = mysql_fetch_row($request);
            mysql_free_result($request);
        } else {
            $quantity = 0;
            $total_size = 0;
        }
        if (!empty($_SESSION['temp_attachments'])) {
            foreach ($_SESSION['temp_attachments'] as $attachID => $name) {
                if (preg_match('~^post_tmp_' . $ID_MEMBER . '_\\d+$~', $attachID) == 0) {
                    continue;
                }
                if (!empty($_POST['attach_del']) && !in_array($attachID, $_POST['attach_del'])) {
                    unset($_SESSION['temp_attachments'][$attachID]);
                    @unlink($modSettings['attachmentUploadDir'] . '/' . $attachID);
                    continue;
                }
                $_FILES['attachment']['tmp_name'][] = $attachID;
                $_FILES['attachment']['name'][] = addslashes($name);
                $_FILES['attachment']['size'][] = filesize($modSettings['attachmentUploadDir'] . '/' . $attachID);
                list($_FILES['attachment']['width'][], $_FILES['attachment']['height'][]) = @getimagesize($modSettings['attachmentUploadDir'] . '/' . $attachID);
                unset($_SESSION['temp_attachments'][$attachID]);
            }
        }
        if (!isset($_FILES['attachment']['name'])) {
            $_FILES['attachment']['tmp_name'] = array();
        }
        $attachIDs = array();
        foreach ($_FILES['attachment']['tmp_name'] as $n => $dummy) {
            if ($_FILES['attachment']['name'][$n] == '') {
                continue;
            }
            // Have we reached the maximum number of files we are allowed?
            $quantity++;
            if (!empty($modSettings['attachmentNumPerPostLimit']) && $quantity > $modSettings['attachmentNumPerPostLimit']) {
                fatal_lang_error('attachments_limit_per_post', false, array($modSettings['attachmentNumPerPostLimit']));
            }
            // Check the total upload size for this post...
            $total_size += $_FILES['attachment']['size'][$n];
            if (!empty($modSettings['attachmentPostLimit']) && $total_size > $modSettings['attachmentPostLimit'] * 1024) {
                fatal_lang_error('smf122', false, array($modSettings['attachmentPostLimit']));
            }
            $attachmentOptions = array('post' => isset($_REQUEST['msg']) ? $_REQUEST['msg'] : 0, 'poster' => $ID_MEMBER, 'name' => $_FILES['attachment']['name'][$n], 'tmp_name' => $_FILES['attachment']['tmp_name'][$n], 'size' => $_FILES['attachment']['size'][$n]);
            if (createAttachment($attachmentOptions)) {
                $attachIDs[] = $attachmentOptions['id'];
                if (!empty($attachmentOptions['thumb'])) {
                    $attachIDs[] = $attachmentOptions['thumb'];
                }
            } else {
                if (in_array('could_not_upload', $attachmentOptions['errors'])) {
                    fatal_lang_error('smf124');
                }
                if (in_array('too_large', $attachmentOptions['errors'])) {
                    fatal_lang_error('smf122', false, array($modSettings['attachmentSizeLimit']));
                }
                if (in_array('bad_extension', $attachmentOptions['errors'])) {
                    fatal_error($attachmentOptions['name'] . '.<br />' . $txt['smf123'] . ' ' . $modSettings['attachmentExtensions'] . '.', false);
                }
                if (in_array('directory_full', $attachmentOptions['errors'])) {
                    fatal_lang_error('smf126');
                }
                if (in_array('bad_filename', $attachmentOptions['errors'])) {
                    fatal_error(basename($attachmentOptions['name']) . '.<br />' . $txt['smf130b'] . '.');
                }
                if (in_array('taken_filename', $attachmentOptions['errors'])) {
                    fatal_lang_error('smf125');
                }
            }
        }
    }
    // Make the poll...
    if (isset($_REQUEST['poll'])) {
        // Create the poll.
        db_query("\n\t\t\tINSERT INTO {$db_prefix}polls\n\t\t\t\t(question, hideResults, maxVotes, expireTime, ID_MEMBER, posterName, changeVote)\n\t\t\tVALUES (SUBSTRING('{$_POST['question']}', 1, 255), {$_POST['poll_hide']}, {$_POST['poll_max_votes']},\n\t\t\t\t" . (empty($_POST['poll_expire']) ? '0' : time() + $_POST['poll_expire'] * 3600 * 24) . ", {$ID_MEMBER}, SUBSTRING('{$_POST['guestname']}', 1, 255), {$_POST['poll_change_vote']})", __FILE__, __LINE__);
        $ID_POLL = db_insert_id();
        // Create each answer choice.
        $i = 0;
        $setString = '';
        foreach ($_POST['options'] as $option) {
            $setString .= "\n\t\t\t\t\t({$ID_POLL}, {$i}, SUBSTRING('{$option}', 1, 255)),";
            $i++;
        }
        db_query("\n\t\t\tINSERT INTO {$db_prefix}poll_choices\n\t\t\t\t(ID_POLL, ID_CHOICE, label)\n\t\t\tVALUES" . substr($setString, 0, -1), __FILE__, __LINE__);
    } else {
        $ID_POLL = 0;
    }
    // Creating a new topic?
    $newTopic = empty($_REQUEST['msg']) && empty($topic);
    // Collect all parameters for the creation or modification of a post.
    $msgOptions = array('id' => empty($_REQUEST['msg']) ? 0 : (int) $_REQUEST['msg'], 'subject' => $_POST['subject'], 'body' => $_POST['message'], 'icon' => preg_replace('~[\\./\\\\*\':"<>]~', '', $_POST['icon']), 'smileys_enabled' => !isset($_POST['ns']), 'attachments' => empty($attachIDs) ? array() : $attachIDs);
    $topicOptions = array('id' => empty($topic) ? 0 : $topic, 'board' => $board, 'poll' => isset($_REQUEST['poll']) ? $ID_POLL : null, 'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null, 'sticky_mode' => isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics']) ? (int) $_POST['sticky'] : null, 'mark_as_read' => true);
    $posterOptions = array('id' => $ID_MEMBER, 'name' => $_POST['guestname'], 'email' => $_POST['email'], 'update_post_count' => !$user_info['is_guest'] && !isset($_REQUEST['msg']) && $board_info['posts_count']);
    // This is an already existing message. Edit it.
    if (!empty($_REQUEST['msg'])) {
        // Have admins allowed people to hide their screwups?
        if (time() - $row['posterTime'] > $modSettings['edit_wait_time'] || $ID_MEMBER != $row['ID_MEMBER']) {
            $msgOptions['modify_time'] = time();
            $msgOptions['modify_name'] = addslashes($user_info['name']);
        }
        modifyPost($msgOptions, $topicOptions, $posterOptions);
    } else {
        createPost($msgOptions, $topicOptions, $posterOptions);
        if (isset($topicOptions['id'])) {
            $topic = $topicOptions['id'];
        }
    }
    // Editing or posting an event?
    if (isset($_POST['calendar']) && (!isset($_REQUEST['eventid']) || $_REQUEST['eventid'] == -1)) {
        require_once $sourcedir . '/Calendar.php';
        calendarCanLink();
        calendarInsertEvent($board, $topic, $_POST['evtitle'], $ID_MEMBER, $_POST['month'], $_POST['day'], $_POST['year'], isset($_POST['span']) ? $_POST['span'] : null);
    } elseif (isset($_POST['calendar'])) {
        $_REQUEST['eventid'] = (int) $_REQUEST['eventid'];
        // Validate the post...
        require_once $sourcedir . '/Subs-Post.php';
        calendarValidatePost();
        // If you're not allowed to edit any events, you have to be the poster.
        if (!allowedTo('calendar_edit_any')) {
            // Get the event's poster.
            $request = db_query("\n\t\t\t\tSELECT ID_MEMBER\n\t\t\t\tFROM {$db_prefix}calendar\n\t\t\t\tWHERE ID_EVENT = {$_REQUEST['eventid']}", __FILE__, __LINE__);
            $row2 = mysql_fetch_assoc($request);
            mysql_free_result($request);
            // Silly hacker, Trix are for kids. ...probably trademarked somewhere, this is FAIR USE! (parody...)
            isAllowedTo('calendar_edit_' . ($row2['ID_MEMBER'] == $ID_MEMBER ? 'own' : 'any'));
        }
        // Delete it?
        if (isset($_REQUEST['deleteevent'])) {
            db_query("\n\t\t\t\tDELETE FROM {$db_prefix}calendar\n\t\t\t\tWHERE ID_EVENT = {$_REQUEST['eventid']}\n\t\t\t\tLIMIT 1", __FILE__, __LINE__);
        } else {
            $span = !empty($modSettings['cal_allowspan']) && !empty($_REQUEST['span']) ? min((int) $modSettings['cal_maxspan'], (int) $_REQUEST['span'] - 1) : 0;
            $start_time = mktime(0, 0, 0, (int) $_REQUEST['month'], (int) $_REQUEST['day'], (int) $_REQUEST['year']);
            db_query("\n\t\t\t\tUPDATE {$db_prefix}calendar\n\t\t\t\tSET endDate = '" . strftime('%Y-%m-%d', $start_time + $span * 86400) . "',\n\t\t\t\t\tstartDate = '" . strftime('%Y-%m-%d', $start_time) . "',\n\t\t\t\t\ttitle = '" . $func['htmlspecialchars']($_REQUEST['evtitle'], ENT_QUOTES) . "'\n\t\t\t\tWHERE ID_EVENT = {$_REQUEST['eventid']}\n\t\t\t\tLIMIT 1", __FILE__, __LINE__);
        }
        updateStats('calendar');
    }
    // Marking read should be done even for editing messages....
    if (!$user_info['is_guest']) {
        // Mark all the parents read.  (since you just posted and they will be unread.)
        if (!empty($board_info['parent_boards'])) {
            db_query("\n\t\t\t\tUPDATE {$db_prefix}log_boards\n\t\t\t\tSET ID_MSG = {$modSettings['maxMsgID']}\n\t\t\t\tWHERE ID_MEMBER = {$ID_MEMBER}\n\t\t\t\t\tAND ID_BOARD IN (" . implode(',', array_keys($board_info['parent_boards'])) . ")", __FILE__, __LINE__);
        }
    }
    // Turn notification on or off.  (note this just blows smoke if it's already on or off.)
    if (!empty($_POST['notify'])) {
        if (allowedTo('mark_any_notify')) {
            db_query("\n\t\t\t\tINSERT IGNORE INTO {$db_prefix}log_notify\n\t\t\t\t\t(ID_MEMBER, ID_TOPIC, ID_BOARD)\n\t\t\t\tVALUES ({$ID_MEMBER}, {$topic}, 0)", __FILE__, __LINE__);
        }
    } elseif (!$newTopic) {
        db_query("\n\t\t\tDELETE FROM {$db_prefix}log_notify\n\t\t\tWHERE ID_MEMBER = {$ID_MEMBER}\n\t\t\t\tAND ID_TOPIC = {$topic}\n\t\t\tLIMIT 1", __FILE__, __LINE__);
    }
    // Log an act of moderation - modifying.
    if (!empty($moderationAction)) {
        logAction('modify', array('topic' => $topic, 'message' => (int) $_REQUEST['msg'], 'member' => $row['ID_MEMBER']));
    }
    if (isset($_POST['lock']) && $_POST['lock'] != 2) {
        logAction('lock', array('topic' => $topicOptions['id']));
    }
    if (isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics'])) {
        logAction('sticky', array('topic' => $topicOptions['id']));
    }
    // Notify any members who have notification turned on for this topic.
    if ($newTopic) {
        notifyMembersBoard();
    } elseif (empty($_REQUEST['msg'])) {
        sendNotifications($topic, 'reply');
    }
    // Returning to the topic?
    if (!empty($_REQUEST['goback'])) {
        // Mark the board as read.... because it might get confusing otherwise.
        db_query("\n\t\t\tUPDATE {$db_prefix}log_boards\n\t\t\tSET ID_MSG = {$modSettings['maxMsgID']}\n\t\t\tWHERE ID_MEMBER = {$ID_MEMBER}\n\t\t\t\tAND ID_BOARD = {$board}", __FILE__, __LINE__);
    }
    if (!empty($_POST['announce_topic'])) {
        redirectexit('action=announce;sa=selectgroup;topic=' . $topic . (!empty($_POST['move']) && allowedTo('move_any') ? ';move' : '') . (empty($_REQUEST['goback']) ? '' : ';goback'));
    }
    if (!empty($_POST['move']) && allowedTo('move_any')) {
        redirectexit('action=movetopic;topic=' . $topic . '.0' . (empty($_REQUEST['goback']) ? '' : ';goback'));
    }
    // Return to post if the mod is on.
    if (isset($_REQUEST['msg']) && !empty($_REQUEST['goback'])) {
        redirectexit('topic=' . $topic . '.msg' . $_REQUEST['msg'] . '#msg' . $_REQUEST['msg'], $context['browser']['is_ie']);
    } elseif (!empty($_REQUEST['goback'])) {
        redirectexit('topic=' . $topic . '.new#new', $context['browser']['is_ie']);
    } else {
        redirectexit('board=' . $board . '.0');
    }
}
示例#17
0
function PlushSearch2()
{
    global $scripturl, $modSettings, $sourcedir, $txt, $db_connection;
    global $user_info, $context, $options, $messages_request, $boards_can;
    global $excludedWords, $participants, $smcFunc, $search_versions, $searchAPI;
    if (!empty($context['load_average']) && !empty($modSettings['loadavg_search']) && $context['load_average'] >= $modSettings['loadavg_search']) {
        fatal_lang_error('loadavg_search_disabled', false);
    }
    // No, no, no... this is a bit hard on the server, so don't you go prefetching it!
    if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') {
        ob_end_clean();
        header('HTTP/1.1 403 Forbidden');
        die;
    }
    $weight_factors = array('frequency', 'age', 'length', 'subject', 'first_message', 'sticky');
    $weight = array();
    $weight_total = 0;
    foreach ($weight_factors as $weight_factor) {
        $weight[$weight_factor] = empty($modSettings['search_weight_' . $weight_factor]) ? 0 : (int) $modSettings['search_weight_' . $weight_factor];
        $weight_total += $weight[$weight_factor];
    }
    // Zero weight.  Weightless :P.
    if (empty($weight_total)) {
        fatal_lang_error('search_invalid_weights');
    }
    // These vars don't require an interface, they're just here for tweaking.
    $recentPercentage = 0.3;
    $humungousTopicPosts = 200;
    $maxMembersToSearch = 500;
    $maxMessageResults = empty($modSettings['search_max_results']) ? 0 : $modSettings['search_max_results'] * 5;
    // Start with no errors.
    $context['search_errors'] = array();
    // Number of pages hard maximum - normally not set at all.
    $modSettings['search_max_results'] = empty($modSettings['search_max_results']) ? 200 * $modSettings['search_results_per_page'] : (int) $modSettings['search_max_results'];
    // Maximum length of the string.
    $context['search_string_limit'] = 100;
    loadLanguage('Search');
    if (!isset($_REQUEST['xml'])) {
        loadTemplate('Search');
    } else {
        $context['sub_template'] = 'results';
    }
    // Are you allowed?
    isAllowedTo('search_posts');
    require_once $sourcedir . '/Display.php';
    require_once $sourcedir . '/Subs-Package.php';
    // Search has a special database set.
    db_extend('search');
    // Load up the search API we are going to use.
    $modSettings['search_index'] = empty($modSettings['search_index']) ? 'standard' : $modSettings['search_index'];
    if (!file_exists($sourcedir . '/SearchAPI-' . ucwords($modSettings['search_index']) . '.php')) {
        fatal_lang_error('search_api_missing');
    }
    loadClassFile('SearchAPI-' . ucwords($modSettings['search_index']) . '.php');
    // Create an instance of the search API and check it is valid for this version of SMF.
    $search_class_name = $modSettings['search_index'] . '_search';
    $searchAPI = new $search_class_name();
    if (!$searchAPI || $searchAPI->supportsMethod('isValid') && !$searchAPI->isValid() || !matchPackageVersion($search_versions['forum_version'], $searchAPI->min_smf_version . '-' . $searchAPI->version_compatible)) {
        // Log the error.
        loadLanguage('Errors');
        log_error(sprintf($txt['search_api_not_compatible'], 'SearchAPI-' . ucwords($modSettings['search_index']) . '.php'), 'critical');
        loadClassFile('SearchAPI-Standard.php');
        $searchAPI = new standard_search();
    }
    // $search_params will carry all settings that differ from the default search parameters.
    // That way, the URLs involved in a search page will be kept as short as possible.
    $search_params = array();
    if (isset($_REQUEST['params'])) {
        // Due to IE's 2083 character limit, we have to compress long search strings
        $temp_params = base64_decode(str_replace(array('-', '_', '.'), array('+', '/', '='), $_REQUEST['params']));
        // Test for gzuncompress failing
        $temp_params2 = @gzuncompress($temp_params);
        $temp_params = explode('|"|', !empty($temp_params2) ? $temp_params2 : $temp_params);
        foreach ($temp_params as $i => $data) {
            @(list($k, $v) = explode('|\'|', $data));
            $search_params[$k] = $v;
        }
        if (isset($search_params['brd'])) {
            $search_params['brd'] = empty($search_params['brd']) ? array() : explode(',', $search_params['brd']);
        }
    }
    // Store whether simple search was used (needed if the user wants to do another query).
    if (!isset($search_params['advanced'])) {
        $search_params['advanced'] = empty($_REQUEST['advanced']) ? 0 : 1;
    }
    // 1 => 'allwords' (default, don't set as param) / 2 => 'anywords'.
    if (!empty($search_params['searchtype']) || !empty($_REQUEST['searchtype']) && $_REQUEST['searchtype'] == 2) {
        $search_params['searchtype'] = 2;
    }
    // Minimum age of messages. Default to zero (don't set param in that case).
    if (!empty($search_params['minage']) || !empty($_REQUEST['minage']) && $_REQUEST['minage'] > 0) {
        $search_params['minage'] = !empty($search_params['minage']) ? (int) $search_params['minage'] : (int) $_REQUEST['minage'];
    }
    // Maximum age of messages. Default to infinite (9999 days: param not set).
    if (!empty($search_params['maxage']) || !empty($_REQUEST['maxage']) && $_REQUEST['maxage'] < 9999) {
        $search_params['maxage'] = !empty($search_params['maxage']) ? (int) $search_params['maxage'] : (int) $_REQUEST['maxage'];
    }
    // Searching a specific topic?
    if (!empty($_REQUEST['topic'])) {
        $search_params['topic'] = (int) $_REQUEST['topic'];
        $search_params['show_complete'] = true;
    } elseif (!empty($search_params['topic'])) {
        $search_params['topic'] = (int) $search_params['topic'];
    }
    if (!empty($search_params['minage']) || !empty($search_params['maxage'])) {
        $request = $smcFunc['db_query']('', '
			SELECT ' . (empty($search_params['maxage']) ? '0, ' : 'IFNULL(MIN(id_msg), -1), ') . (empty($search_params['minage']) ? '0' : 'IFNULL(MAX(id_msg), -1)') . '
			FROM {db_prefix}messages
			WHERE 1=1' . ($modSettings['postmod_active'] ? '
				AND approved = {int:is_approved_true}' : '') . (empty($search_params['minage']) ? '' : '
				AND poster_time <= {int:timestamp_minimum_age}') . (empty($search_params['maxage']) ? '' : '
				AND poster_time >= {int:timestamp_maximum_age}'), array('timestamp_minimum_age' => empty($search_params['minage']) ? 0 : time() - 86400 * $search_params['minage'], 'timestamp_maximum_age' => empty($search_params['maxage']) ? 0 : time() - 86400 * $search_params['maxage'], 'is_approved_true' => 1));
        list($minMsgID, $maxMsgID) = $smcFunc['db_fetch_row']($request);
        if ($minMsgID < 0 || $maxMsgID < 0) {
            $context['search_errors']['no_messages_in_time_frame'] = true;
        }
        $smcFunc['db_free_result']($request);
    }
    // Default the user name to a wildcard matching every user (*).
    if (!empty($search_params['userspec']) || !empty($_REQUEST['userspec']) && $_REQUEST['userspec'] != '*') {
        $search_params['userspec'] = isset($search_params['userspec']) ? $search_params['userspec'] : $_REQUEST['userspec'];
    }
    // If there's no specific user, then don't mention it in the main query.
    if (empty($search_params['userspec'])) {
        $userQuery = '';
    } else {
        $userString = strtr($smcFunc['htmlspecialchars']($search_params['userspec'], ENT_QUOTES), array('&quot;' => '"'));
        $userString = strtr($userString, array('%' => '\\%', '_' => '\\_', '*' => '%', '?' => '_'));
        preg_match_all('~"([^"]+)"~', $userString, $matches);
        $possible_users = array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $userString)));
        for ($k = 0, $n = count($possible_users); $k < $n; $k++) {
            $possible_users[$k] = trim($possible_users[$k]);
            if (strlen($possible_users[$k]) == 0) {
                unset($possible_users[$k]);
            }
        }
        // Create a list of database-escaped search names.
        $realNameMatches = array();
        foreach ($possible_users as $possible_user) {
            $realNameMatches[] = $smcFunc['db_quote']('{string:possible_user}', array('possible_user' => $possible_user));
        }
        // Retrieve a list of possible members.
        $request = $smcFunc['db_query']('', '
			SELECT id_member
			FROM {db_prefix}members
			WHERE {raw:match_possible_users}', array('match_possible_users' => 'real_name LIKE ' . implode(' OR real_name LIKE ', $realNameMatches)));
        // Simply do nothing if there're too many members matching the criteria.
        if ($smcFunc['db_num_rows']($request) > $maxMembersToSearch) {
            $userQuery = '';
        } elseif ($smcFunc['db_num_rows']($request) == 0) {
            $userQuery = $smcFunc['db_quote']('m.id_member = {int:id_member_guest} AND ({raw:match_possible_guest_names})', array('id_member_guest' => 0, 'match_possible_guest_names' => 'm.poster_name LIKE ' . implode(' OR m.poster_name LIKE ', $realNameMatches)));
        } else {
            $memberlist = array();
            while ($row = $smcFunc['db_fetch_assoc']($request)) {
                $memberlist[] = $row['id_member'];
            }
            $userQuery = $smcFunc['db_quote']('(m.id_member IN ({array_int:matched_members}) OR (m.id_member = {int:id_member_guest} AND ({raw:match_possible_guest_names})))', array('matched_members' => $memberlist, 'id_member_guest' => 0, 'match_possible_guest_names' => 'm.poster_name LIKE ' . implode(' OR m.poster_name LIKE ', $realNameMatches)));
        }
        $smcFunc['db_free_result']($request);
    }
    // If the boards were passed by URL (params=), temporarily put them back in $_REQUEST.
    if (!empty($search_params['brd']) && is_array($search_params['brd'])) {
        $_REQUEST['brd'] = $search_params['brd'];
    }
    // Ensure that brd is an array.
    if (!empty($_REQUEST['brd']) && !is_array($_REQUEST['brd'])) {
        $_REQUEST['brd'] = strpos($_REQUEST['brd'], ',') !== false ? explode(',', $_REQUEST['brd']) : array($_REQUEST['brd']);
    }
    // Make sure all boards are integers.
    if (!empty($_REQUEST['brd'])) {
        foreach ($_REQUEST['brd'] as $id => $brd) {
            $_REQUEST['brd'][$id] = (int) $brd;
        }
    }
    // Special case for boards: searching just one topic?
    if (!empty($search_params['topic'])) {
        $request = $smcFunc['db_query']('', '
			SELECT b.id_board
			FROM {db_prefix}topics AS t
				INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
			WHERE t.id_topic = {int:search_topic_id}
				AND {query_see_board}' . ($modSettings['postmod_active'] ? '
				AND t.approved = {int:is_approved_true}' : '') . '
			LIMIT 1', array('search_topic_id' => $search_params['topic'], 'is_approved_true' => 1));
        if ($smcFunc['db_num_rows']($request) == 0) {
            fatal_lang_error('topic_gone', false);
        }
        $search_params['brd'] = array();
        list($search_params['brd'][0]) = $smcFunc['db_fetch_row']($request);
        $smcFunc['db_free_result']($request);
    } elseif ($user_info['is_admin'] && (!empty($search_params['advanced']) || !empty($_REQUEST['brd']))) {
        $search_params['brd'] = empty($_REQUEST['brd']) ? array() : $_REQUEST['brd'];
    } else {
        $see_board = empty($search_params['advanced']) ? 'query_wanna_see_board' : 'query_see_board';
        $request = $smcFunc['db_query']('', '
			SELECT b.id_board
			FROM {db_prefix}boards AS b
			WHERE {raw:boards_allowed_to_see}
				AND redirect = {string:empty_string}' . (empty($_REQUEST['brd']) ? !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
				AND b.id_board != {int:recycle_board_id}' : '' : '
				AND b.id_board IN ({array_int:selected_search_boards})'), array('boards_allowed_to_see' => $user_info[$see_board], 'empty_string' => '', 'selected_search_boards' => empty($_REQUEST['brd']) ? array() : $_REQUEST['brd'], 'recycle_board_id' => $modSettings['recycle_board']));
        $search_params['brd'] = array();
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            $search_params['brd'][] = $row['id_board'];
        }
        $smcFunc['db_free_result']($request);
        // This error should pro'bly only happen for hackers.
        if (empty($search_params['brd'])) {
            $context['search_errors']['no_boards_selected'] = true;
        }
    }
    if (count($search_params['brd']) != 0) {
        foreach ($search_params['brd'] as $k => $v) {
            $search_params['brd'][$k] = (int) $v;
        }
        // If we've selected all boards, this parameter can be left empty.
        $request = $smcFunc['db_query']('', '
			SELECT COUNT(*)
			FROM {db_prefix}boards
			WHERE redirect = {string:empty_string}', array('empty_string' => ''));
        list($num_boards) = $smcFunc['db_fetch_row']($request);
        $smcFunc['db_free_result']($request);
        if (count($search_params['brd']) == $num_boards) {
            $boardQuery = '';
        } elseif (count($search_params['brd']) == $num_boards - 1 && !empty($modSettings['recycle_board']) && !in_array($modSettings['recycle_board'], $search_params['brd'])) {
            $boardQuery = '!= ' . $modSettings['recycle_board'];
        } else {
            $boardQuery = 'IN (' . implode(', ', $search_params['brd']) . ')';
        }
    } else {
        $boardQuery = '';
    }
    $search_params['show_complete'] = !empty($search_params['show_complete']) || !empty($_REQUEST['show_complete']);
    $search_params['subject_only'] = !empty($search_params['subject_only']) || !empty($_REQUEST['subject_only']);
    $context['compact'] = !$search_params['show_complete'];
    // Get the sorting parameters right. Default to sort by relevance descending.
    $sort_columns = array('relevance', 'num_replies', 'id_msg');
    if (empty($search_params['sort']) && !empty($_REQUEST['sort'])) {
        list($search_params['sort'], $search_params['sort_dir']) = array_pad(explode('|', $_REQUEST['sort']), 2, '');
    }
    $search_params['sort'] = !empty($search_params['sort']) && in_array($search_params['sort'], $sort_columns) ? $search_params['sort'] : 'relevance';
    if (!empty($search_params['topic']) && $search_params['sort'] === 'num_replies') {
        $search_params['sort'] = 'id_msg';
    }
    // Sorting direction: descending unless stated otherwise.
    $search_params['sort_dir'] = !empty($search_params['sort_dir']) && $search_params['sort_dir'] == 'asc' ? 'asc' : 'desc';
    // Determine some values needed to calculate the relevance.
    $minMsg = (int) ((1 - $recentPercentage) * $modSettings['maxMsgID']);
    $recentMsg = $modSettings['maxMsgID'] - $minMsg;
    // *** Parse the search query
    // Unfortunately, searching for words like this is going to be slow, so we're blacklisting them.
    // !!! Setting to add more here?
    // !!! Maybe only blacklist if they are the only word, or "any" is used?
    $blacklisted_words = array('img', 'url', 'quote', 'www', 'http', 'the', 'is', 'it', 'are', 'if');
    // What are we searching for?
    if (empty($search_params['search'])) {
        if (isset($_GET['search'])) {
            $search_params['search'] = un_htmlspecialchars($_GET['search']);
        } elseif (isset($_POST['search'])) {
            $search_params['search'] = $_POST['search'];
        } else {
            $search_params['search'] = '';
        }
    }
    // Nothing??
    if (!isset($search_params['search']) || $search_params['search'] == '') {
        $context['search_errors']['invalid_search_string'] = true;
    } elseif ($smcFunc['strlen']($search_params['search']) > $context['search_string_limit']) {
        $context['search_errors']['string_too_long'] = true;
        $txt['error_string_too_long'] = sprintf($txt['error_string_too_long'], $context['search_string_limit']);
    }
    // Change non-word characters into spaces.
    $stripped_query = preg_replace('~(?:[\\x0B\\0' . ($context['utf8'] ? $context['server']['complex_preg_chars'] ? '\\x{A0}' : " " : '\\xA0') . '\\t\\r\\s\\n(){}\\[\\]<>!@$%^*.,:+=`\\~\\?/\\\\]+|&(?:amp|lt|gt|quot);)+~' . ($context['utf8'] ? 'u' : ''), ' ', $search_params['search']);
    // Make the query lower case. It's gonna be case insensitive anyway.
    $stripped_query = un_htmlspecialchars($smcFunc['strtolower']($stripped_query));
    // This (hidden) setting will do fulltext searching in the most basic way.
    if (!empty($modSettings['search_simple_fulltext'])) {
        $stripped_query = strtr($stripped_query, array('"' => ''));
    }
    $no_regexp = preg_match('~&#(?:\\d{1,7}|x[0-9a-fA-F]{1,6});~', $stripped_query) === 1;
    // Extract phrase parts first (e.g. some words "this is a phrase" some more words.)
    preg_match_all('/(?:^|\\s)([-]?)"([^"]+)"(?:$|\\s)/', $stripped_query, $matches, PREG_PATTERN_ORDER);
    $phraseArray = $matches[2];
    // Remove the phrase parts and extract the words.
    $wordArray = explode(' ', preg_replace('~(?:^|\\s)(?:[-]?)"(?:[^"]+)"(?:$|\\s)~' . ($context['utf8'] ? 'u' : ''), ' ', $search_params['search']));
    // A minus sign in front of a word excludes the word.... so...
    $excludedWords = array();
    $excludedIndexWords = array();
    $excludedSubjectWords = array();
    $excludedPhrases = array();
    // .. first, we check for things like -"some words", but not "-some words".
    foreach ($matches[1] as $index => $word) {
        if ($word === '-') {
            if (($word = trim($phraseArray[$index], '-_\' ')) !== '' && !in_array($word, $blacklisted_words)) {
                $excludedWords[] = $word;
            }
            unset($phraseArray[$index]);
        }
    }
    // Now we look for -test, etc.... normaller.
    foreach ($wordArray as $index => $word) {
        if (strpos(trim($word), '-') === 0) {
            if (($word = trim($word, '-_\' ')) !== '' && !in_array($word, $blacklisted_words)) {
                $excludedWords[] = $word;
            }
            unset($wordArray[$index]);
        }
    }
    // The remaining words and phrases are all included.
    $searchArray = array_merge($phraseArray, $wordArray);
    // Trim everything and make sure there are no words that are the same.
    foreach ($searchArray as $index => $value) {
        // Skip anything practically empty.
        if (($searchArray[$index] = trim($value, '-_\' ')) === '') {
            unset($searchArray[$index]);
        } elseif (in_array($searchArray[$index], $blacklisted_words)) {
            $foundBlackListedWords = true;
            unset($searchArray[$index]);
        } elseif ($smcFunc['strlen']($value) < 2) {
            $context['search_errors']['search_string_small_words'] = true;
            unset($searchArray[$index]);
        } else {
            $searchArray[$index] = $searchArray[$index];
        }
    }
    $searchArray = array_slice(array_unique($searchArray), 0, 10);
    // Create an array of replacements for highlighting.
    $context['mark'] = array();
    foreach ($searchArray as $word) {
        $context['mark'][$word] = '<strong class="highlight">' . $word . '</strong>';
    }
    // Initialize two arrays storing the words that have to be searched for.
    $orParts = array();
    $searchWords = array();
    // Make sure at least one word is being searched for.
    if (empty($searchArray)) {
        $context['search_errors']['invalid_search_string' . (!empty($foundBlackListedWords) ? '_blacklist' : '')] = true;
    } elseif (empty($search_params['searchtype'])) {
        $orParts[0] = $searchArray;
    } else {
        foreach ($searchArray as $index => $value) {
            $orParts[$index] = array($value);
        }
    }
    // Don't allow duplicate error messages if one string is too short.
    if (isset($context['search_errors']['search_string_small_words'], $context['search_errors']['invalid_search_string'])) {
        unset($context['search_errors']['invalid_search_string']);
    }
    // Make sure the excluded words are in all or-branches.
    foreach ($orParts as $orIndex => $andParts) {
        foreach ($excludedWords as $word) {
            $orParts[$orIndex][] = $word;
        }
    }
    // Determine the or-branches and the fulltext search words.
    foreach ($orParts as $orIndex => $andParts) {
        $searchWords[$orIndex] = array('indexed_words' => array(), 'words' => array(), 'subject_words' => array(), 'all_words' => array());
        // Sort the indexed words (large words -> small words -> excluded words).
        if ($searchAPI->supportsMethod('searchSort')) {
            usort($orParts[$orIndex], 'searchSort');
        }
        foreach ($orParts[$orIndex] as $word) {
            $is_excluded = in_array($word, $excludedWords);
            $searchWords[$orIndex]['all_words'][] = $word;
            $subjectWords = text2words($word);
            if (!$is_excluded || count($subjectWords) === 1) {
                $searchWords[$orIndex]['subject_words'] = array_merge($searchWords[$orIndex]['subject_words'], $subjectWords);
                if ($is_excluded) {
                    $excludedSubjectWords = array_merge($excludedSubjectWords, $subjectWords);
                }
            } else {
                $excludedPhrases[] = $word;
            }
            // Have we got indexes to prepare?
            if ($searchAPI->supportsMethod('prepareIndexes')) {
                $searchAPI->prepareIndexes($word, $searchWords[$orIndex], $excludedIndexWords, $is_excluded);
            }
        }
        // Search_force_index requires all AND parts to have at least one fulltext word.
        if (!empty($modSettings['search_force_index']) && empty($searchWords[$orIndex]['indexed_words'])) {
            $context['search_errors']['query_not_specific_enough'] = true;
            break;
        } elseif ($search_params['subject_only'] && empty($searchWords[$orIndex]['subject_words']) && empty($excludedSubjectWords)) {
            $context['search_errors']['query_not_specific_enough'] = true;
            break;
        } else {
            $searchWords[$orIndex]['indexed_words'] = array_slice($searchWords[$orIndex]['indexed_words'], 0, 7);
            $searchWords[$orIndex]['subject_words'] = array_slice($searchWords[$orIndex]['subject_words'], 0, 7);
        }
    }
    // *** Spell checking
    $context['show_spellchecking'] = !empty($modSettings['enableSpellChecking']) && function_exists('pspell_new');
    if ($context['show_spellchecking']) {
        // Windows fix.
        ob_start();
        $old = error_reporting(0);
        pspell_new('en');
        $pspell_link = pspell_new($txt['lang_dictionary'], $txt['lang_spelling'], '', strtr($txt['lang_character_set'], array('iso-' => 'iso', 'ISO-' => 'iso')), PSPELL_FAST | PSPELL_RUN_TOGETHER);
        if (!$pspell_link) {
            $pspell_link = pspell_new('en', '', '', '', PSPELL_FAST | PSPELL_RUN_TOGETHER);
        }
        error_reporting($old);
        ob_end_clean();
        $did_you_mean = array('search' => array(), 'display' => array());
        $found_misspelling = false;
        foreach ($searchArray as $word) {
            if (empty($pspell_link)) {
                continue;
            }
            $word = $word;
            // Don't check phrases.
            if (preg_match('~^\\w+$~', $word) === 0) {
                $did_you_mean['search'][] = '"' . $word . '"';
                $did_you_mean['display'][] = '&quot;' . $smcFunc['htmlspecialchars']($word) . '&quot;';
                continue;
            } elseif (preg_match('~\\d~', $word) === 1) {
                $did_you_mean['search'][] = $word;
                $did_you_mean['display'][] = $smcFunc['htmlspecialchars']($word);
                continue;
            } elseif (pspell_check($pspell_link, $word)) {
                $did_you_mean['search'][] = $word;
                $did_you_mean['display'][] = $smcFunc['htmlspecialchars']($word);
                continue;
            }
            $suggestions = pspell_suggest($pspell_link, $word);
            foreach ($suggestions as $i => $s) {
                // Search is case insensitive.
                if ($smcFunc['strtolower']($s) == $smcFunc['strtolower']($word)) {
                    unset($suggestions[$i]);
                } elseif ($suggestions[$i] != censorText($s)) {
                    unset($suggestions[$i]);
                }
            }
            // Anything found?  If so, correct it!
            if (!empty($suggestions)) {
                $suggestions = array_values($suggestions);
                $did_you_mean['search'][] = $suggestions[0];
                $did_you_mean['display'][] = '<em><strong>' . $smcFunc['htmlspecialchars']($suggestions[0]) . '</strong></em>';
                $found_misspelling = true;
            } else {
                $did_you_mean['search'][] = $word;
                $did_you_mean['display'][] = $smcFunc['htmlspecialchars']($word);
            }
        }
        if ($found_misspelling) {
            // Don't spell check excluded words, but add them still...
            $temp_excluded = array('search' => array(), 'display' => array());
            foreach ($excludedWords as $word) {
                $word = $word;
                if (preg_match('~^\\w+$~', $word) == 0) {
                    $temp_excluded['search'][] = '-"' . $word . '"';
                    $temp_excluded['display'][] = '-&quot;' . $smcFunc['htmlspecialchars']($word) . '&quot;';
                } else {
                    $temp_excluded['search'][] = '-' . $word;
                    $temp_excluded['display'][] = '-' . $smcFunc['htmlspecialchars']($word);
                }
            }
            $did_you_mean['search'] = array_merge($did_you_mean['search'], $temp_excluded['search']);
            $did_you_mean['display'] = array_merge($did_you_mean['display'], $temp_excluded['display']);
            $temp_params = $search_params;
            $temp_params['search'] = implode(' ', $did_you_mean['search']);
            if (isset($temp_params['brd'])) {
                $temp_params['brd'] = implode(',', $temp_params['brd']);
            }
            $context['params'] = array();
            foreach ($temp_params as $k => $v) {
                $context['did_you_mean_params'][] = $k . '|\'|' . $v;
            }
            $context['did_you_mean_params'] = base64_encode(implode('|"|', $context['did_you_mean_params']));
            $context['did_you_mean'] = implode(' ', $did_you_mean['display']);
        }
    }
    // Let the user adjust the search query, should they wish?
    $context['search_params'] = $search_params;
    if (isset($context['search_params']['search'])) {
        $context['search_params']['search'] = $smcFunc['htmlspecialchars']($context['search_params']['search']);
    }
    if (isset($context['search_params']['userspec'])) {
        $context['search_params']['userspec'] = $smcFunc['htmlspecialchars']($context['search_params']['userspec']);
    }
    // Do we have captcha enabled?
    if ($user_info['is_guest'] && !empty($modSettings['search_enable_captcha']) && empty($_SESSION['ss_vv_passed']) && (empty($_SESSION['last_ss']) || $_SESSION['last_ss'] != $search_params['search'])) {
        // If we come from another search box tone down the error...
        if (!isset($_REQUEST['search_vv'])) {
            $context['search_errors']['need_verification_code'] = true;
        } else {
            require_once $sourcedir . '/Subs-Editor.php';
            $verificationOptions = array('id' => 'search');
            $context['require_verification'] = create_control_verification($verificationOptions, true);
            if (is_array($context['require_verification'])) {
                foreach ($context['require_verification'] as $error) {
                    $context['search_errors'][$error] = true;
                }
            } else {
                $_SESSION['ss_vv_passed'] = true;
            }
        }
    }
    // *** Encode all search params
    // All search params have been checked, let's compile them to a single string... made less simple by PHP 4.3.9 and below.
    $temp_params = $search_params;
    if (isset($temp_params['brd'])) {
        $temp_params['brd'] = implode(',', $temp_params['brd']);
    }
    $context['params'] = array();
    foreach ($temp_params as $k => $v) {
        $context['params'][] = $k . '|\'|' . $v;
    }
    if (!empty($context['params'])) {
        // Due to old IE's 2083 character limit, we have to compress long search strings
        $params = @gzcompress(implode('|"|', $context['params']));
        // Gzcompress failed, use try non-gz
        if (empty($params)) {
            $params = implode('|"|', $context['params']);
        }
        // Base64 encode, then replace +/= with uri safe ones that can be reverted
        $context['params'] = str_replace(array('+', '/', '='), array('-', '_', '.'), base64_encode($params));
    }
    // ... and add the links to the link tree.
    $context['linktree'][] = array('url' => $scripturl . '?action=search;params=' . $context['params'], 'name' => $txt['search']);
    $context['linktree'][] = array('url' => $scripturl . '?action=search2;params=' . $context['params'], 'name' => $txt['search_results']);
    // *** A last error check
    // One or more search errors? Go back to the first search screen.
    if (!empty($context['search_errors'])) {
        $_REQUEST['params'] = $context['params'];
        return PlushSearch1();
    }
    // Spam me not, Spam-a-lot?
    if (empty($_SESSION['last_ss']) || $_SESSION['last_ss'] != $search_params['search']) {
        spamProtection('search');
    }
    // Store the last search string to allow pages of results to be browsed.
    $_SESSION['last_ss'] = $search_params['search'];
    // *** Reserve an ID for caching the search results.
    $query_params = array_merge($search_params, array('min_msg_id' => isset($minMsgID) ? (int) $minMsgID : 0, 'max_msg_id' => isset($maxMsgID) ? (int) $maxMsgID : 0, 'memberlist' => !empty($memberlist) ? $memberlist : array()));
    // Can this search rely on the API given the parameters?
    if ($searchAPI->supportsMethod('searchQuery', $query_params)) {
        $participants = array();
        $searchArray = array();
        $num_results = $searchAPI->searchQuery($query_params, $searchWords, $excludedIndexWords, $participants, $searchArray);
    } else {
        $update_cache = empty($_SESSION['search_cache']) || $_SESSION['search_cache']['params'] != $context['params'];
        if ($update_cache) {
            // Increase the pointer...
            $modSettings['search_pointer'] = empty($modSettings['search_pointer']) ? 0 : (int) $modSettings['search_pointer'];
            // ...and store it right off.
            updateSettings(array('search_pointer' => $modSettings['search_pointer'] >= 255 ? 0 : $modSettings['search_pointer'] + 1));
            // As long as you don't change the parameters, the cache result is yours.
            $_SESSION['search_cache'] = array('id_search' => $modSettings['search_pointer'], 'num_results' => -1, 'params' => $context['params']);
            // Clear the previous cache of the final results cache.
            $smcFunc['db_search_query']('delete_log_search_results', '
				DELETE FROM {db_prefix}log_search_results
				WHERE id_search = {int:search_id}', array('search_id' => $_SESSION['search_cache']['id_search']));
            if ($search_params['subject_only']) {
                // We do this to try and avoid duplicate keys on databases not supporting INSERT IGNORE.
                $inserts = array();
                foreach ($searchWords as $orIndex => $words) {
                    $subject_query_params = array();
                    $subject_query = array('from' => '{db_prefix}topics AS t', 'inner_join' => array(), 'left_join' => array(), 'where' => array());
                    if ($modSettings['postmod_active']) {
                        $subject_query['where'][] = 't.approved = {int:is_approved}';
                    }
                    $numTables = 0;
                    $prev_join = 0;
                    $numSubjectResults = 0;
                    foreach ($words['subject_words'] as $subjectWord) {
                        $numTables++;
                        if (in_array($subjectWord, $excludedSubjectWords)) {
                            $subject_query['left_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.word ' . (empty($modSettings['search_match_words']) ? 'LIKE {string:subject_words_' . $numTables . '_wild}' : '= {string:subject_words_' . $numTables . '}') . ' AND subj' . $numTables . '.id_topic = t.id_topic)';
                            $subject_query['where'][] = '(subj' . $numTables . '.word IS NULL)';
                        } else {
                            $subject_query['inner_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.id_topic = ' . ($prev_join === 0 ? 't' : 'subj' . $prev_join) . '.id_topic)';
                            $subject_query['where'][] = 'subj' . $numTables . '.word ' . (empty($modSettings['search_match_words']) ? 'LIKE {string:subject_words_' . $numTables . '_wild}' : '= {string:subject_words_' . $numTables . '}');
                            $prev_join = $numTables;
                        }
                        $subject_query_params['subject_words_' . $numTables] = $subjectWord;
                        $subject_query_params['subject_words_' . $numTables . '_wild'] = '%' . $subjectWord . '%';
                    }
                    if (!empty($userQuery)) {
                        if ($subject_query['from'] != '{db_prefix}messages AS m') {
                            $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_topic = t.id_topic)';
                        }
                        $subject_query['where'][] = $userQuery;
                    }
                    if (!empty($search_params['topic'])) {
                        $subject_query['where'][] = 't.id_topic = ' . $search_params['topic'];
                    }
                    if (!empty($minMsgID)) {
                        $subject_query['where'][] = 't.id_first_msg >= ' . $minMsgID;
                    }
                    if (!empty($maxMsgID)) {
                        $subject_query['where'][] = 't.id_last_msg <= ' . $maxMsgID;
                    }
                    if (!empty($boardQuery)) {
                        $subject_query['where'][] = 't.id_board ' . $boardQuery;
                    }
                    if (!empty($excludedPhrases)) {
                        if ($subject_query['from'] != '{db_prefix}messages AS m') {
                            $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)';
                        }
                        $count = 0;
                        foreach ($excludedPhrases as $phrase) {
                            $subject_query['where'][] = 'm.subject NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:excluded_phrases_' . $count . '}';
                            $subject_query_params['excluded_phrases_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($phrase, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $phrase), '\\\'') . '[[:>:]]';
                        }
                    }
                    $ignoreRequest = $smcFunc['db_search_query']('insert_log_search_results_subject', ($smcFunc['db_support_ignore'] ? '
						INSERT IGNORE INTO {db_prefix}log_search_results
							(id_search, id_topic, relevance, id_msg, num_matches)' : '') . '
						SELECT
							{int:id_search},
							t.id_topic,
							1000 * (
								{int:weight_frequency} / (t.num_replies + 1) +
								{int:weight_age} * CASE WHEN t.id_first_msg < {int:min_msg} THEN 0 ELSE (t.id_first_msg - {int:min_msg}) / {int:recent_message} END +
								{int:weight_length} * CASE WHEN t.num_replies < {int:huge_topic_posts} THEN t.num_replies / {int:huge_topic_posts} ELSE 1 END +
								{int:weight_subject} +
								{int:weight_sticky} * t.is_sticky
							) / {int:weight_total} AS relevance,
							' . (empty($userQuery) ? 't.id_first_msg' : 'm.id_msg') . ',
							1
						FROM ' . $subject_query['from'] . (empty($subject_query['inner_join']) ? '' : '
							INNER JOIN ' . implode('
							INNER JOIN ', $subject_query['inner_join'])) . (empty($subject_query['left_join']) ? '' : '
							LEFT JOIN ' . implode('
							LEFT JOIN ', $subject_query['left_join'])) . '
						WHERE ' . implode('
							AND ', $subject_query['where']) . (empty($modSettings['search_max_results']) ? '' : '
						LIMIT ' . ($modSettings['search_max_results'] - $numSubjectResults)), array_merge($subject_query_params, array('id_search' => $_SESSION['search_cache']['id_search'], 'weight_age' => $weight['age'], 'weight_frequency' => $weight['frequency'], 'weight_length' => $weight['length'], 'weight_sticky' => $weight['sticky'], 'weight_subject' => $weight['subject'], 'weight_total' => $weight_total, 'min_msg' => $minMsg, 'recent_message' => $recentMsg, 'huge_topic_posts' => $humungousTopicPosts, 'is_approved' => 1)));
                    // If the database doesn't support IGNORE to make this fast we need to do some tracking.
                    if (!$smcFunc['db_support_ignore']) {
                        while ($row = $smcFunc['db_fetch_row']($ignoreRequest)) {
                            // No duplicates!
                            if (isset($inserts[$row[1]])) {
                                continue;
                            }
                            foreach ($row as $key => $value) {
                                $inserts[$row[1]][] = (int) $row[$key];
                            }
                        }
                        $smcFunc['db_free_result']($ignoreRequest);
                        $numSubjectResults = count($inserts);
                    } else {
                        $numSubjectResults += $smcFunc['db_affected_rows']();
                    }
                    if (!empty($modSettings['search_max_results']) && $numSubjectResults >= $modSettings['search_max_results']) {
                        break;
                    }
                }
                // If there's data to be inserted for non-IGNORE databases do it here!
                if (!empty($inserts)) {
                    $smcFunc['db_insert']('', '{db_prefix}log_search_results', array('id_search' => 'int', 'id_topic' => 'int', 'relevance' => 'int', 'id_msg' => 'int', 'num_matches' => 'int'), $inserts, array('id_search', 'id_topic'));
                }
                $_SESSION['search_cache']['num_results'] = $numSubjectResults;
            } else {
                $main_query = array('select' => array('id_search' => $_SESSION['search_cache']['id_search'], 'relevance' => '0'), 'weights' => array(), 'from' => '{db_prefix}topics AS t', 'inner_join' => array('{db_prefix}messages AS m ON (m.id_topic = t.id_topic)'), 'left_join' => array(), 'where' => array(), 'group_by' => array(), 'parameters' => array('min_msg' => $minMsg, 'recent_message' => $recentMsg, 'huge_topic_posts' => $humungousTopicPosts, 'is_approved' => 1));
                if (empty($search_params['topic']) && empty($search_params['show_complete'])) {
                    $main_query['select']['id_topic'] = 't.id_topic';
                    $main_query['select']['id_msg'] = 'MAX(m.id_msg) AS id_msg';
                    $main_query['select']['num_matches'] = 'COUNT(*) AS num_matches';
                    $main_query['weights'] = array('frequency' => 'COUNT(*) / (MAX(t.num_replies) + 1)', 'age' => 'CASE WHEN MAX(m.id_msg) < {int:min_msg} THEN 0 ELSE (MAX(m.id_msg) - {int:min_msg}) / {int:recent_message} END', 'length' => 'CASE WHEN MAX(t.num_replies) < {int:huge_topic_posts} THEN MAX(t.num_replies) / {int:huge_topic_posts} ELSE 1 END', 'subject' => '0', 'first_message' => 'CASE WHEN MIN(m.id_msg) = MAX(t.id_first_msg) THEN 1 ELSE 0 END', 'sticky' => 'MAX(t.is_sticky)');
                    $main_query['group_by'][] = 't.id_topic';
                } else {
                    // This is outrageous!
                    $main_query['select']['id_topic'] = 'm.id_msg AS id_topic';
                    $main_query['select']['id_msg'] = 'm.id_msg';
                    $main_query['select']['num_matches'] = '1 AS num_matches';
                    $main_query['weights'] = array('age' => '((m.id_msg - t.id_first_msg) / CASE WHEN t.id_last_msg = t.id_first_msg THEN 1 ELSE t.id_last_msg - t.id_first_msg END)', 'first_message' => 'CASE WHEN m.id_msg = t.id_first_msg THEN 1 ELSE 0 END');
                    if (!empty($search_params['topic'])) {
                        $main_query['where'][] = 't.id_topic = {int:topic}';
                        $main_query['parameters']['topic'] = $search_params['topic'];
                    }
                    if (!empty($search_params['show_complete'])) {
                        $main_query['group_by'][] = 'm.id_msg, t.id_first_msg, t.id_last_msg';
                    }
                }
                // *** Get the subject results.
                $numSubjectResults = 0;
                if (empty($search_params['topic'])) {
                    $inserts = array();
                    // Create a temporary table to store some preliminary results in.
                    $smcFunc['db_search_query']('drop_tmp_log_search_topics', '
						DROP TABLE IF EXISTS {db_prefix}tmp_log_search_topics', array('db_error_skip' => true));
                    $createTemporary = $smcFunc['db_search_query']('create_tmp_log_search_topics', '
						CREATE TEMPORARY TABLE {db_prefix}tmp_log_search_topics (
							id_topic mediumint(8) unsigned NOT NULL default {string:string_zero},
							PRIMARY KEY (id_topic)
						) ENGINE=MEMORY', array('string_zero' => '0', 'db_error_skip' => true)) !== false;
                    // Clean up some previous cache.
                    if (!$createTemporary) {
                        $smcFunc['db_search_query']('delete_log_search_topics', '
							DELETE FROM {db_prefix}log_search_topics
							WHERE id_search = {int:search_id}', array('search_id' => $_SESSION['search_cache']['id_search']));
                    }
                    foreach ($searchWords as $orIndex => $words) {
                        $subject_query = array('from' => '{db_prefix}topics AS t', 'inner_join' => array(), 'left_join' => array(), 'where' => array(), 'params' => array());
                        $numTables = 0;
                        $prev_join = 0;
                        $count = 0;
                        foreach ($words['subject_words'] as $subjectWord) {
                            $numTables++;
                            if (in_array($subjectWord, $excludedSubjectWords)) {
                                if ($subject_query['from'] != '{db_prefix}messages AS m') {
                                    $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)';
                                }
                                $subject_query['left_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.word ' . (empty($modSettings['search_match_words']) ? 'LIKE {string:subject_not_' . $count . '}' : '= {string:subject_not_' . $count . '}') . ' AND subj' . $numTables . '.id_topic = t.id_topic)';
                                $subject_query['params']['subject_not_' . $count] = empty($modSettings['search_match_words']) ? '%' . $subjectWord . '%' : $subjectWord;
                                $subject_query['where'][] = '(subj' . $numTables . '.word IS NULL)';
                                $subject_query['where'][] = 'm.body NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:body_not_' . $count . '}';
                                $subject_query['params']['body_not_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($subjectWord, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $subjectWord), '\\\'') . '[[:>:]]';
                            } else {
                                $subject_query['inner_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.id_topic = ' . ($prev_join === 0 ? 't' : 'subj' . $prev_join) . '.id_topic)';
                                $subject_query['where'][] = 'subj' . $numTables . '.word LIKE {string:subject_like_' . $count . '}';
                                $subject_query['params']['subject_like_' . $count++] = empty($modSettings['search_match_words']) ? '%' . $subjectWord . '%' : $subjectWord;
                                $prev_join = $numTables;
                            }
                        }
                        if (!empty($userQuery)) {
                            if ($subject_query['from'] != '{db_prefix}messages AS m') {
                                $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)';
                            }
                            $subject_query['where'][] = '{raw:user_query}';
                            $subject_query['params']['user_query'] = $userQuery;
                        }
                        if (!empty($search_params['topic'])) {
                            $subject_query['where'][] = 't.id_topic = {int:topic}';
                            $subject_query['params']['topic'] = $search_params['topic'];
                        }
                        if (!empty($minMsgID)) {
                            $subject_query['where'][] = 't.id_first_msg >= {int:min_msg_id}';
                            $subject_query['params']['min_msg_id'] = $minMsgID;
                        }
                        if (!empty($maxMsgID)) {
                            $subject_query['where'][] = 't.id_last_msg <= {int:max_msg_id}';
                            $subject_query['params']['max_msg_id'] = $maxMsgID;
                        }
                        if (!empty($boardQuery)) {
                            $subject_query['where'][] = 't.id_board {raw:board_query}';
                            $subject_query['params']['board_query'] = $boardQuery;
                        }
                        if (!empty($excludedPhrases)) {
                            if ($subject_query['from'] != '{db_prefix}messages AS m') {
                                $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)';
                            }
                            $count = 0;
                            foreach ($excludedPhrases as $phrase) {
                                $subject_query['where'][] = 'm.subject NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:exclude_phrase_' . $count . '}';
                                $subject_query['where'][] = 'm.body NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:exclude_phrase_' . $count . '}';
                                $subject_query['params']['exclude_phrase_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($phrase, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $phrase), '\\\'') . '[[:>:]]';
                            }
                        }
                        // Nothing to search for?
                        if (empty($subject_query['where'])) {
                            continue;
                        }
                        $ignoreRequest = $smcFunc['db_search_query']('insert_log_search_topics', ($smcFunc['db_support_ignore'] ? '
							INSERT IGNORE INTO {db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics
								(' . ($createTemporary ? '' : 'id_search, ') . 'id_topic)' : '') . '
							SELECT ' . ($createTemporary ? '' : $_SESSION['search_cache']['id_search'] . ', ') . 't.id_topic
							FROM ' . $subject_query['from'] . (empty($subject_query['inner_join']) ? '' : '
								INNER JOIN ' . implode('
								INNER JOIN ', $subject_query['inner_join'])) . (empty($subject_query['left_join']) ? '' : '
								LEFT JOIN ' . implode('
								LEFT JOIN ', $subject_query['left_join'])) . '
							WHERE ' . implode('
								AND ', $subject_query['where']) . (empty($modSettings['search_max_results']) ? '' : '
							LIMIT ' . ($modSettings['search_max_results'] - $numSubjectResults)), $subject_query['params']);
                        // Don't do INSERT IGNORE? Manually fix this up!
                        if (!$smcFunc['db_support_ignore']) {
                            while ($row = $smcFunc['db_fetch_row']($ignoreRequest)) {
                                $ind = $createTemporary ? 0 : 1;
                                // No duplicates!
                                if (isset($inserts[$row[$ind]])) {
                                    continue;
                                }
                                $inserts[$row[$ind]] = $row;
                            }
                            $smcFunc['db_free_result']($ignoreRequest);
                            $numSubjectResults = count($inserts);
                        } else {
                            $numSubjectResults += $smcFunc['db_affected_rows']();
                        }
                        if (!empty($modSettings['search_max_results']) && $numSubjectResults >= $modSettings['search_max_results']) {
                            break;
                        }
                    }
                    // Got some non-MySQL data to plonk in?
                    if (!empty($inserts)) {
                        $smcFunc['db_insert']('', '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics', $createTemporary ? array('id_topic' => 'int') : array('id_search' => 'int', 'id_topic' => 'int'), $inserts, $createTemporary ? array('id_topic') : array('id_search', 'id_topic'));
                    }
                    if ($numSubjectResults !== 0) {
                        $main_query['weights']['subject'] = 'CASE WHEN MAX(lst.id_topic) IS NULL THEN 0 ELSE 1 END';
                        $main_query['left_join'][] = '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics AS lst ON (' . ($createTemporary ? '' : 'lst.id_search = {int:id_search} AND ') . 'lst.id_topic = t.id_topic)';
                        if (!$createTemporary) {
                            $main_query['parameters']['id_search'] = $_SESSION['search_cache']['id_search'];
                        }
                    }
                }
                $indexedResults = 0;
                // We building an index?
                if ($searchAPI->supportsMethod('indexedWordQuery', $query_params)) {
                    $inserts = array();
                    $smcFunc['db_search_query']('drop_tmp_log_search_messages', '
						DROP TABLE IF EXISTS {db_prefix}tmp_log_search_messages', array('db_error_skip' => true));
                    $createTemporary = $smcFunc['db_search_query']('create_tmp_log_search_messages', '
						CREATE TEMPORARY TABLE {db_prefix}tmp_log_search_messages (
							id_msg int(10) unsigned NOT NULL default {string:string_zero},
							PRIMARY KEY (id_msg)
						) ENGINE=MEMORY', array('string_zero' => '0', 'db_error_skip' => true)) !== false;
                    // Clear, all clear!
                    if (!$createTemporary) {
                        $smcFunc['db_search_query']('delete_log_search_messages', '
							DELETE FROM {db_prefix}log_search_messages
							WHERE id_search = {int:id_search}', array('id_search' => $_SESSION['search_cache']['id_search']));
                    }
                    foreach ($searchWords as $orIndex => $words) {
                        // Search for this word, assuming we have some words!
                        if (!empty($words['indexed_words'])) {
                            // Variables required for the search.
                            $search_data = array('insert_into' => ($createTemporary ? 'tmp_' : '') . 'log_search_messages', 'no_regexp' => $no_regexp, 'max_results' => $maxMessageResults, 'indexed_results' => $indexedResults, 'params' => array('id_search' => !$createTemporary ? $_SESSION['search_cache']['id_search'] : 0, 'excluded_words' => $excludedWords, 'user_query' => !empty($userQuery) ? $userQuery : '', 'board_query' => !empty($boardQuery) ? $boardQuery : '', 'topic' => !empty($search_params['topic']) ? $search_params['topic'] : 0, 'min_msg_id' => !empty($minMsgID) ? $minMsgID : 0, 'max_msg_id' => !empty($maxMsgID) ? $maxMsgID : 0, 'excluded_phrases' => !empty($excludedPhrases) ? $excludedPhrases : array(), 'excluded_index_words' => !empty($excludedIndexWords) ? $excludedIndexWords : array(), 'excluded_subject_words' => !empty($excludedSubjectWords) ? $excludedSubjectWords : array()));
                            $ignoreRequest = $searchAPI->indexedWordQuery($words, $search_data);
                            if (!$smcFunc['db_support_ignore']) {
                                while ($row = $smcFunc['db_fetch_row']($ignoreRequest)) {
                                    // No duplicates!
                                    if (isset($inserts[$row[0]])) {
                                        continue;
                                    }
                                    $inserts[$row[0]] = $row;
                                }
                                $smcFunc['db_free_result']($ignoreRequest);
                                $indexedResults = count($inserts);
                            } else {
                                $indexedResults += $smcFunc['db_affected_rows']();
                            }
                            if (!empty($maxMessageResults) && $indexedResults >= $maxMessageResults) {
                                break;
                            }
                        }
                    }
                    // More non-MySQL stuff needed?
                    if (!empty($inserts)) {
                        $smcFunc['db_insert']('', '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_messages', $createTemporary ? array('id_msg' => 'int') : array('id_msg' => 'int', 'id_search' => 'int'), $inserts, $createTemporary ? array('id_msg') : array('id_msg', 'id_search'));
                    }
                    if (empty($indexedResults) && empty($numSubjectResults) && !empty($modSettings['search_force_index'])) {
                        $context['search_errors']['query_not_specific_enough'] = true;
                        $_REQUEST['params'] = $context['params'];
                        return PlushSearch1();
                    } elseif (!empty($indexedResults)) {
                        $main_query['inner_join'][] = '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_messages AS lsm ON (lsm.id_msg = m.id_msg)';
                        if (!$createTemporary) {
                            $main_query['where'][] = 'lsm.id_search = {int:id_search}';
                            $main_query['parameters']['id_search'] = $_SESSION['search_cache']['id_search'];
                        }
                    }
                } else {
                    $orWhere = array();
                    $count = 0;
                    foreach ($searchWords as $orIndex => $words) {
                        $where = array();
                        foreach ($words['all_words'] as $regularWord) {
                            $where[] = 'm.body' . (in_array($regularWord, $excludedWords) ? ' NOT' : '') . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:all_word_body_' . $count . '}';
                            if (in_array($regularWord, $excludedWords)) {
                                $where[] = 'm.subject NOT' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:all_word_body_' . $count . '}';
                            }
                            $main_query['parameters']['all_word_body_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($regularWord, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $regularWord), '\\\'') . '[[:>:]]';
                        }
                        if (!empty($where)) {
                            $orWhere[] = count($where) > 1 ? '(' . implode(' AND ', $where) . ')' : $where[0];
                        }
                    }
                    if (!empty($orWhere)) {
                        $main_query['where'][] = count($orWhere) > 1 ? '(' . implode(' OR ', $orWhere) . ')' : $orWhere[0];
                    }
                    if (!empty($userQuery)) {
                        $main_query['where'][] = '{raw:user_query}';
                        $main_query['parameters']['user_query'] = $userQuery;
                    }
                    if (!empty($search_params['topic'])) {
                        $main_query['where'][] = 'm.id_topic = {int:topic}';
                        $main_query['parameters']['topic'] = $search_params['topic'];
                    }
                    if (!empty($minMsgID)) {
                        $main_query['where'][] = 'm.id_msg >= {int:min_msg_id}';
                        $main_query['parameters']['min_msg_id'] = $minMsgID;
                    }
                    if (!empty($maxMsgID)) {
                        $main_query['where'][] = 'm.id_msg <= {int:max_msg_id}';
                        $main_query['parameters']['max_msg_id'] = $maxMsgID;
                    }
                    if (!empty($boardQuery)) {
                        $main_query['where'][] = 'm.id_board {raw:board_query}';
                        $main_query['parameters']['board_query'] = $boardQuery;
                    }
                }
                // Did we either get some indexed results, or otherwise did not do an indexed query?
                if (!empty($indexedResults) || !$searchAPI->supportsMethod('indexedWordQuery', $query_params)) {
                    $relevance = '1000 * (';
                    $new_weight_total = 0;
                    foreach ($main_query['weights'] as $type => $value) {
                        $relevance .= $weight[$type] . ' * ' . $value . ' + ';
                        $new_weight_total += $weight[$type];
                    }
                    $main_query['select']['relevance'] = substr($relevance, 0, -3) . ') / ' . $new_weight_total . ' AS relevance';
                    $ignoreRequest = $smcFunc['db_search_query']('insert_log_search_results_no_index', ($smcFunc['db_support_ignore'] ? '
						INSERT IGNORE INTO ' . '{db_prefix}log_search_results
							(' . implode(', ', array_keys($main_query['select'])) . ')' : '') . '
						SELECT
							' . implode(',
							', $main_query['select']) . '
						FROM ' . $main_query['from'] . (empty($main_query['inner_join']) ? '' : '
							INNER JOIN ' . implode('
							INNER JOIN ', $main_query['inner_join'])) . (empty($main_query['left_join']) ? '' : '
							LEFT JOIN ' . implode('
							LEFT JOIN ', $main_query['left_join'])) . (!empty($main_query['where']) ? '
						WHERE ' : '') . implode('
							AND ', $main_query['where']) . (empty($main_query['group_by']) ? '' : '
						GROUP BY ' . implode(', ', $main_query['group_by'])) . (empty($modSettings['search_max_results']) ? '' : '
						LIMIT ' . $modSettings['search_max_results']), $main_query['parameters']);
                    // We love to handle non-good databases that don't support our ignore!
                    if (!$smcFunc['db_support_ignore']) {
                        $inserts = array();
                        while ($row = $smcFunc['db_fetch_row']($ignoreRequest)) {
                            // No duplicates!
                            if (isset($inserts[$row[2]])) {
                                continue;
                            }
                            foreach ($row as $key => $value) {
                                $inserts[$row[2]][] = (int) $row[$key];
                            }
                        }
                        $smcFunc['db_free_result']($ignoreRequest);
                        // Now put them in!
                        if (!empty($inserts)) {
                            $query_columns = array();
                            foreach ($main_query['select'] as $k => $v) {
                                $query_columns[$k] = 'int';
                            }
                            $smcFunc['db_insert']('', '{db_prefix}log_search_results', $query_columns, $inserts, array('id_search', 'id_topic'));
                        }
                        $_SESSION['search_cache']['num_results'] += count($inserts);
                    } else {
                        $_SESSION['search_cache']['num_results'] = $smcFunc['db_affected_rows']();
                    }
                }
                // Insert subject-only matches.
                if ($_SESSION['search_cache']['num_results'] < $modSettings['search_max_results'] && $numSubjectResults !== 0) {
                    $usedIDs = array_flip(empty($inserts) ? array() : array_keys($inserts));
                    $ignoreRequest = $smcFunc['db_search_query']('insert_log_search_results_sub_only', ($smcFunc['db_support_ignore'] ? '
						INSERT IGNORE INTO {db_prefix}log_search_results
							(id_search, id_topic, relevance, id_msg, num_matches)' : '') . '
						SELECT
							{int:id_search},
							t.id_topic,
							1000 * (
								{int:weight_frequency} / (t.num_replies + 1) +
								{int:weight_age} * CASE WHEN t.id_first_msg < {int:min_msg} THEN 0 ELSE (t.id_first_msg - {int:min_msg}) / {int:recent_message} END +
								{int:weight_length} * CASE WHEN t.num_replies < {int:huge_topic_posts} THEN t.num_replies / {int:huge_topic_posts} ELSE 1 END +
								{int:weight_subject} +
								{int:weight_sticky} * t.is_sticky
							) / {int:weight_total} AS relevance,
							t.id_first_msg,
							1
						FROM {db_prefix}topics AS t
							INNER JOIN {db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics AS lst ON (lst.id_topic = t.id_topic)' . ($createTemporary ? '' : 'WHERE lst.id_search = {int:id_search}') . (empty($modSettings['search_max_results']) ? '' : '
						LIMIT ' . ($modSettings['search_max_results'] - $_SESSION['search_cache']['num_results'])), array('id_search' => $_SESSION['search_cache']['id_search'], 'weight_age' => $weight['age'], 'weight_frequency' => $weight['frequency'], 'weight_length' => $weight['frequency'], 'weight_sticky' => $weight['frequency'], 'weight_subject' => $weight['frequency'], 'weight_total' => $weight_total, 'min_msg' => $minMsg, 'recent_message' => $recentMsg, 'huge_topic_posts' => $humungousTopicPosts));
                    // Once again need to do the inserts if the database don't support ignore!
                    if (!$smcFunc['db_support_ignore']) {
                        $inserts = array();
                        while ($row = $smcFunc['db_fetch_row']($ignoreRequest)) {
                            // No duplicates!
                            if (isset($usedIDs[$row[1]])) {
                                continue;
                            }
                            $usedIDs[$row[1]] = true;
                            $inserts[] = $row;
                        }
                        $smcFunc['db_free_result']($ignoreRequest);
                        // Now put them in!
                        if (!empty($inserts)) {
                            $smcFunc['db_insert']('', '{db_prefix}log_search_results', array('id_search' => 'int', 'id_topic' => 'int', 'relevance' => 'float', 'id_msg' => 'int', 'num_matches' => 'int'), $inserts, array('id_search', 'id_topic'));
                        }
                        $_SESSION['search_cache']['num_results'] += count($inserts);
                    } else {
                        $_SESSION['search_cache']['num_results'] += $smcFunc['db_affected_rows']();
                    }
                } else {
                    $_SESSION['search_cache']['num_results'] = 0;
                }
            }
        }
        // *** Retrieve the results to be shown on the page
        $participants = array();
        $request = $smcFunc['db_search_query']('', '
			SELECT ' . (empty($search_params['topic']) ? 'lsr.id_topic' : $search_params['topic'] . ' AS id_topic') . ', lsr.id_msg, lsr.relevance, lsr.num_matches
			FROM {db_prefix}log_search_results AS lsr' . ($search_params['sort'] == 'num_replies' ? '
				INNER JOIN {db_prefix}topics AS t ON (t.id_topic = lsr.id_topic)' : '') . '
			WHERE lsr.id_search = {int:id_search}
			ORDER BY ' . $search_params['sort'] . ' ' . $search_params['sort_dir'] . '
			LIMIT ' . (int) $_REQUEST['start'] . ', ' . $modSettings['search_results_per_page'], array('id_search' => $_SESSION['search_cache']['id_search']));
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            $context['topics'][$row['id_msg']] = array('relevance' => round($row['relevance'] / 10, 1) . '%', 'num_matches' => $row['num_matches'], 'matches' => array());
            // By default they didn't participate in the topic!
            $participants[$row['id_topic']] = false;
        }
        $smcFunc['db_free_result']($request);
        $num_results = $_SESSION['search_cache']['num_results'];
    }
    if (!empty($context['topics'])) {
        // Create an array for the permissions.
        $boards_can = array('post_reply_own' => boardsAllowedTo('post_reply_own'), 'post_reply_any' => boardsAllowedTo('post_reply_any'), 'mark_any_notify' => boardsAllowedTo('mark_any_notify'));
        // How's about some quick moderation?
        if (!empty($options['display_quick_mod'])) {
            $boards_can['lock_any'] = boardsAllowedTo('lock_any');
            $boards_can['lock_own'] = boardsAllowedTo('lock_own');
            $boards_can['make_sticky'] = boardsAllowedTo('make_sticky');
            $boards_can['move_any'] = boardsAllowedTo('move_any');
            $boards_can['move_own'] = boardsAllowedTo('move_own');
            $boards_can['remove_any'] = boardsAllowedTo('remove_any');
            $boards_can['remove_own'] = boardsAllowedTo('remove_own');
            $boards_can['merge_any'] = boardsAllowedTo('merge_any');
            $context['can_lock'] = in_array(0, $boards_can['lock_any']);
            $context['can_sticky'] = in_array(0, $boards_can['make_sticky']) && !empty($modSettings['enableStickyTopics']);
            $context['can_move'] = in_array(0, $boards_can['move_any']);
            $context['can_remove'] = in_array(0, $boards_can['remove_any']);
            $context['can_merge'] = in_array(0, $boards_can['merge_any']);
        }
        // What messages are we using?
        $msg_list = array_keys($context['topics']);
        // Load the posters...
        $request = $smcFunc['db_query']('', '
			SELECT id_member
			FROM {db_prefix}messages
			WHERE id_member != {int:no_member}
				AND id_msg IN ({array_int:message_list})
			LIMIT ' . count($context['topics']), array('message_list' => $msg_list, 'no_member' => 0));
        $posters = array();
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            $posters[] = $row['id_member'];
        }
        $smcFunc['db_free_result']($request);
        if (!empty($posters)) {
            loadMemberData(array_unique($posters));
        }
        // Get the messages out for the callback - select enough that it can be made to look just like Display.
        $messages_request = $smcFunc['db_query']('', '
			SELECT
				m.id_msg, m.subject, m.poster_name, m.poster_email, m.poster_time, m.id_member,
				m.icon, m.poster_ip, m.body, m.smileys_enabled, m.modified_time, m.modified_name,
				first_m.id_msg AS first_msg, first_m.subject AS first_subject, first_m.icon AS first_icon, first_m.poster_time AS first_poster_time,
				first_mem.id_member AS first_member_id, IFNULL(first_mem.real_name, first_m.poster_name) AS first_member_name,
				last_m.id_msg AS last_msg, last_m.poster_time AS last_poster_time, last_mem.id_member AS last_member_id,
				IFNULL(last_mem.real_name, last_m.poster_name) AS last_member_name, last_m.icon AS last_icon, last_m.subject AS last_subject,
				t.id_topic, t.is_sticky, t.locked, t.id_poll, t.num_replies, t.num_views,
				b.id_board, b.name AS board_name, c.id_cat, c.name AS cat_name
			FROM {db_prefix}messages AS m
				INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)
				INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
				INNER JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat)
				INNER JOIN {db_prefix}messages AS first_m ON (first_m.id_msg = t.id_first_msg)
				INNER JOIN {db_prefix}messages AS last_m ON (last_m.id_msg = t.id_last_msg)
				LEFT JOIN {db_prefix}members AS first_mem ON (first_mem.id_member = first_m.id_member)
				LEFT JOIN {db_prefix}members AS last_mem ON (last_mem.id_member = first_m.id_member)
			WHERE m.id_msg IN ({array_int:message_list})' . ($modSettings['postmod_active'] ? '
				AND m.approved = {int:is_approved}' : '') . '
			ORDER BY FIND_IN_SET(m.id_msg, {string:message_list_in_set})
			LIMIT {int:limit}', array('message_list' => $msg_list, 'is_approved' => 1, 'message_list_in_set' => implode(',', $msg_list), 'limit' => count($context['topics'])));
        // If there are no results that means the things in the cache got deleted, so pretend we have no topics anymore.
        if ($smcFunc['db_num_rows']($messages_request) == 0) {
            $context['topics'] = array();
        }
        // If we want to know who participated in what then load this now.
        if (!empty($modSettings['enableParticipation']) && !$user_info['is_guest']) {
            $result = $smcFunc['db_query']('', '
				SELECT id_topic
				FROM {db_prefix}messages
				WHERE id_topic IN ({array_int:topic_list})
					AND id_member = {int:current_member}
				GROUP BY id_topic
				LIMIT ' . count($participants), array('current_member' => $user_info['id'], 'topic_list' => array_keys($participants)));
            while ($row = $smcFunc['db_fetch_assoc']($result)) {
                $participants[$row['id_topic']] = true;
            }
            $smcFunc['db_free_result']($result);
        }
    }
    // Now that we know how many results to expect we can start calculating the page numbers.
    $context['page_index'] = constructPageIndex($scripturl . '?action=search2;params=' . $context['params'], $_REQUEST['start'], $num_results, $modSettings['search_results_per_page'], false);
    // Consider the search complete!
    if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2) {
        cache_put_data('search_start:' . ($user_info['is_guest'] ? $user_info['ip'] : $user_info['id']), null, 90);
    }
    $context['key_words'] =& $searchArray;
    // Setup the default topic icons... for checking they exist and the like!
    $stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'moved', 'recycled', 'wireless', 'clip');
    $context['icon_sources'] = array();
    foreach ($stable_icons as $icon) {
        $context['icon_sources'][$icon] = 'images_url';
    }
    $context['sub_template'] = 'results';
    $context['page_title'] = $txt['search_results'];
    $context['get_topics'] = 'prepareSearchContext';
    $context['can_send_pm'] = allowedTo('pm_send');
    $context['jump_to'] = array('label' => addslashes(un_htmlspecialchars($txt['jump_to'])), 'board_name' => addslashes(un_htmlspecialchars($txt['select_destination'])));
}
示例#18
0
function Register2($verifiedOpenID = false)
{
    global $txt, $modSettings, $context, $sourcedir;
    // Start collecting together any errors.
    $reg_errors = array();
    // Did we save some open ID fields?
    if ($verifiedOpenID && !empty($context['openid_save_fields'])) {
        foreach ($context['openid_save_fields'] as $id => $value) {
            $_POST[$id] = $value;
        }
    }
    // You can't register if it's disabled.
    if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 3) {
        fatal_lang_error('registration_disabled', false);
    }
    // Things we don't do for people who have already confirmed their OpenID allegances via register.
    if (!$verifiedOpenID) {
        // Well, if you don't agree, you can't register.
        if (!empty($modSettings['requireAgreement']) && empty($_SESSION['registration_agreed'])) {
            redirectexit();
        }
        // Make sure they came from *somewhere*, have a session.
        if (!isset($_SESSION['old_url'])) {
            redirectexit('action=register');
        }
        // Are they under age, and under age users are banned?
        if (!empty($modSettings['coppaAge']) && empty($modSettings['coppaType']) && empty($_SESSION['skip_coppa'])) {
            // !!! This should be put in Errors, imho.
            loadLanguage('Login');
            fatal_lang_error('under_age_registration_prohibited', false, array($modSettings['coppaAge']));
        }
        // Check whether the visual verification code was entered correctly.
        if (!empty($modSettings['reg_verification'])) {
            require_once $sourcedir . '/lib/Subs-Editor.php';
            $verificationOptions = array('id' => 'register');
            $context['visual_verification'] = create_control_verification($verificationOptions, true);
            if (is_array($context['visual_verification'])) {
                loadLanguage('Errors');
                foreach ($context['visual_verification'] as $error) {
                    $reg_errors[] = $txt['error_' . $error];
                }
            }
        }
    }
    foreach ($_POST as $key => $value) {
        if (!is_array($_POST[$key])) {
            $_POST[$key] = htmltrim__recursive(str_replace(array("\n", "\r"), '', $_POST[$key]));
        }
    }
    // Collect all extra registration fields someone might have filled in.
    $possible_strings = array('location', 'birthdate', 'time_format', 'buddy_list', 'pm_ignore_list', 'smiley_set', 'signature', 'personal_text', 'avatar', 'lngfile', 'secret_question', 'secret_answer');
    $possible_ints = array('pm_email_notify', 'notify_types', 'gender', 'id_theme');
    $possible_floats = array('time_offset');
    $possible_bools = array('notify_announcements', 'notify_regularity', 'notify_send_body', 'hide_email', 'show_online');
    if (isset($_POST['secret_answer']) && $_POST['secret_answer'] != '') {
        $_POST['secret_answer'] = md5($_POST['secret_answer']);
    }
    // Needed for isReservedName() and registerMember().
    require_once $sourcedir . '/lib/Subs-Members.php';
    // Validation... even if we're not a mall.
    if (isset($_POST['real_name']) && (!empty($modSettings['allow_editDisplayName']) || allowedTo('moderate_forum'))) {
        $_POST['real_name'] = trim(preg_replace('~[\\s]~u', ' ', $_POST['real_name']));
        if (trim($_POST['real_name']) != '' && !isReservedName($_POST['real_name']) && commonAPI::strlen($_POST['real_name']) < 60) {
            $possible_strings[] = 'real_name';
        }
    }
    // Handle a string as a birthdate...
    if (isset($_POST['birthdate']) && $_POST['birthdate'] != '') {
        $_POST['birthdate'] = strftime('%Y-%m-%d', strtotime($_POST['birthdate']));
    } elseif (!empty($_POST['bday1']) && !empty($_POST['bday2'])) {
        $_POST['birthdate'] = sprintf('%04d-%02d-%02d', empty($_POST['bday3']) ? 0 : (int) $_POST['bday3'], (int) $_POST['bday1'], (int) $_POST['bday2']);
    }
    // By default assume email is hidden, only show it if we tell it to.
    $_POST['hide_email'] = !empty($_POST['allow_email']) ? 0 : 1;
    // Validate the passed language file.
    if (isset($_POST['lngfile']) && !empty($modSettings['userLanguage'])) {
        // Do we have any languages?
        if (empty($context['languages'])) {
            getLanguages();
        }
        // Did we find it?
        if (isset($context['languages'][$_POST['lngfile']])) {
            $_SESSION['language'] = $_POST['lngfile'];
        } else {
            unset($_POST['lngfile']);
        }
    } else {
        unset($_POST['lngfile']);
    }
    // Set the options needed for registration.
    $regOptions = array('interface' => 'guest', 'username' => !empty($_POST['user']) ? $_POST['user'] : '', 'email' => !empty($_POST['email']) ? $_POST['email'] : '', 'password' => !empty($_POST['passwrd1']) ? $_POST['passwrd1'] : '', 'password_check' => !empty($_POST['passwrd2']) ? $_POST['passwrd2'] : '', 'openid' => !empty($_POST['openid_identifier']) ? $_POST['openid_identifier'] : '', 'auth_method' => !empty($_POST['authenticate']) ? $_POST['authenticate'] : '', 'check_reserved_name' => true, 'check_password_strength' => true, 'check_email_ban' => true, 'send_welcome_email' => !empty($modSettings['send_welcomeEmail']), 'require' => !empty($modSettings['coppaAge']) && !$verifiedOpenID && empty($_SESSION['skip_coppa']) ? 'coppa' : (empty($modSettings['registration_method']) ? 'nothing' : ($modSettings['registration_method'] == 1 ? 'activation' : 'approval')), 'extra_register_vars' => array(), 'theme_vars' => array());
    // Include the additional options that might have been filled in.
    foreach ($possible_strings as $var) {
        if (isset($_POST[$var])) {
            $regOptions['extra_register_vars'][$var] = commonAPI::htmlspecialchars($_POST[$var], ENT_QUOTES);
        }
    }
    foreach ($possible_ints as $var) {
        if (isset($_POST[$var])) {
            $regOptions['extra_register_vars'][$var] = (int) $_POST[$var];
        }
    }
    foreach ($possible_floats as $var) {
        if (isset($_POST[$var])) {
            $regOptions['extra_register_vars'][$var] = (double) $_POST[$var];
        }
    }
    foreach ($possible_bools as $var) {
        if (isset($_POST[$var])) {
            $regOptions['extra_register_vars'][$var] = empty($_POST[$var]) ? 0 : 1;
        }
    }
    // Registration options are always default options...
    if (isset($_POST['default_options'])) {
        $_POST['options'] = isset($_POST['options']) ? $_POST['options'] + $_POST['default_options'] : $_POST['default_options'];
    }
    $regOptions['theme_vars'] = isset($_POST['options']) && is_array($_POST['options']) ? $_POST['options'] : array();
    // Make sure they are clean, dammit!
    $regOptions['theme_vars'] = htmlspecialchars__recursive($regOptions['theme_vars']);
    // If Quick Reply hasn't been set then set it to be shown but collapsed.
    if (!isset($regOptions['theme_vars']['display_quick_reply'])) {
        $regOptions['theme_vars']['display_quick_reply'] = 1;
    }
    // Check whether we have fields that simply MUST be displayed?
    $request = smf_db_query('
		SELECT col_name, field_name, field_type, field_length, mask, show_reg
		FROM {db_prefix}custom_fields
		WHERE active = {int:is_active}', array('is_active' => 1));
    $custom_field_errors = array();
    while ($row = mysql_fetch_assoc($request)) {
        // Don't allow overriding of the theme variables.
        if (isset($regOptions['theme_vars'][$row['col_name']])) {
            unset($regOptions['theme_vars'][$row['col_name']]);
        }
        // Not actually showing it then?
        if (!$row['show_reg']) {
            continue;
        }
        // Prepare the value!
        $value = isset($_POST['customfield'][$row['col_name']]) ? trim($_POST['customfield'][$row['col_name']]) : '';
        // We only care for text fields as the others are valid to be empty.
        if (!in_array($row['field_type'], array('check', 'select', 'radio'))) {
            // Is it too long?
            if ($row['field_length'] && $row['field_length'] < commonAPI::strlen($value)) {
                $custom_field_errors[] = array('custom_field_too_long', array($row['field_name'], $row['field_length']));
            }
            // Any masks to apply?
            if ($row['field_type'] == 'text' && !empty($row['mask']) && $row['mask'] != 'none') {
                //!!! We never error on this - just ignore it at the moment...
                if ($row['mask'] == 'email' && (preg_match('~^[0-9A-Za-z=_+\\-/][0-9A-Za-z=_\'+\\-/\\.]*@[\\w\\-]+(\\.[\\w\\-]+)*(\\.[\\w]{2,6})$~', $value) === 0 || strlen($value) > 255)) {
                    $custom_field_errors[] = array('custom_field_invalid_email', array($row['field_name']));
                } elseif ($row['mask'] == 'number' && preg_match('~[^\\d]~', $value)) {
                    $custom_field_errors[] = array('custom_field_not_number', array($row['field_name']));
                } elseif (substr($row['mask'], 0, 5) == 'regex' && preg_match(substr($row['mask'], 5), $value) === 0) {
                    $custom_field_errors[] = array('custom_field_inproper_format', array($row['field_name']));
                }
            }
        }
        // Is this required but not there?
        if (trim($value) == '' && $row['show_reg'] > 1) {
            $custom_field_errors[] = array('custom_field_empty', array($row['field_name']));
        }
    }
    mysql_free_result($request);
    // Process any errors.
    if (!empty($custom_field_errors)) {
        loadLanguage('Errors');
        foreach ($custom_field_errors as $error) {
            $reg_errors[] = vsprintf($txt['error_' . $error[0]], $error[1]);
        }
    }
    // Lets check for other errors before trying to register the member.
    if (!empty($reg_errors)) {
        $_REQUEST['step'] = 2;
        return Register($reg_errors);
    }
    // If they're wanting to use OpenID we need to validate them first.
    if (empty($_SESSION['openid']['verified']) && !empty($_POST['authenticate']) && $_POST['authenticate'] == 'openid') {
        // What do we need to save?
        $save_variables = array();
        foreach ($_POST as $k => $v) {
            if (!in_array($k, array('sc', 'sesc', $context['session_var'], 'passwrd1', 'passwrd2', 'regSubmit'))) {
                $save_variables[$k] = $v;
            }
        }
        require_once $sourcedir . '/lib/Subs-OpenID.php';
        smf_openID_validate($_POST['openid_identifier'], false, $save_variables);
    } elseif ($verifiedOpenID || !empty($_POST['openid_identifier']) && $_POST['authenticate'] == 'openid') {
        $regOptions['username'] = !empty($_POST['user']) && trim($_POST['user']) != '' ? $_POST['user'] : $_SESSION['openid']['nickname'];
        $regOptions['email'] = !empty($_POST['email']) && trim($_POST['email']) != '' ? $_POST['email'] : $_SESSION['openid']['email'];
        $regOptions['auth_method'] = 'openid';
        $regOptions['openid'] = !empty($_POST['openid_identifier']) ? $_POST['openid_identifier'] : $_SESSION['openid']['openid_uri'];
    }
    $memberID = registerMember($regOptions, true);
    // What there actually an error of some kind dear boy?
    if (is_array($memberID)) {
        $reg_errors = array_merge($reg_errors, $memberID);
        $_REQUEST['step'] = 2;
        return Register($reg_errors);
    }
    // Do our spam protection now.
    spamProtection('register');
    HookAPI::callHook('register_process');
    // We'll do custom fields after as then we get to use the helper function!
    if (!empty($_POST['customfield'])) {
        require_once $sourcedir . '/Profile.php';
        require_once $sourcedir . '/Profile-Modify.php';
        makeCustomFieldChanges($memberID, 'register');
    }
    // If COPPA has been selected then things get complicated, setup the template.
    if (!empty($modSettings['coppaAge']) && empty($_SESSION['skip_coppa'])) {
        redirectexit('action=coppa;member=' . $memberID);
    } elseif (!empty($modSettings['registration_method'])) {
        EoS_Smarty::loadTemplate('register/base');
        EoS_Smarty::getConfigInstance()->registerHookTemplate('register_content_area', 'register/done');
        $context += array('page_title' => $txt['register'], 'title' => $txt['registration_successful'], 'description' => $modSettings['registration_method'] == 2 ? $txt['approval_after_registration'] : $txt['activate_after_registration']);
    } else {
        HookAPI::callHook('integrate_activate', array($row['member_name']));
        setLoginCookie(60 * $modSettings['cookieTime'], $memberID, sha1(sha1(strtolower($regOptions['username']) . $regOptions['password']) . $regOptions['register_vars']['password_salt']));
        redirectexit('action=login2;sa=check;member=' . $memberID, $context['server']['needs_login_fix']);
    }
}
function shd_search2()
{
    global $context, $smcFunc, $txt, $modSettings, $scripturl, $sourcedir;
    shd_is_allowed_to('shd_search', 0);
    if (!empty($context['load_average']) && !empty($modSettings['loadavg_search']) && $context['load_average'] >= $modSettings['loadavg_search']) {
        fatal_lang_error('loadavg_search_disabled', false);
    }
    // No, no, no... this is a bit hard on the server, so don't you go prefetching it!
    if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') {
        ob_end_clean();
        header('HTTP/1.1 403 Forbidden');
        die;
    }
    // We will need this.
    require_once $sourcedir . '/sd_source/Subs-SimpleDeskSearch.php';
    loadTemplate('sd_template/SimpleDesk-Search');
    $context['page_title'] = $txt['shd_search_results'];
    $context['linktree'][] = array('name' => $txt['shd_search_results']);
    $context['search_clauses'] = array('{query_see_ticket}');
    $context['search_params'] = array();
    // Departments first.
    $visible_depts = shd_allowed_to('access_helpdesk', false);
    $using_depts = array();
    if (!empty($_POST['search_dept']) && is_array($_POST['search_dept'])) {
        foreach ($_POST['search_dept'] as $dept) {
            if ((int) $dept > 0) {
                $using_depts[] = (int) $dept;
            }
        }
    }
    if (!empty($using_depts)) {
        $using_depts = array_intersect($using_depts, $visible_depts);
    }
    // No departments? Can't really do a lot, sorry. Bye then.
    if (empty($using_depts)) {
        return $context['sub_template'] = 'search_no_results';
    }
    // Is the selected list the same size as the list we can see? If it is, theory says that means we're picking every department we can see and don't need to exclude it.
    if (count($using_depts) != count($visible_depts)) {
        $context['search_clauses'][] = 'hdt.id_dept IN ({array_int:visible_depts})';
        $context['search_params']['visible_depts'] = $using_depts;
        // Also, we need to get the department list for displaying, only if we can actually see multiple departments at all.
        if ($context['shd_multi_dept']) {
            $query = $smcFunc['db_query']('', '
				SELECT id_dept, dept_name
				FROM {db_prefix}helpdesk_depts
				WHERE id_dept IN ({array_int:dept_list})
				ORDER BY dept_order', array('dept_list' => $using_depts));
            $context['search_dept_list'] = array();
            while ($row = $smcFunc['db_fetch_assoc']($query)) {
                $context['search_dept_list'][$row['id_dept']] = $row['dept_name'];
            }
            $smcFunc['db_free_result']($query);
        }
    }
    // Ticket urgency
    $using_urgency = array();
    if (!empty($_POST['urgency']) && is_array($_POST['urgency'])) {
        foreach ($_POST['urgency'] as $urgency) {
            $urgency = (int) $urgency;
            if ($urgency >= 0 && $urgency <= 5) {
                // All the currently defined urgencies
                $using_urgency[] = $urgency;
            }
        }
    }
    if (empty($using_urgency)) {
        return $context['sub_template'] = 'search_no_results';
    } else {
        $using_urgency = array_unique($using_urgency);
        if (count($using_urgency) < 6) {
            // We have less than 6 selected urgencies, which means we actually need to filter on them, as opposed to if all 6 are selected when we don't.
            $context['search_clauses'][] = 'hdt.urgency IN ({array_int:urgency})';
            $context['search_params']['urgency'] = $using_urgency;
        }
    }
    // Ticket scope
    // All empty? If so, bye.
    if (empty($_POST['scope_open']) && empty($_POST['scope_closed']) && empty($_POST['scope_recycle'])) {
        return $context['sub_template'] = 'search_no_results';
    } elseif (empty($_POST['scope_open']) || empty($_POST['scope_closed']) || empty($_POST['scope_recycle'])) {
        $status = array();
        if (!empty($_POST['scope_open'])) {
            $status = array_merge($status, array(TICKET_STATUS_NEW, TICKET_STATUS_PENDING_STAFF, TICKET_STATUS_PENDING_USER, TICKET_STATUS_WITH_SUPERVISOR, TICKET_STATUS_ESCALATED));
        }
        if (!empty($_POST['scope_closed'])) {
            $status = array_merge($status, array(TICKET_STATUS_CLOSED));
        }
        if (!empty($_POST['scope_recycle'])) {
            $status = array_merge($status, array(TICKET_STATUS_DELETED));
        }
        $context['search_clauses'][] = 'hdt.status IN ({array_int:status})';
        $context['search_params']['status'] = $status;
        // That's ticket level status taken care of. We'll pick up recycled items in non recycled tickets separately since it's only relevant if you're actually searching text.
    }
    // Ticket starter
    $starters = shd_get_named_people('starter');
    if (!empty($starters)) {
        $context['search_clauses'][] = 'hdt.id_member_started IN ({array_int:member_started})';
        $context['search_params']['member_started'] = $starters;
    }
    // Ticket assigned to
    $assignees = shd_get_named_people('assignee');
    if (!empty($assignees)) {
        $context['search_clauses'][] = 'hdt.id_member_assigned IN ({array_int:member_assigned})';
        $context['search_params']['member_assigned'] = $assignees;
    }
    // Lastly, page number. We're doing something different to SMF's normal style here. Long and complicated, but there you go.
    if (isset($_POST['page'])) {
        $context['pagenum'] = (int) $_POST['page'];
    }
    if (empty($context['pagenum']) || $context['pagenum'] < 1) {
        $context['pagenum'] = 1;
    }
    $number_per_page = 20;
    // OK, so are there any words? If not, execute this sucker the quick way and get out to the template quick.
    $context['search_terms'] = !empty($_POST['search']) ? trim($_POST['search']) : '';
    // Also, did we select some text but fail to select what it was searching in? If so, kick it out.
    if (!empty($context['search_terms']) && empty($_POST['search_subjects']) && empty($_POST['search_tickets']) && empty($_POST['search_replies'])) {
        return $context['sub_template'] = 'search_no_results';
    } elseif (!empty($context['search_terms'])) {
        // We're using search terms, and we need to store the areas we're covering. Only makes sense if we're using terms though.
        $context['search_params']['areas'] = array();
        foreach (array('subjects', 'tickets', 'replies') as $area) {
            if (!empty($_POST['search_' . $area])) {
                $context['search_params']['areas'][$area] = true;
            }
        }
        // While we're at it, see if we actually have any words to search for.
        $tokens = shd_tokeniser($context['search_terms']);
        $count_tokens = count($tokens);
        // No actual words?
        if ($count_tokens == 0) {
            $context['search_terms'] = '';
            unset($context['search_params']['areas']);
        }
    }
    // Spam me not!
    if (empty($_SESSION['lastsearch'])) {
        spamProtection('search');
    } else {
        list($temp_clauses, $temp_params, $temp_terms) = unserialize($_SESSION['lastsearch']);
        if ($temp_clauses != $context['search_clauses'] || $temp_params != $context['search_params'] || $temp_terms != $context['search_terms']) {
            spamProtection('search');
        }
    }
    $_SESSION['lastsearch'] = serialize(array($context['search_clauses'], $context['search_params'], $context['search_terms']));
    $context['search_params']['start'] = ($context['pagenum'] - 1) * $number_per_page;
    $context['search_params']['limit'] = $number_per_page;
    if (empty($context['search_terms'])) {
        // This is where it starts to get expensive, *sob*. We first have to query to get the number of applicable rows.
        $query = shd_db_query('', '
			SELECT COUNT(id_ticket)
			FROM {db_prefix}helpdesk_tickets AS hdt
			WHERE ' . implode(' AND ', $context['search_clauses']) . ' LIMIT 1000', $context['search_params']);
        list($count) = $smcFunc['db_fetch_row']($query);
        if ($count == 0) {
            $smcFunc['db_free_result']($query);
            return $context['sub_template'] = 'search_no_results';
        }
        // OK, at least one result, awesome. Are we off the end of the list?
        if ($context['search_params']['start'] > $count) {
            $context['search_params']['start'] = $count - $count % $number_per_page;
            $context['pagenum'] = $context['search_params']['start'] / $number_per_page + 1;
            $context['num_results'] = $count;
        }
        $query = shd_db_query('', '
			SELECT hdt.id_ticket, hdt.id_dept, hdd.dept_name, hdt.subject, hdt.urgency, hdt.private, hdt.last_updated, hdtr.body,
				hdtr.smileys_enabled, hdtr.id_member AS id_member, IFNULL(mem.real_name, hdtr.poster_name) AS poster_name, hdtr.poster_time
			FROM {db_prefix}helpdesk_tickets AS hdt
				INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr ON (hdt.id_first_msg = hdtr.id_msg)
				INNER JOIN {db_prefix}helpdesk_depts AS hdd ON (hdt.id_dept = hdd.id_dept)
				LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = hdtr.id_member)
			WHERE ' . implode(' AND ', $context['search_clauses']) . '
			ORDER BY hdt.last_updated DESC
			LIMIT {int:start}, {int:limit}', $context['search_params']);
        $context['search_results'] = array();
        $page_pos = $context['search_params']['start'];
        // e.g. 0 on page 1, 10 for page 2, the first item will be page_pos + 1, so ++ it before using it.
        while ($row = $smcFunc['db_fetch_assoc']($query)) {
            $row['result'] = ++$page_pos;
            // Increment first, then use.
            $row['display_id'] = str_pad($row['id_ticket'], $modSettings['shd_zerofill'], '0', STR_PAD_LEFT);
            $row['is_ticket'] = true;
            // If we're here, we're only handling tickets anyway. If we're searching text we will need to know if it was a ticket or reply though.
            $row['dept_link'] = !$context['shd_multi_dept'] ? '' : '[<a href="' . $scripturl . '?action=helpdesk;sa=main;dept=' . $row['id_dept'] . '">' . $row['dept_name'] . '</a>] ';
            $context['search_results'][] = $row;
        }
        return $context['sub_template'] = 'search_results';
    } else {
        $context['match_all'] = empty($_POST['searchtype']) || $_POST['searchtype'] == 'all';
        // Then figure out what terms are being matched.
        $matches = array('subjects' => array(), 'messages' => array(), 'id_msg' => array());
        // Doing subjects. Fetch all the instances that match and begin filtering as we go.
        if (!empty($context['search_params']['areas']['subjects'])) {
            $query = shd_db_query('', '
				SELECT hdssw.id_word, hdt.id_first_msg
				FROM {db_prefix}helpdesk_search_subject_words AS hdssw
					INNER JOIN {db_prefix}helpdesk_tickets AS hdt ON (hdssw.id_ticket = hdt.id_ticket)
				WHERE {query_see_ticket}
					AND id_word IN ({array_string:tokens})', array('tokens' => $tokens));
            while ($row = $smcFunc['db_fetch_assoc']($query)) {
                $matches['subjects'][$row['id_first_msg']][$row['id_word']] = true;
            }
            $smcFunc['db_free_result']($query);
            // Now go through and figure out which tickets we're interested in keeping.
            if ($context['match_all']) {
                foreach ($matches['subjects'] as $msg => $ticket_words) {
                    if (count($ticket_words) != $count_tokens) {
                        // How many words did we match in this subject? If it isn't the number we're expecting, ditch it.
                        unset($matches['subjects'][$msg]);
                    }
                }
            }
            // Now, we just have a list of tickets to play with. Let's put that together in a master list.
            foreach ($matches['subjects'] as $msg => $ticket_words) {
                $matches['id_msg'][$msg] = true;
            }
            unset($matches['subjects']);
        }
        // Now we get the list of words that apply to tickets and replies. The process is different if we do one or both. Both, first.
        if (!empty($context['search_params']['areas']['tickets']) && !empty($context['search_params']['areas']['replies'])) {
            // If we're doing both replies and tickets themselves, we don't have to care too much about the message itself, except for being deleted.
            $query = shd_db_query('', '
				SELECT hdssw.id_word, hdt.id_first_msg
				FROM {db_prefix}helpdesk_search_subject_words AS hdssw
					INNER JOIN {db_prefix}helpdesk_tickets AS hdt ON (hdssw.id_ticket = hdt.id_ticket)
				WHERE {query_see_ticket}
					AND id_word IN ({array_string:tokens})' . (empty($_POST['scope_recycle']) || !shd_allowed_to('shd_access_recyclebin', 0) ? '
					AND hdtr.message_status = {int:not_deleted}' : ''), array('tokens' => $tokens, 'not_deleted' => MSG_STATUS_NORMAL));
            while ($row = $smcFunc['db_fetch_assoc']($query)) {
                $matches['messages'][$row['id_first_msg']][$row['id_word']] = true;
            }
            $smcFunc['db_free_result']($query);
            if ($context['match_all']) {
                foreach ($matches['messages'] as $msg => $ticket_words) {
                    if (count($ticket_words) != $count_tokens) {
                        // How many words did we match in this subject? If it isn't the number we're expecting, ditch it.
                        unset($matches['messages'][$msg]);
                    }
                }
            }
            // Now, we just have a list of tickets to play with. Let's put that together in a master list.
            foreach ($matches['messages'] as $msg => $ticket_words) {
                $matches['id_msg'][$msg] = true;
            }
            unset($matches['messages']);
        } elseif (!empty($context['search_params']['areas']['tickets']) || !empty($context['search_params']['areas']['replies'])) {
            $query = $smcFunc['db_query']('', '
				SELECT hdstw.id_word, hdstw.id_msg
				FROM {db_prefix}helpdesk_search_ticket_words AS hdstw
					INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr ON (hdstw.id_msg = hdtr.id_msg)
					INNER JOIN {db_prefix}helpdesk_tickets AS hdt ON (hdtr.id_ticket = hdt.id_ticket)
				WHERE id_word IN ({array_string:tokens})
					AND hdstw.id_msg {raw:operator} hdt.id_first_msg' . (empty($_POST['scope_recycle']) || !shd_allowed_to('shd_access_recyclebin', 0) ? '
					AND hdtr.message_status = {int:not_deleted}' : ''), array('tokens' => $tokens, 'not_deleted' => MSG_STATUS_NORMAL, 'operator' => !empty($context['search_params']['areas']['tickets']) ? '=' : '!='));
            while ($row = $smcFunc['db_fetch_assoc']($query)) {
                $matches['messages'][$row['id_msg']][$row['id_word']] = true;
            }
            $smcFunc['db_free_result']($query);
            if ($context['match_all']) {
                foreach ($matches['messages'] as $ticket => $ticket_words) {
                    if (count($ticket_words) != $count_tokens) {
                        // How many words did we match in this subject? If it isn't the number we're expecting, ditch it.
                        unset($matches['messages'][$ticket]);
                    }
                }
            }
            // Now, we just have a list of tickets to play with. Let's put that together in a master list.
            foreach ($matches['messages'] as $msg => $ticket_words) {
                $matches['id_msg'][$ticket] = true;
            }
            unset($matches['messages']);
        }
        // Aw, no matches?
        if (empty($matches['id_msg'])) {
            return $context['sub_template'] = 'search_no_results';
        }
        $context['search_clauses'][] = 'hdtr.id_msg IN ({array_int:msg})';
        $context['search_params']['msg'] = array_keys($matches['id_msg']);
        // How many results are there in total?
        $query = shd_db_query('', '
			SELECT COUNT(*)
			FROM {db_prefix}helpdesk_tickets AS hdt
				INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr ON (hdtr.id_ticket = hdt.id_ticket)
			WHERE ' . implode(' AND ', $context['search_clauses']) . ' LIMIT 1000', $context['search_params']);
        list($count) = $smcFunc['db_fetch_row']($query);
        if ($count == 0) {
            $smcFunc['db_free_result']($query);
            return $context['sub_template'] = 'search_no_results';
        }
        // OK, at least one result, awesome. Are we off the end of the list?
        if ($context['search_params']['start'] > $count) {
            $context['search_params']['start'] = $count - $count % $number_per_page;
            $context['pagenum'] = $context['search_params']['start'] / $number_per_page + 1;
            $context['num_results'] = $count;
        }
        // Get the results for displaying.
        $query = shd_db_query('', '
			SELECT hdt.id_ticket, hdt.id_dept, hdd.dept_name, hdt.subject, hdt.urgency, hdt.private, hdt.last_updated, hdtr.body,
				hdtr.smileys_enabled, hdtr.id_member AS id_member, IFNULL(mem.real_name, hdtr.poster_name) AS poster_name, hdtr.poster_time,
				hdt.id_first_msg, hdtr.id_msg
			FROM {db_prefix}helpdesk_ticket_replies AS hdtr
				INNER JOIN {db_prefix}helpdesk_tickets AS hdt ON (hdt.id_ticket = hdtr.id_ticket)
				INNER JOIN {db_prefix}helpdesk_depts AS hdd ON (hdt.id_dept = hdd.id_dept)
				LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = hdtr.id_member)
			WHERE ' . implode(' AND ', $context['search_clauses']) . '
			ORDER BY hdt.last_updated DESC, hdtr.id_msg DESC
			LIMIT {int:start}, {int:limit}', $context['search_params']);
        $context['search_results'] = array();
        $page_pos = $context['search_params']['start'];
        // e.g. 0 on page 1, 10 for page 2, the first item will be page_pos + 1, so ++ it before using it.
        while ($row = $smcFunc['db_fetch_assoc']($query)) {
            $row['result'] = ++$page_pos;
            // Increment first, then use.
            $row['display_id'] = str_pad($row['id_ticket'], $modSettings['shd_zerofill'], '0', STR_PAD_LEFT);
            $row['is_ticket'] = $row['id_msg'] == $row['id_first_msg'];
            // If the message we grabbed is the first message, this is actually a ticket, not a reply to one.
            $row['dept_link'] = !$context['shd_multi_dept'] ? '' : '[<a href="' . $scripturl . '?action=helpdesk;sa=main;dept=' . $row['id_dept'] . '">' . $row['dept_name'] . '</a>] ';
            $context['search_results'][] = $row;
        }
        return $context['sub_template'] = 'search_results';
    }
}
示例#20
0
function ReportToModerator2()
{
    global $txt, $scripturl, $topic, $board, $user_info, $modSettings, $sourcedir, $language, $context, $smcFunc;
    // You must have the proper permissions!
    isAllowedTo('report_any');
    // Make sure they aren't spamming.
    spamProtection('reporttm');
    require_once $sourcedir . '/Subs-Post.php';
    // No errors, yet.
    $post_errors = array();
    // Check their session.
    if (checkSession('post', '', false) != '') {
        $post_errors[] = 'session_timeout';
    }
    // Make sure we have a comment and it's clean.
    if (!isset($_POST['comment']) || $smcFunc['htmltrim']($_POST['comment']) === '') {
        $post_errors[] = 'no_comment';
    }
    $poster_comment = strtr($smcFunc['htmlspecialchars']($_POST['comment']), array("\r" => '', "\n" => '', "\t" => ''));
    // Guests need to provide their address!
    if ($user_info['is_guest']) {
        $_POST['email'] = !isset($_POST['email']) ? '' : trim($_POST['email']);
        if ($_POST['email'] === '') {
            $post_errors[] = 'no_email';
        } elseif (preg_match('~^[0-9A-Za-z=_+\\-/][0-9A-Za-z=_\'+\\-/\\.]*@[\\w\\-]+(\\.[\\w\\-]+)*(\\.[\\w]{2,6})$~', $_POST['email']) == 0) {
            $post_errors[] = 'bad_email';
        }
        isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt['guest_title']));
        $user_info['email'] = htmlspecialchars($_POST['email']);
    }
    // Could they get the right verification code?
    if ($user_info['is_guest'] && !empty($modSettings['guests_report_require_captcha'])) {
        require_once $sourcedir . '/Subs-Editor.php';
        $verificationOptions = array('id' => 'report');
        $context['require_verification'] = create_control_verification($verificationOptions, true);
        if (is_array($context['require_verification'])) {
            $post_errors = array_merge($post_errors, $context['require_verification']);
        }
    }
    // Any errors?
    if (!empty($post_errors)) {
        loadLanguage('Errors');
        $context['post_errors'] = array();
        foreach ($post_errors as $post_error) {
            $context['post_errors'][] = $txt['error_' . $post_error];
        }
        return ReportToModerator();
    }
    // Get the basic topic information, and make sure they can see it.
    $_POST['msg'] = (int) $_POST['msg'];
    $request = $smcFunc['db_query']('', '
		SELECT m.id_topic, m.id_board, m.subject, m.body, m.id_member AS id_poster, m.poster_name, mem.real_name
		FROM {db_prefix}messages AS m
			LEFT JOIN {db_prefix}members AS mem ON (m.id_member = mem.id_member)
		WHERE m.id_msg = {int:id_msg}
			AND m.id_topic = {int:current_topic}
		LIMIT 1', array('current_topic' => $topic, 'id_msg' => $_POST['msg']));
    if ($smcFunc['db_num_rows']($request) == 0) {
        fatal_lang_error('no_board', false);
    }
    $message = $smcFunc['db_fetch_assoc']($request);
    $smcFunc['db_free_result']($request);
    $poster_name = un_htmlspecialchars($message['real_name']) . ($message['real_name'] != $message['poster_name'] ? ' (' . $message['poster_name'] . ')' : '');
    $reporterName = un_htmlspecialchars($user_info['name']) . ($user_info['name'] != $user_info['username'] && $user_info['username'] != '' ? ' (' . $user_info['username'] . ')' : '');
    $subject = un_htmlspecialchars($message['subject']);
    // Get a list of members with the moderate_board permission.
    require_once $sourcedir . '/Subs-Members.php';
    $moderators = membersAllowedTo('moderate_board', $board);
    $request = $smcFunc['db_query']('', '
		SELECT id_member, email_address, lngfile, mod_prefs
		FROM {db_prefix}members
		WHERE id_member IN ({array_int:moderator_list})
			AND notify_types != {int:notify_types}
		ORDER BY lngfile', array('moderator_list' => $moderators, 'notify_types' => 4));
    // Check that moderators do exist!
    if ($smcFunc['db_num_rows']($request) == 0) {
        fatal_lang_error('no_mods', false);
    }
    // If we get here, I believe we should make a record of this, for historical significance, yabber.
    if (empty($modSettings['disable_log_report'])) {
        $request2 = $smcFunc['db_query']('', '
			SELECT id_report, ignore_all
			FROM {db_prefix}log_reported
			WHERE id_msg = {int:id_msg}
				AND (closed = {int:not_closed} OR ignore_all = {int:ignored})
			ORDER BY ignore_all DESC', array('id_msg' => $_POST['msg'], 'not_closed' => 0, 'ignored' => 1));
        if ($smcFunc['db_num_rows']($request2) != 0) {
            list($id_report, $ignore) = $smcFunc['db_fetch_row']($request2);
        }
        $smcFunc['db_free_result']($request2);
        // If we're just going to ignore these, then who gives a monkeys...
        if (!empty($ignore)) {
            redirectexit('topic=' . $topic . '.msg' . $_POST['msg'] . '#msg' . $_POST['msg']);
        }
        // Already reported? My god, we could be dealing with a real rogue here...
        if (!empty($id_report)) {
            $smcFunc['db_query']('', '
				UPDATE {db_prefix}log_reported
				SET num_reports = num_reports + 1, time_updated = {int:current_time}
				WHERE id_report = {int:id_report}', array('current_time' => time(), 'id_report' => $id_report));
        } else {
            if (empty($message['real_name'])) {
                $message['real_name'] = $message['poster_name'];
            }
            $smcFunc['db_insert']('', '{db_prefix}log_reported', array('id_msg' => 'int', 'id_topic' => 'int', 'id_board' => 'int', 'id_member' => 'int', 'membername' => 'string', 'subject' => 'string', 'body' => 'string', 'time_started' => 'int', 'time_updated' => 'int', 'num_reports' => 'int', 'closed' => 'int'), array($_POST['msg'], $message['id_topic'], $message['id_board'], $message['id_poster'], $message['real_name'], $message['subject'], $message['body'], time(), time(), 1, 0), array('id_report'));
            $id_report = $smcFunc['db_insert_id']('{db_prefix}log_reported', 'id_report');
        }
        // Now just add our report...
        if ($id_report) {
            $smcFunc['db_insert']('', '{db_prefix}log_reported_comments', array('id_report' => 'int', 'id_member' => 'int', 'membername' => 'string', 'email_address' => 'string', 'member_ip' => 'string', 'comment' => 'string', 'time_sent' => 'int'), array($id_report, $user_info['id'], $user_info['name'], $user_info['email'], $user_info['ip'], $poster_comment, time()), array('id_comment'));
        }
    }
    // Find out who the real moderators are - for mod preferences.
    $request2 = $smcFunc['db_query']('', '
		SELECT id_member
		FROM {db_prefix}moderators
		WHERE id_board = {int:current_board}', array('current_board' => $board));
    $real_mods = array();
    while ($row = $smcFunc['db_fetch_assoc']($request2)) {
        $real_mods[] = $row['id_member'];
    }
    $smcFunc['db_free_result']($request2);
    // Send every moderator an email.
    while ($row = $smcFunc['db_fetch_assoc']($request)) {
        // Maybe they don't want to know?!
        if (!empty($row['mod_prefs'])) {
            list(, , $pref_binary) = explode('|', $row['mod_prefs']);
            if (!($pref_binary & 1) && (!($pref_binary & 2) || !in_array($row['id_member'], $real_mods))) {
                continue;
            }
        }
        $replacements = array('TOPICSUBJECT' => $subject, 'POSTERNAME' => $poster_name, 'REPORTERNAME' => $reporterName, 'TOPICLINK' => $scripturl . '?topic=' . $topic . '.msg' . $_POST['msg'] . '#msg' . $_POST['msg'], 'REPORTLINK' => !empty($id_report) ? $scripturl . '?action=moderate;area=reports;report=' . $id_report : '', 'COMMENT' => $_POST['comment']);
        $emaildata = loadEmailTemplate('report_to_moderator', $replacements, empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']);
        // Send it to the moderator.
        sendmail($row['email_address'], $emaildata['subject'], $emaildata['body'], $user_info['email'], null, false, 2);
    }
    $smcFunc['db_free_result']($request);
    // Keep track of when the mod reports get updated, that way we know when we need to look again.
    updateSettings(array('last_mod_report_action' => time()));
    // Back to the post we reported!
    redirectexit('reportsent;topic=' . $topic . '.msg' . $_POST['msg'] . '#msg' . $_POST['msg']);
}
示例#21
0
 /**
  * Pick a reminder type.
  * Accessed by sa=picktype
  */
 public function action_picktype()
 {
     global $context, $txt, $scripturl, $user_info, $webmaster_email, $language, $modSettings;
     checkSession();
     validateToken('remind');
     createToken('remind');
     require_once SUBSDIR . '/Auth.subs.php';
     // No where params just yet
     $where_params = array();
     // Coming with a known ID?
     if (!empty($_REQUEST['uid'])) {
         $where = 'id_member = {int:id_member}';
         $where_params['id_member'] = (int) $_REQUEST['uid'];
     } elseif (isset($_POST['user']) && $_POST['user'] != '') {
         $where = 'member_name = {string:member_name}';
         $where_params['member_name'] = $_POST['user'];
         $where_params['email_address'] = $_POST['user'];
     }
     // You must enter a username/email address.
     if (empty($where)) {
         fatal_lang_error('username_no_exist', false);
     }
     // Make sure we are not being slammed
     // Don't call this if you're coming from the "Choose a reminder type" page - otherwise you'll likely get an error
     if (!isset($_POST['reminder_type']) || !in_array($_POST['reminder_type'], array('email', 'secret'))) {
         spamProtection('remind');
     }
     $member = findUser($where, $where_params);
     $context['account_type'] = !empty($member['openid_uri']) ? 'openid' : 'password';
     // If the user isn't activated/approved, give them some feedback on what to do next.
     if ($member['is_activated'] != 1) {
         // Awaiting approval...
         if (trim($member['validation_code']) == '') {
             fatal_error($txt['registration_not_approved'] . ' <a href="' . $scripturl . '?action=activate;user='******'user'] . '">' . $txt['here'] . '</a>.', false);
         } else {
             fatal_error($txt['registration_not_activated'] . ' <a href="' . $scripturl . '?action=activate;user='******'user'] . '">' . $txt['here'] . '</a>.', false);
         }
     }
     // You can't get emailed if you have no email address.
     $member['email_address'] = trim($member['email_address']);
     if ($member['email_address'] == '') {
         fatal_error($txt['no_reminder_email'] . '<br />' . $txt['send_email'] . ' <a href="mailto:' . $webmaster_email . '">webmaster</a> ' . $txt['to_ask_password'] . '.');
     }
     // If they have no secret question then they can only get emailed the item, or they are requesting the email, send them an email.
     if (empty($member['secret_question']) || isset($_POST['reminder_type']) && $_POST['reminder_type'] == 'email') {
         // Randomly generate a new password, with only alpha numeric characters that is a max length of 10 chars.
         $password = generateValidationCode();
         require_once SUBSDIR . '/Mail.subs.php';
         $replacements = array('REALNAME' => $member['real_name'], 'REMINDLINK' => $scripturl . '?action=reminder;sa=setpassword;u=' . $member['id_member'] . ';code=' . $password, 'IP' => $user_info['ip'], 'MEMBERNAME' => $member['member_name'], 'OPENID' => $member['openid_uri']);
         $emaildata = loadEmailTemplate('forgot_' . $context['account_type'], $replacements, empty($member['lngfile']) || empty($modSettings['userLanguage']) ? $language : $member['lngfile']);
         $context['description'] = $txt['reminder_' . (!empty($member['openid_uri']) ? 'openid_' : '') . 'sent'];
         // If they were using OpenID simply email them their OpenID identity.
         sendmail($member['email_address'], $emaildata['subject'], $emaildata['body'], null, null, false, 1);
         if (empty($member['openid_uri'])) {
             // Set the password in the database.
             updateMemberData($member['id_member'], array('validation_code' => substr(md5($password), 0, 10)));
         }
         // Set up the template.
         $context['sub_template'] = 'sent';
         // Dont really.
         return;
     } elseif (isset($_POST['reminder_type']) && $_POST['reminder_type'] == 'secret') {
         return secretAnswerInput();
     }
     // No we're here setup the context for template number 2!
     $context['sub_template'] = 'reminder_pick';
     $context['current_member'] = array('id' => $member['id_member'], 'name' => $member['member_name']);
 }
示例#22
0
function Login2()
{
    global $txt, $scripturl, $user_info, $user_settings, $smcFunc;
    global $cookiename, $maintenance, $modSettings, $context, $sc, $sourcedir;
    // Load cookie authentication stuff.
    require_once $sourcedir . '/Subs-Auth.php';
    if (isset($_GET['sa']) && $_GET['sa'] == 'salt' && !$user_info['is_guest']) {
        if (isset($_COOKIE[$cookiename]) && preg_match('~^a:[34]:\\{i:0;(i:\\d{1,6}|s:[1-8]:"\\d{1,8}");i:1;s:(0|40):"([a-fA-F0-9]{40})?";i:2;[id]:\\d{1,14};(i:3;i:\\d;)?\\}$~', $_COOKIE[$cookiename]) === 1) {
            list(, , $timeout) = @unserialize($_COOKIE[$cookiename]);
        } elseif (isset($_SESSION['login_' . $cookiename])) {
            list(, , $timeout) = @unserialize($_SESSION['login_' . $cookiename]);
        } else {
            trigger_error('Login2(): Cannot be logged in without a session or cookie', E_USER_ERROR);
        }
        $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4);
        updateMemberData($user_info['id'], array('password_salt' => $user_settings['password_salt']));
        setLoginCookie($timeout - time(), $user_info['id'], sha1($user_settings['passwd'] . $user_settings['password_salt']));
        redirectexit('action=login2;sa=check;member=' . $user_info['id'], $context['server']['needs_login_fix']);
    } elseif (isset($_GET['sa']) && $_GET['sa'] == 'check') {
        // Strike!  You're outta there!
        if ($_GET['member'] != $user_info['id']) {
            fatal_lang_error('login_cookie_error', false);
        }
        // Some whitelisting for login_url...
        if (empty($_SESSION['login_url'])) {
            redirectexit();
        } else {
            // Best not to clutter the session data too much...
            $temp = $_SESSION['login_url'];
            unset($_SESSION['login_url']);
            redirectexit($temp);
        }
    }
    // Beyond this point you are assumed to be a guest trying to login.
    if (!$user_info['is_guest']) {
        redirectexit();
    }
    // Set the login_url if it's not already set (but careful not to send us to an attachment).
    if (empty($_SESSION['login_url']) && isset($_SESSION['old_url']) && strpos($_SESSION['old_url'], 'dlattach') === false && preg_match('~(board|topic)[=,]~', $_SESSION['old_url']) != 0) {
        $_SESSION['login_url'] = $_SESSION['old_url'];
    }
    // Are you guessing with a script that doesn't keep the session id?
    spamProtection('login');
    // Been guessing a lot, haven't we?
    if (isset($_SESSION['failed_login']) && $_SESSION['failed_login'] >= $modSettings['failed_login_threshold'] * 3) {
        fatal_lang_error('login_threshold_fail', 'critical');
    }
    // Set up the cookie length.  (if it's invalid, just fall through and use the default.)
    if (isset($_POST['cookieneverexp']) || !empty($_POST['cookielength']) && $_POST['cookielength'] == -1) {
        $modSettings['cookieTime'] = 3153600;
    } elseif (!empty($_POST['cookielength']) && ($_POST['cookielength'] >= 1 || $_POST['cookielength'] <= 525600)) {
        $modSettings['cookieTime'] = (int) $_POST['cookielength'];
    }
    loadLanguage('Login');
    // Load the template stuff - wireless or normal.
    if (WIRELESS) {
        $context['sub_template'] = WIRELESS_PROTOCOL . '_login';
    } else {
        loadTemplate('Login');
        $context['sub_template'] = 'login';
    }
    // Set up the default/fallback stuff.
    $context['default_username'] = isset($_REQUEST['user']) ? preg_replace('~&amp;#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', htmlspecialchars($_REQUEST['user'])) : '';
    $context['default_password'] = '';
    $context['never_expire'] = $modSettings['cookieTime'] == 525600 || $modSettings['cookieTime'] == 3153600;
    $context['login_errors'] = array($txt['error_occured']);
    $context['page_title'] = $txt['login'];
    // Add the login chain to the link tree.
    $context['linktree'][] = array('url' => $scripturl . '?action=login', 'name' => $txt['login']);
    if (!empty($_REQUEST['openid_identifier']) && !empty($modSettings['enableOpenID'])) {
        require_once $sourcedir . '/Subs-OpenID.php';
        return smf_openID_validate($_REQUEST['openid_identifier']);
    }
    // You forgot to type your username, dummy!
    if (!isset($_REQUEST['user']) || $_REQUEST['user'] == '') {
        $context['login_errors'] = array($txt['need_username']);
        return;
    }
    // Hmm... maybe 'admin' will login with no password. Uhh... NO!
    if ((!isset($_POST['passwrd']) || $_POST['passwrd'] == '') && (!isset($_REQUEST['hash_passwrd']) || strlen($_REQUEST['hash_passwrd']) != 40)) {
        $context['login_errors'] = array($txt['no_password']);
        return;
    }
    // No funky symbols either.
    if (preg_match('~[<>&"\'=\\\\]~', preg_replace('~(&#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~', '', $_REQUEST['user'])) != 0) {
        $context['login_errors'] = array($txt['error_invalid_characters_username']);
        return;
    }
    // Are we using any sort of integration to validate the login?
    if (isset($modSettings['integrate_validate_login']) && is_callable($modSettings['integrate_validate_login'])) {
        if (call_user_func(strpos($modSettings['integrate_validate_login'], '::') === false ? $modSettings['integrate_validate_login'] : explode('::', $modSettings['integrate_validate_login']), $_REQUEST['user'], isset($_REQUEST['hash_passwrd']) && strlen($_REQUEST['hash_passwrd']) == 40 ? $_REQUEST['hash_passwrd'] : null, $modSettings['cookieTime']) == 'retry') {
            $context['login_errors'] = array($txt['login_hash_error']);
            $context['disable_login_hashing'] = true;
            return;
        }
    }
    // Load the data up!
    $request = $smcFunc['db_query']('', '
		SELECT passwd, id_member, id_group, lngfile, is_activated, email_address, additional_groups, member_name, password_salt,
			openid_uri, passwd_flood
		FROM {db_prefix}members
		WHERE ' . ($smcFunc['db_case_sensitive'] ? 'LOWER(member_name) = LOWER({string:user_name})' : 'member_name = {string:user_name}') . '
		LIMIT 1', array('user_name' => $smcFunc['db_case_sensitive'] ? strtolower($_REQUEST['user']) : $_REQUEST['user']));
    // Probably mistyped or their email, try it as an email address. (member_name first, though!)
    if ($smcFunc['db_num_rows']($request) == 0) {
        $smcFunc['db_free_result']($request);
        $request = $smcFunc['db_query']('', '
			SELECT passwd, id_member, id_group, lngfile, is_activated, email_address, additional_groups, member_name, password_salt, openid_uri,
			passwd_flood
			FROM {db_prefix}members
			WHERE email_address = {string:user_name}
			LIMIT 1', array('user_name' => $_REQUEST['user']));
        // Let them try again, it didn't match anything...
        if ($smcFunc['db_num_rows']($request) == 0) {
            $context['login_errors'] = array($txt['username_no_exist']);
            return;
        }
    }
    $user_settings = $smcFunc['db_fetch_assoc']($request);
    $smcFunc['db_free_result']($request);
    // Figure out the password using SMF's encryption - if what they typed is right.
    if (isset($_REQUEST['hash_passwrd']) && strlen($_REQUEST['hash_passwrd']) == 40) {
        // Needs upgrading?
        if (strlen($user_settings['passwd']) != 40) {
            $context['login_errors'] = array($txt['login_hash_error']);
            $context['disable_login_hashing'] = true;
            unset($user_settings);
            return;
        } elseif ($_REQUEST['hash_passwrd'] == sha1($user_settings['passwd'] . $sc)) {
            $sha_passwd = $user_settings['passwd'];
        } else {
            // Don't allow this!
            validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood']);
            $_SESSION['failed_login'] = @$_SESSION['failed_login'] + 1;
            if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold']) {
                redirectexit('action=reminder');
            } else {
                log_error($txt['incorrect_password'] . ' - <span class="remove">' . $user_settings['member_name'] . '</span>', 'user');
                $context['disable_login_hashing'] = true;
                $context['login_errors'] = array($txt['incorrect_password']);
                unset($user_settings);
                return;
            }
        }
    } else {
        $sha_passwd = sha1(strtolower($user_settings['member_name']) . un_htmlspecialchars($_POST['passwrd']));
    }
    // Bad password!  Thought you could fool the database?!
    if ($user_settings['passwd'] != $sha_passwd) {
        // Let's be cautious, no hacking please. thanx.
        validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood']);
        // Maybe we were too hasty... let's try some other authentication methods.
        $other_passwords = array();
        // None of the below cases will be used most of the time (because the salt is normally set.)
        if ($user_settings['password_salt'] == '') {
            // YaBB SE, Discus, MD5 (used a lot), SHA-1 (used some), SMF 1.0.x, IkonBoard, and none at all.
            $other_passwords[] = crypt($_POST['passwrd'], substr($_POST['passwrd'], 0, 2));
            $other_passwords[] = crypt($_POST['passwrd'], substr($user_settings['passwd'], 0, 2));
            $other_passwords[] = md5($_POST['passwrd']);
            $other_passwords[] = sha1($_POST['passwrd']);
            $other_passwords[] = md5_hmac($_POST['passwrd'], strtolower($user_settings['member_name']));
            $other_passwords[] = md5($_POST['passwrd'] . strtolower($user_settings['member_name']));
            $other_passwords[] = $_POST['passwrd'];
            // This one is a strange one... MyPHP, crypt() on the MD5 hash.
            $other_passwords[] = crypt(md5($_POST['passwrd']), md5($_POST['passwrd']));
            // Snitz style - SHA-256.  Technically, this is a downgrade, but most PHP configurations don't support sha256 anyway.
            if (strlen($user_settings['passwd']) == 64 && function_exists('mhash') && defined('MHASH_SHA256')) {
                $other_passwords[] = bin2hex(mhash(MHASH_SHA256, $_POST['passwrd']));
            }
            // phpBB3 users new hashing.  We now support it as well ;).
            $other_passwords[] = phpBB3_password_check($_POST['passwrd'], $user_settings['passwd']);
            // APBoard 2 Login Method.
            $other_passwords[] = md5(crypt($_REQUEST['passwrd'], 'CRYPT_MD5'));
        } elseif (strlen($user_settings['passwd']) == 32) {
            // vBulletin 3 style hashing?  Let's welcome them with open arms \o/.
            $other_passwords[] = md5(md5($_POST['passwrd']) . $user_settings['password_salt']);
            // Hmm.. p'raps it's Invision 2 style?
            $other_passwords[] = md5(md5($user_settings['password_salt']) . md5($_POST['passwrd']));
            // Some common md5 ones.
            $other_passwords[] = md5($user_settings['password_salt'] . $_POST['passwrd']);
            $other_passwords[] = md5($_POST['passwrd'] . $user_settings['password_salt']);
            $other_passwords[] = md5($_POST['passwrd']);
            $other_passwords[] = md5(md5($_POST['passwrd']));
        } elseif (strlen($user_settings['passwd']) == 40) {
            // Maybe they are using a hash from before the password fix.
            $other_passwords[] = sha1(strtolower($user_settings['member_name']) . un_htmlspecialchars($_POST['passwrd']));
            // BurningBoard3 style of hashing.
            $other_passwords[] = sha1($user_settings['password_salt'] . sha1($user_settings['password_salt'] . sha1($_REQUEST['passwrd'])));
            // Perhaps we converted to UTF-8 and have a valid password being hashed differently.
            if ($context['character_set'] == 'utf8' && !empty($modSettings['previousCharacterSet']) && $modSettings['previousCharacterSet'] != 'utf8') {
                // Try iconv first, for no particular reason.
                if (function_exists('iconv')) {
                    $other_passwords['iconv'] = sha1(strtolower(iconv('UTF-8', $modSettings['previousCharacterSet'], $user_settings['member_name'])) . un_htmlspecialchars(iconv('UTF-8', $modSettings['previousCharacterSet'], $_POST['passwrd'])));
                }
                // Say it aint so, iconv failed!
                if (empty($other_passwords['iconv']) && function_exists('mb_convert_encoding')) {
                    $other_passwords[] = sha1(strtolower(mb_convert_encoding($user_settings['member_name'], 'UTF-8', $modSettings['previousCharacterSet'])) . un_htmlspecialchars(mb_convert_encoding($_POST['passwrd'], 'UTF-8', $modSettings['previousCharacterSet'])));
                }
            }
        }
        // SMF's sha1 function can give a funny result on Linux (Not our fault!). If we've now got the real one let the old one be valid!
        if (strpos(strtolower(PHP_OS), 'win') !== 0) {
            require_once $sourcedir . '/Subs-Compat.php';
            $other_passwords[] = sha1_smf(strtolower($user_settings['member_name']) . un_htmlspecialchars($_POST['passwrd']));
        }
        // Whichever encryption it was using, let's make it use SMF's now ;).
        if (in_array($user_settings['passwd'], $other_passwords)) {
            $user_settings['passwd'] = $sha_passwd;
            $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4);
            // Update the password and set up the hash.
            updateMemberData($user_settings['id_member'], array('passwd' => $user_settings['passwd'], 'password_salt' => $user_settings['password_salt']));
        } else {
            // They've messed up again - keep a count to see if they need a hand.
            $_SESSION['failed_login'] = @$_SESSION['failed_login'] + 1;
            // Hmm... don't remember it, do you?  Here, try the password reminder ;).
            if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold']) {
                redirectexit('action=reminder');
            } else {
                // Log an error so we know that it didn't go well in the error log.
                log_error($txt['incorrect_password'] . ' - <span class="remove">' . $user_settings['member_name'] . '</span>', 'user');
                $context['login_errors'] = array($txt['incorrect_password']);
                return;
            }
        }
    } elseif (!empty($user_settings['passwd_flood'])) {
        // Let's be sure they wern't a little hacker.
        validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood'], true);
        // If we got here then we can reset the flood counter.
        updateMemberData($user_settings['id_member'], array('passwd_flood' => ''));
    }
    // Correct password, but they've got no salt; fix it!
    if ($user_settings['password_salt'] == '') {
        $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4);
        updateMemberData($user_settings['id_member'], array('password_salt' => $user_settings['password_salt']));
    }
    // Check their activation status.
    if (!checkActivation()) {
        return;
    }
    DoLogin();
}
 public function action_register2()
 {
     global $txt, $modSettings, $context, $user_info;
     // Start collecting together any errors.
     $reg_errors = Error_Context::context('register', 0);
     // Check they are who they should be
     checkSession();
     if (!validateToken('register', 'post', true, false)) {
         $reg_errors->addError('token_verification');
     }
     // You can't register if it's disabled.
     if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 3) {
         fatal_lang_error('registration_disabled', false);
     }
     // Well, if you don't agree, you can't register.
     if (!empty($modSettings['requireAgreement']) && !isset($_POST['checkbox_agreement'])) {
         $reg_errors->addError('agreement_unchecked');
     }
     // Make sure they came from *somewhere*, have a session.
     if (!isset($_SESSION['old_url'])) {
         redirectexit('action=register');
     }
     // Check their provider deatils match up correctly in case they're pulling something funny
     if ($_POST['provider'] != $_SESSION['extauth_info']['provider']) {
         redirectexit('action=register');
     }
     // Clean up
     foreach ($_POST as $key => $value) {
         if (!is_array($_POST[$key])) {
             $_POST[$key] = htmltrim__recursive(str_replace(array("\n", "\r"), '', $_POST[$key]));
         }
     }
     // Needed for isReservedName() and registerMember()
     require_once SUBSDIR . '/Members.subs.php';
     // Needed for generateValidationCode()
     require_once SUBSDIR . '/Auth.subs.php';
     // Set the options needed for registration.
     $regOptions = array('interface' => 'guest', 'username' => !empty($_POST['user']) ? $_POST['user'] : '', 'email' => !empty($_POST['email']) ? $_POST['email'] : '', 'check_reserved_name' => true, 'check_password_strength' => true, 'check_email_ban' => true, 'send_welcome_email' => !empty($modSettings['send_welcomeEmail']), 'require' => empty($modSettings['registration_method']) ? 'nothing' : ($modSettings['registration_method'] == 1 ? 'activation' : 'approval'));
     // Lets check for other errors before trying to register the member.
     if ($reg_errors->hasErrors()) {
         return $this->action_register();
     }
     mt_srand(time() + 1277);
     $regOptions['password'] = generateValidationCode();
     $regOptions['password_check'] = $regOptions['password'];
     // Registration needs to know your IP
     $req = request();
     $regOptions['ip'] = $user_info['ip'];
     $regOptions['ip2'] = $req->ban_ip();
     $memberID = registerMember($regOptions, 'register');
     // If there are "important" errors and you are not an admin: log the first error
     // Otherwise grab all of them and don't log anything
     if ($reg_errors->hasErrors(1) && !$user_info['is_admin']) {
         foreach ($reg_errors->prepareErrors(1) as $error) {
             fatal_error($error, 'general');
         }
     }
     // One last error check
     if ($reg_errors->hasErrors()) {
         return $this->action_register();
     }
     // Do our spam protection now.
     spamProtection('register');
     // Since all is well, we'll go ahead and associate the member's external account
     addAuth($memberID, $_SESSION['extauth_info']['provider'], $_SESSION['extauth_info']['uid'], $_SESSION['extauth_info']['name']);
     // Basic template variable setup.
     if (!empty($modSettings['registration_method'])) {
         loadTemplate('Register');
         $context += array('page_title' => $txt['register'], 'title' => $txt['registration_successful'], 'sub_template' => 'after', 'description' => $modSettings['registration_method'] == 2 ? $txt['approval_after_registration'] : $txt['activate_after_registration']);
     } else {
         call_integration_hook('integrate_activate', array($regOptions['username']));
         setLoginCookie(60 * $modSettings['cookieTime'], $memberID, hash('sha256', Util::strtolower($regOptions['username']) . $regOptions['password'] . $regOptions['register_vars']['password_salt']));
         redirectexit('action=auth;sa=check;member=' . $memberID, $context['server']['needs_login_fix']);
     }
 }