Example #1
0
function Post2()
{
    global $board, $topic, $txt, $modSettings, $sourcedir, $context;
    global $user_info, $board_info, $options, $backend_subdir;
    /*  todo: drafts -> plugin
    	if(in_array('dr', $context['admin_features'])) {
    		require_once($sourcedir . '/lib/Subs-Drafts.php');
    		enqueueThemeScript('drafts', 'scripts/drafts.js', true);
    		$context['have_drafts'] = true;
    	}
    	else*/
    $context['have_drafts'] = false;
    $context['auto_preview'] = isset($_REQUEST['autopreview']) && $_REQUEST['autopreview'] ? 1 : 0;
    $context['need_synhlt'] = true;
    $context['no_astream'] = isset($_REQUEST['noactivity']) && (int) $_REQUEST['noactivity'] == 1;
    $context['can_tag_users'] = allowedTo('tag_users');
    // 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 . '/lib/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 . '/lib/Subs-Editor.php';
        $verificationOptions = array('id' => 'post', 'skip_template' => true);
        $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 . '/lib/Subs-Post.php';
    loadLanguage('Post');
    // If this isn't a new topic load the topic info that we need.
    if (!empty($topic)) {
        $request = smf_db_query('
			SELECT t.locked, t.is_sticky, t.id_poll, t.approved, t.id_first_msg, t.id_last_msg, t.id_member_started, t.id_member_updated,
				t.id_board, t.id_prefix, t.id_layout, t.num_replies, b.automerge, ba.id_topic AS banned_from_topic
			FROM {db_prefix}topics AS t
			LEFT JOIN {db_prefix}boards AS b on b.id_board = t.id_board 
			LEFT JOIN {db_prefix}topicbans AS ba ON (ba.id_topic = {int:current_topic} AND ba.id_member = {int:current_member})
			WHERE t.id_topic = {int:current_topic}
			LIMIT 1', array('current_topic' => $topic, 'current_member' => $user_info['id']));
        $topic_info = mysql_fetch_assoc($request);
        mysql_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');
        }
        if ($topic_info['banned_from_topic'] != 0 && !$user_info['is_admin'] && !allowedTo('moderate_board') && !allowedTo('moderate_forum')) {
            fatal_lang_error('banned_from_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();
        }
        // drafts
        if (isset($_POST['lock'])) {
            $_POST['lock_draft'] = !empty($_POST['lock']) ? 1 : 0;
        } else {
            $_POST['lock_draft'] = !empty($topic_info['locked']) ? 1 : 0;
        }
        // it's not, grab from topic's current info
        if ($context['have_drafts']) {
            $draft = saveDraft();
            if (!empty($draft) && !in_array('session_timeout', $post_errors)) {
                if (isset($_REQUEST['xml'])) {
                    draftXmlReturn($draft);
                }
                EoS_Smarty::loadTemplate('post/draft_saved');
                $context['page_title'] = $txt['draft_saved_short'];
                return;
            }
        }
        $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'];
        // Are we saving a draft? If so, hand over control to the draft code -- except, in the case of a session failure
        $_POST['lock_draft'] = !empty($_POST['lock']) ? 1 : 0;
        if ($context['have_drafts']) {
            $draft = saveDraft();
            if (!empty($draft) && !in_array('session_timeout', $post_errors)) {
                if (isset($_REQUEST['xml'])) {
                    draftXmlReturn($draft);
                }
                EoS_Smarty::loadTemplate('post/draft_saved');
                $context['page_title'] = $txt['draft_saved_short'];
                return;
            }
        }
    } elseif (isset($_REQUEST['msg']) && !empty($topic)) {
        $_REQUEST['msg'] = (int) $_REQUEST['msg'];
        $request = smf_db_query('
			SELECT id_member, poster_name, poster_email, poster_time, approved, locked
			FROM {db_prefix}messages
			WHERE id_msg = {int:id_msg}
			LIMIT 1', array('id_msg' => $_REQUEST['msg']));
        if (mysql_num_rows($request) == 0) {
            fatal_lang_error('cant_find_messages', false);
        }
        $row = mysql_fetch_assoc($request);
        $msg_owner = $row['id_member'];
        mysql_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['locked'] && !(allowedTo('moderate_board') || allowedTo('moderate_forum'))) {
            fatal_lang_error('modify_message_locked', false);
        }
        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 ($context['have_drafts']) {
            $draft = saveDraft();
            if (!empty($draft) && !in_array('session_timeout', $post_errors)) {
                if (isset($_REQUEST['xml'])) {
                    draftXmlReturn($draft);
                }
                EoS_Smarty::loadTemplate('post/draft_saved');
                $context['page_title'] = $txt['draft_saved_short'];
                return;
            }
        }
    }
    // 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 (commonAPI::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']) || commonAPI::htmltrim(commonAPI::htmlspecialchars($_POST['subject'])) === '') {
        $post_errors[] = 'no_subject';
    }
    if (!isset($_POST['message']) || commonAPI::htmltrim(commonAPI::htmlspecialchars($_POST['message']), ENT_QUOTES) === '') {
        $post_errors[] = 'no_message';
    } elseif (!empty($modSettings['max_messageLength']) && commonAPI::strlen($_POST['message']) > $modSettings['max_messageLength']) {
        $post_errors[] = 'long_message';
    } else {
        // Prepare the message a bit for some additional testing.
        $_POST['message'] = commonAPI::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 (commonAPI::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']) && commonAPI::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 . '/lib/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(commonAPI::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 (commonAPI::strlen($_POST['subject']) > 100) {
        $_POST['subject'] = commonAPI::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 . '/lib/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'] = commonAPI::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 . '/lib/Subs-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 = smf_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) = 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_' . $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.
        smf_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 = smf_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++;
        }
        smf_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'];
    if (empty($attachIDs) && $_POST['icon'] == 'clip') {
        $_POST['icon'] = 'xx';
    }
    // 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, 'id_owner' => isset($msg_owner) ? $msg_owner : 0, 'locked' => !empty($_POST['lock_message']) && (allowedTo('moderate_board') || allowedTo('moderate_forum')));
    $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, 'topic_prefix' => isset($_REQUEST['topic_prefix']) ? intval($_REQUEST['topic_prefix']) : null, 'topic_layout' => (isset($_REQUEST['stickfirst']) && $_REQUEST['stickfirst'] ? 0x80 : 0) | (isset($_REQUEST['firstlayout']) && $_REQUEST['firstlayout'] ? $_REQUEST['firstlayout'] : 0), 'automerge' => !empty($topic) ? $topic_info['automerge'] : 0, 'id_first_msg' => !empty($topic) ? $topic_info['id_first_msg'] : 0, 'id_last_msg' => !empty($topic) ? $topic_info['id_last_msg'] : 0, 'id_member_started' => !empty($topic) ? $topic_info['id_member_started'] : 0, 'id_member_updated' => !empty($topic) ? $topic_info['id_member_updated'] : 0, 'is_approved' => !$modSettings['postmod_active'] || empty($topic) || !empty($board_info['cur_topic_approved']), 'num_replies' => !empty($topic) ? $topic_info['num_replies'] : 0);
    $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 {
        //handleUserTags($msgOptions['body']);
        createPost($msgOptions, $topicOptions, $posterOptions);
        if (isset($topicOptions['id'])) {
            $topic = $topicOptions['id'];
        }
        if (isset($_REQUEST['tags']) && !isset($_REQUEST['num_replies'])) {
            global $user_info;
            $result = smf_db_query('
              SELECT COUNT(*) as total
              FROM {db_prefix}tags_log
              WHERE ID_TOPIC = {int:id_topic}', array('id_topic' => $topic));
            $row = mysql_fetch_assoc($result);
            $nr_tags = $row['total'];
            mysql_free_result($result);
            // Check Tag restrictions
            $tags = explode(',', htmlspecialchars($_REQUEST['tags'], ENT_QUOTES));
            if ($nr_tags < $modSettings['smftags_set_maxtags']) {
                $count = 0;
                foreach ($tags as $tag) {
                    $tag = trim($tag);
                    if (empty($tag)) {
                        continue;
                    }
                    if ($count >= $modSettings['smftags_set_maxtags']) {
                        continue;
                    }
                    if (strlen($tag) < $modSettings['smftags_set_mintaglength']) {
                        continue;
                    }
                    if (strlen($tag) > $modSettings['smftags_set_maxtaglength']) {
                        continue;
                    }
                    $result = smf_db_query('
                      SELECT ID_TAG
                      FROM {db_prefix}tags
                      WHERE tag = {string:tag}', array('tag' => $tag));
                    if (0 == smf_db_affected_rows()) {
                        smf_db_query('INSERT INTO {db_prefix}tags
                          (tag, approved)
                          VALUES ({string:tag}, 1)', array('tag' => $tag));
                        $ID_TAG = smf_db_insert_id('{db_prefix}tags', 'ID_TAG');
                        smf_db_query('INSERT INTO {db_prefix}tags_log
                            (ID_TAG, ID_TOPIC, ID_MEMBER)
                            VALUES ({int:id_tag}, {int:topic}, {int:userid})', array('id_tag' => $ID_TAG, 'topic' => $topic, 'userid' => $user_info['id']));
                        $count++;
                    } else {
                        $row = mysql_fetch_assoc($result);
                        $ID_TAG = $row['ID_TAG'];
                        $result2 = smf_db_query('
                          SELECT ID FROM {db_prefix}tags_log
                          WHERE ID_TAG = {int:id_tag} AND ID_TOPIC = {int:topic}', array('id_tag' => $ID_TAG, 'topic' => $topic));
                        if (smf_db_affected_rows() != 0) {
                            continue;
                        }
                        mysql_free_result($result2);
                        smf_db_query('INSERT INTO {db_prefix}tags_log
                            (ID_TAG, ID_TOPIC, ID_MEMBER)
                            VALUES ({int:id_tag}, {int:topic}, {int:userid})', array('id_tag' => $ID_TAG, 'topic' => $topic, 'userid' => $user_info['id']));
                        $count++;
                    }
                    mysql_free_result($result);
                }
            }
        }
    }
    // Editing or posting an event?
    if (isset($_POST['calendar']) && (!isset($_REQUEST['eventid']) || $_REQUEST['eventid'] == -1)) {
        require_once $sourcedir . '/lib/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 . '/lib/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 = smf_db_query('
				SELECT id_member
				FROM {db_prefix}calendar
				WHERE id_event = {int:id_event}', array('id_event' => $_REQUEST['eventid']));
            $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'] == $user_info['id'] ? 'own' : 'any'));
        }
        // Delete it?
        if (isset($_REQUEST['deleteevent'])) {
            smf_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']);
            smf_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' => commonAPI::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'])) {
        smf_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')) {
        smf_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) {
        smf_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?
    // Um, did this come from a draft?
    if (!empty($_POST['draft_id']) && !empty($user_info['id'])) {
        $_POST['draft_id'] = (int) $_POST['draft_id'];
        smf_db_query('
			DELETE FROM {db_prefix}drafts
			WHERE id_draft = {int:draft}
				AND id_member = {int:member}
			LIMIT 1', array('draft' => $_POST['draft_id'], 'member' => $user_info['id']));
    }
    if (!empty($_REQUEST['goback'])) {
        // Mark the board as read.... because it might get confusing otherwise.
        smf_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) {
        CacheAPI::putCache('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');
    }
}
Example #2
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');
        }
    }