/**
     * Actually do the search of personal messages and show the results
     *
     * What it does:
     * - accessed with ?action=pm;sa=search2
     * - checks user input and searches the pm table for messages matching the query.
     * - uses the search_results sub template of the PersonalMessage template.
     * - show the results of the search query.
     */
    public function action_search2()
    {
        global $scripturl, $modSettings, $context, $txt, $memberContext;
        $db = database();
        // Make sure the server is able to do this right now
        if (!empty($modSettings['loadavg_search']) && $modSettings['current_load'] >= $modSettings['loadavg_search']) {
            fatal_lang_error('loadavg_search_disabled', false);
        }
        // Some useful general permissions.
        $context['can_send_pm'] = allowedTo('pm_send');
        // Some hardcoded variables that can be tweaked if required.
        $maxMembersToSearch = 500;
        // Extract all the search parameters.
        $search_params = array();
        if (isset($_REQUEST['params'])) {
            $temp_params = explode('|"|', base64_decode(strtr($_REQUEST['params'], array(' ' => '+'))));
            foreach ($temp_params as $i => $data) {
                @(list($k, $v) = explode('|\'|', $data));
                $search_params[$k] = $v;
            }
        }
        $context['start'] = isset($_GET['start']) ? (int) $_GET['start'] : 0;
        // 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'];
        }
        // Search modifiers
        $search_params['subject_only'] = !empty($search_params['subject_only']) || !empty($_REQUEST['subject_only']);
        $search_params['show_complete'] = !empty($search_params['show_complete']) || !empty($_REQUEST['show_complete']);
        $search_params['sent_only'] = !empty($search_params['sent_only']) || !empty($_REQUEST['sent_only']);
        $context['folder'] = empty($search_params['sent_only']) ? 'inbox' : 'sent';
        // 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'];
        }
        // This will be full of all kinds of parameters!
        $searchq_parameters = array();
        // If there's no specific user, then don't mention it in the main query.
        if (empty($search_params['userspec'])) {
            $userQuery = '';
        } else {
            // Set up so we can seach by user name, wildcards, like, etc
            $userString = strtr(Util::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)));
            require_once SUBSDIR . '/Members.subs.php';
            // Who matches those criteria?
            $members = membersBy('member_names', array('member_names' => $possible_users));
            foreach ($possible_users as $key => $possible_user) {
                $searchq_parameters['guest_user_name_implode_' . $key] = defined('DB_CASE_SENSITIVE') ? strtolower($possible_user) : $possible_user;
            }
            // Simply do nothing if there are too many members matching the criteria.
            if (count($members) > $maxMembersToSearch) {
                $userQuery = '';
            } elseif (count($members) == 0) {
                if ($context['folder'] === 'inbox') {
                    $uq = array();
                    $name = defined('DB_CASE_SENSITIVE') ? 'LOWER(pm.from_name)' : 'pm.from_name';
                    foreach (array_keys($possible_users) as $key) {
                        $uq[] = 'AND pm.id_member_from = 0 AND (' . $name . ' LIKE {string:guest_user_name_implode_' . $key . '})';
                    }
                    $userQuery = implode(' ', $uq);
                    $searchq_parameters['pm_from_name'] = defined('DB_CASE_SENSITIVE') ? 'LOWER(pm.from_name)' : 'pm.from_name';
                } else {
                    $userQuery = '';
                }
            } else {
                $memberlist = array();
                foreach ($members as $id) {
                    $memberlist[] = $id;
                }
                // Use the name as as sent from or sent to
                if ($context['folder'] === 'inbox') {
                    $uq = array();
                    $name = defined('DB_CASE_SENSITIVE') ? 'LOWER(pm.from_name)' : 'pm.from_name';
                    foreach (array_keys($possible_users) as $key) {
                        $uq[] = 'AND (pm.id_member_from IN ({array_int:member_list}) OR (pm.id_member_from = 0 AND (' . $name . ' LIKE {string:guest_user_name_implode_' . $key . '})))';
                    }
                    $userQuery = implode(' ', $uq);
                } else {
                    $userQuery = 'AND (pmr.id_member IN ({array_int:member_list}))';
                }
                $searchq_parameters['pm_from_name'] = defined('DB_CASE_SENSITIVE') ? 'LOWER(pm.from_name)' : 'pm.from_name';
                $searchq_parameters['member_list'] = $memberlist;
            }
        }
        // Setup the sorting variables...
        $sort_columns = array('pm.id_pm');
        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'] : 'pm.id_pm';
        $search_params['sort_dir'] = !empty($search_params['sort_dir']) && $search_params['sort_dir'] == 'asc' ? 'asc' : 'desc';
        // Sort out any labels we may be searching by.
        $labelQuery = '';
        if ($context['folder'] == 'inbox' && !empty($search_params['advanced']) && $context['currently_using_labels']) {
            // Came here from pagination?  Put them back into $_REQUEST for sanitization.
            if (isset($search_params['labels'])) {
                $_REQUEST['searchlabel'] = explode(',', $search_params['labels']);
            }
            // Assuming we have some labels - make them all integers.
            if (!empty($_REQUEST['searchlabel']) && is_array($_REQUEST['searchlabel'])) {
                $_REQUEST['searchlabel'] = array_map('intval', $_REQUEST['searchlabel']);
            } else {
                $_REQUEST['searchlabel'] = array();
            }
            // Now that everything is cleaned up a bit, make the labels a param.
            $search_params['labels'] = implode(',', $_REQUEST['searchlabel']);
            // No labels selected? That must be an error!
            if (empty($_REQUEST['searchlabel'])) {
                $context['search_errors']['no_labels_selected'] = true;
            } elseif (count($_REQUEST['searchlabel']) != count($context['labels'])) {
                $labelQuery = '
				AND {raw:label_implode}';
                $labelStatements = array();
                foreach ($_REQUEST['searchlabel'] as $label) {
                    $labelStatements[] = $db->quote('FIND_IN_SET({string:label}, pmr.labels) != 0', array('label' => $label));
                }
                $searchq_parameters['label_implode'] = '(' . implode(' OR ', $labelStatements) . ')';
            }
        }
        // Unfortunately, searching for words like this is going to be slow, so we're blacklisting them.
        $blacklisted_words = array('quote', 'the', 'is', 'it', 'are', 'if');
        // What are we actually searching for?
        $search_params['search'] = !empty($search_params['search']) ? $search_params['search'] : (isset($_REQUEST['search']) ? $_REQUEST['search'] : '');
        // If nothing is left to search on - we set an error!
        if (!isset($search_params['search']) || $search_params['search'] == '') {
            $context['search_errors']['invalid_search_string'] = true;
        }
        // Change non-word characters into spaces.
        $stripped_query = preg_replace('~(?:[\\x0B\\0\\x{A0}\\t\\r\\s\\n(){}\\[\\]<>!@$%^*.,:+=`\\~\\?/\\\\]+|&(?:amp|lt|gt|quot);)+~u', ' ', $search_params['search']);
        // Make the query lower case since it will case insensitive anyway.
        $stripped_query = un_htmlspecialchars(Util::strtolower($stripped_query));
        // 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 = preg_replace('~(?:^|\\s)(?:[-]?)"(?:[^"]+)"(?:$|\\s)~u', ' ', $search_params['search']);
        $wordArray = explode(' ', Util::htmlspecialchars(un_htmlspecialchars($wordArray), ENT_QUOTES));
        // A minus sign in front of a word excludes the word.... so...
        $excludedWords = array();
        // 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
        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 thats close to empty.
            if (($searchArray[$index] = trim($value, '-_\' ')) === '') {
                unset($searchArray[$index]);
            } elseif (in_array($searchArray[$index], $blacklisted_words)) {
                $foundBlackListedWords = true;
                unset($searchArray[$index]);
            }
            $searchArray[$index] = Util::strtolower(trim($value));
            if ($searchArray[$index] == '') {
                unset($searchArray[$index]);
            } else {
                // Sort out entities first.
                $searchArray[$index] = Util::htmlspecialchars($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>';
        }
        // This contains *everything*
        $searchWords = array_merge($searchArray, $excludedWords);
        // Make sure at least one word is being searched for.
        if (empty($searchArray)) {
            $context['search_errors']['invalid_search_string' . (!empty($foundBlackListedWords) ? '_blacklist' : '')] = true;
        }
        // Sort out the search query so the user can edit it - if they want.
        $context['search_params'] = $search_params;
        if (isset($context['search_params']['search'])) {
            $context['search_params']['search'] = Util::htmlspecialchars($context['search_params']['search']);
        }
        if (isset($context['search_params']['userspec'])) {
            $context['search_params']['userspec'] = Util::htmlspecialchars($context['search_params']['userspec']);
        }
        // Now we have all the parameters, combine them together for pagination and the like...
        $context['params'] = array();
        foreach ($search_params as $k => $v) {
            $context['params'][] = $k . '|\'|' . $v;
        }
        $context['params'] = base64_encode(implode('|"|', $context['params']));
        // Compile the subject query part.
        $andQueryParts = array();
        foreach ($searchWords as $index => $word) {
            if ($word == '') {
                continue;
            }
            if ($search_params['subject_only']) {
                $andQueryParts[] = 'pm.subject' . (in_array($word, $excludedWords) ? ' NOT' : '') . ' LIKE {string:search_' . $index . '}';
            } else {
                $andQueryParts[] = '(pm.subject' . (in_array($word, $excludedWords) ? ' NOT' : '') . ' LIKE {string:search_' . $index . '} ' . (in_array($word, $excludedWords) ? 'AND pm.body NOT' : 'OR pm.body') . ' LIKE {string:search_' . $index . '})';
            }
            $searchq_parameters['search_' . $index] = '%' . strtr($word, array('_' => '\\_', '%' => '\\%')) . '%';
        }
        $searchQuery = ' 1=1';
        if (!empty($andQueryParts)) {
            $searchQuery = implode(!empty($search_params['searchtype']) && $search_params['searchtype'] == 2 ? ' OR ' : ' AND ', $andQueryParts);
        }
        // Age limits?
        $timeQuery = '';
        if (!empty($search_params['minage'])) {
            $timeQuery .= ' AND pm.msgtime < ' . (time() - $search_params['minage'] * 86400);
        }
        if (!empty($search_params['maxage'])) {
            $timeQuery .= ' AND pm.msgtime > ' . (time() - $search_params['maxage'] * 86400);
        }
        // If we have errors - return back to the first screen...
        if (!empty($context['search_errors'])) {
            $_REQUEST['params'] = $context['params'];
            return $this->action_search();
        }
        // Get the number of results.
        $numResults = numPMSeachResults($userQuery, $labelQuery, $timeQuery, $searchQuery, $searchq_parameters);
        // Get all the matching message ids, senders and head pm nodes
        list($foundMessages, $posters, $head_pms) = loadPMSearchMessages($userQuery, $labelQuery, $timeQuery, $searchQuery, $searchq_parameters, $search_params);
        // Find the real head pm when in converstaion view
        if ($context['display_mode'] == 2 && !empty($head_pms)) {
            $real_pm_ids = loadPMSearchHeads($head_pms);
        }
        // Load the found user data
        $posters = array_unique($posters);
        if (!empty($posters)) {
            loadMemberData($posters);
        }
        // Sort out the page index.
        $context['page_index'] = constructPageIndex($scripturl . '?action=pm;sa=search2;params=' . $context['params'], $_GET['start'], $numResults, $modSettings['search_results_per_page'], false);
        $context['message_labels'] = array();
        $context['message_replied'] = array();
        $context['personal_messages'] = array();
        $context['first_label'] = array();
        // If we have results, we have work to do!
        if (!empty($foundMessages)) {
            $recipients = array();
            list($context['message_labels'], $context['message_replied'], $context['message_unread'], $context['first_label']) = loadPMRecipientInfo($foundMessages, $recipients, $context['folder'], true);
            // Prepare for the callback!
            $search_results = loadPMSearchResults($foundMessages, $search_params);
            $counter = 0;
            foreach ($search_results as $row) {
                // If there's no subject, use the default.
                $row['subject'] = $row['subject'] == '' ? $txt['no_subject'] : $row['subject'];
                // Load this posters context info, if its not there then fill in the essentials...
                if (!loadMemberContext($row['id_member_from'], true)) {
                    $memberContext[$row['id_member_from']]['name'] = $row['from_name'];
                    $memberContext[$row['id_member_from']]['id'] = 0;
                    $memberContext[$row['id_member_from']]['group'] = $txt['guest_title'];
                    $memberContext[$row['id_member_from']]['link'] = $row['from_name'];
                    $memberContext[$row['id_member_from']]['email'] = '';
                    $memberContext[$row['id_member_from']]['show_email'] = showEmailAddress(true, 0);
                    $memberContext[$row['id_member_from']]['is_guest'] = true;
                }
                // Censor anything we don't want to see...
                censorText($row['body']);
                censorText($row['subject']);
                // Parse out any BBC...
                $row['body'] = parse_bbc($row['body'], true, 'pm' . $row['id_pm']);
                // Highlight the hits
                $body_highlighted = '';
                $subject_highlighted = '';
                foreach ($searchArray as $query) {
                    // Fix the international characters in the keyword too.
                    $query = un_htmlspecialchars($query);
                    $query = trim($query, '\\*+');
                    $query = strtr(Util::htmlspecialchars($query), array('\\\'' => '\''));
                    $body_highlighted = preg_replace_callback('/((<[^>]*)|' . preg_quote(strtr($query, array('\'' => '&#039;')), '/') . ')/iu', array($this, '_highlighted_callback'), $row['body']);
                    $subject_highlighted = preg_replace('/(' . preg_quote($query, '/') . ')/iu', '<strong class="highlight">$1</strong>', $row['subject']);
                }
                // Set a link using the first label information
                $href = $scripturl . '?action=pm;f=' . $context['folder'] . (isset($context['first_label'][$row['id_pm']]) ? ';l=' . $context['first_label'][$row['id_pm']] : '') . ';pmid=' . ($context['display_mode'] == 2 && isset($real_pm_ids[$head_pms[$row['id_pm']]]) && $context['folder'] == 'inbox' ? $real_pm_ids[$head_pms[$row['id_pm']]] : $row['id_pm']) . '#msg_' . $row['id_pm'];
                $context['personal_messages'][] = array('id' => $row['id_pm'], 'member' => &$memberContext[$row['id_member_from']], 'subject' => $subject_highlighted, 'body' => $body_highlighted, 'time' => standardTime($row['msgtime']), 'html_time' => htmlTime($row['msgtime']), 'timestamp' => forum_time(true, $row['msgtime']), 'recipients' => &$recipients[$row['id_pm']], 'labels' => &$context['message_labels'][$row['id_pm']], 'fully_labeled' => count($context['message_labels'][$row['id_pm']]) == count($context['labels']), 'is_replied_to' => &$context['message_replied'][$row['id_pm']], 'href' => $href, 'link' => '<a href="' . $href . '">' . $subject_highlighted . '</a>', 'counter' => ++$counter);
            }
        }
        // Finish off the context.
        $context['page_title'] = $txt['pm_search_title'];
        $context['sub_template'] = 'search_results';
        $context['menu_data_' . $context['pm_menu_id']]['current_area'] = 'search';
        $context['linktree'][] = array('url' => $scripturl . '?action=pm;sa=search', 'name' => $txt['pm_search_bar_title']);
    }
Exemple #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');
        }
    }
Exemple #3
0
 /**
  * Display members of a group, and allow adding of members to a group.
  *
  * What it does:
  * - It can be called from ManageMembergroups if it needs templating within the admin environment.
  * - It shows a list of members that are part of a given membergroup.
  * - It is called by ?action=moderate;area=viewgroups;sa=members;group=x
  * - It requires the manage_membergroups permission.
  * - It allows to add and remove members from the selected membergroup.
  * - It allows sorting on several columns.
  * - It redirects to itself.
  * @uses ManageMembergroups template, group_members sub template.
  */
 public function action_members()
 {
     global $txt, $scripturl, $context, $modSettings, $user_info, $settings;
     $current_group = isset($_REQUEST['group']) ? (int) $_REQUEST['group'] : 0;
     // These will be needed
     require_once SUBSDIR . '/Membergroups.subs.php';
     require_once SUBSDIR . '/Members.subs.php';
     // Load up the group details.
     $context['group'] = membergroupById($current_group, true, true);
     // No browsing of guests, membergroup 0 or moderators or non-existing groups.
     if ($context['group'] === false || in_array($current_group, array(-1, 0, 3))) {
         fatal_lang_error('membergroup_does_not_exist', false);
     }
     $context['group']['id'] = $context['group']['id_group'];
     $context['group']['name'] = $context['group']['group_name'];
     // Fix the membergroup icons.
     $context['group']['icons'] = explode('#', $context['group']['icons']);
     $context['group']['icons'] = !empty($context['group']['icons'][0]) && !empty($context['group']['icons'][1]) ? str_repeat('<img src="' . $settings['images_url'] . '/group_icons/' . $context['group']['icons'][1] . '" alt="*" />', $context['group']['icons'][0]) : '';
     $context['group']['can_moderate'] = allowedTo('manage_membergroups') && (allowedTo('admin_forum') || $context['group']['group_type'] != 1);
     // The template is very needy
     $context['linktree'][] = array('url' => $scripturl . '?action=groups;sa=members;group=' . $context['group']['id'], 'name' => $context['group']['name']);
     $context['can_send_email'] = allowedTo('send_email_to_members');
     $context['sort_direction'] = isset($_REQUEST['desc']) ? 'down' : 'up';
     $context['start'] = $_REQUEST['start'];
     $context['can_moderate_forum'] = allowedTo('moderate_forum');
     // @todo: use createList
     // Load all the group moderators, for fun.
     $context['group']['moderators'] = array();
     $moderators = getGroupModerators($current_group);
     foreach ($moderators as $id_member => $name) {
         $context['group']['moderators'][] = array('id' => $id_member, 'name' => $name);
         if ($user_info['id'] == $id_member && $context['group']['group_type'] != 1) {
             $context['group']['can_moderate'] = true;
         }
     }
     // If this group is hidden then it can only "exist" if the user can moderate it!
     if ($context['group']['hidden'] && !$context['group']['can_moderate']) {
         fatal_lang_error('membergroup_does_not_exist', false);
     }
     // You can only assign membership if you are the moderator and/or can manage groups!
     if (!$context['group']['can_moderate']) {
         $context['group']['assignable'] = 0;
     } elseif ($context['group']['id'] == 1 && !allowedTo('admin_forum')) {
         $context['group']['assignable'] = 0;
     }
     // Removing member from group?
     if (isset($_POST['remove']) && !empty($_REQUEST['rem']) && is_array($_REQUEST['rem']) && $context['group']['assignable']) {
         // Security first
         checkSession();
         validateToken('mod-mgm');
         // Make sure we're dealing with integers only.
         foreach ($_REQUEST['rem'] as $key => $group) {
             $_REQUEST['rem'][$key] = (int) $group;
         }
         removeMembersFromGroups($_REQUEST['rem'], $current_group, true);
     } elseif (isset($_REQUEST['add']) && (!empty($_REQUEST['toAdd']) || !empty($_REQUEST['member_add'])) && $context['group']['assignable']) {
         // Make sure you can do this
         checkSession();
         validateToken('mod-mgm');
         $member_query = array(array('and' => 'not_in_group'));
         $member_parameters = array('not_in_group' => $current_group);
         // Get all the members to be added... taking into account names can be quoted ;)
         $_REQUEST['toAdd'] = strtr(Util::htmlspecialchars($_REQUEST['toAdd'], ENT_QUOTES), array('&quot;' => '"'));
         preg_match_all('~"([^"]+)"~', $_REQUEST['toAdd'], $matches);
         $member_names = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $_REQUEST['toAdd']))));
         foreach ($member_names as $index => $member_name) {
             $member_names[$index] = trim(Util::strtolower($member_names[$index]));
             if (strlen($member_names[$index]) == 0) {
                 unset($member_names[$index]);
             }
         }
         // Any members passed by ID?
         $member_ids = array();
         if (!empty($_REQUEST['member_add'])) {
             foreach ($_REQUEST['member_add'] as $id) {
                 if ($id > 0) {
                     $member_ids[] = (int) $id;
                 }
             }
         }
         // Construct the query pelements, first for adds by name
         if (!empty($member_ids)) {
             $member_query[] = array('or' => 'member_ids');
             $member_parameters['member_ids'] = $member_ids;
         }
         // And then adds by ID
         if (!empty($member_names)) {
             $member_query[] = array('or' => 'member_names');
             $member_parameters['member_names'] = $member_names;
         }
         // Get back the ones that were not already in the group
         $members = membersBy($member_query, $member_parameters);
         // Do the updates...
         if (!empty($members)) {
             addMembersToGroup($members, $current_group, $context['group']['hidden'] ? 'only_additional' : 'auto', true);
         }
     }
     // Sort out the sorting!
     $sort_methods = array('name' => 'real_name', 'email' => allowedTo('moderate_forum') ? 'email_address' : 'hide_email ' . (isset($_REQUEST['desc']) ? 'DESC' : 'ASC') . ', email_address', 'active' => 'last_login', 'registered' => 'date_registered', 'posts' => 'posts');
     // They didn't pick one, or tried a wrong one, so default to by name..
     if (!isset($_REQUEST['sort']) || !isset($sort_methods[$_REQUEST['sort']])) {
         $context['sort_by'] = 'name';
         $querySort = 'real_name' . (isset($_REQUEST['desc']) ? ' DESC' : ' ASC');
     } else {
         $context['sort_by'] = $_REQUEST['sort'];
         $querySort = $sort_methods[$_REQUEST['sort']] . (isset($_REQUEST['desc']) ? ' DESC' : ' ASC');
     }
     // The where on the query is interesting. Non-moderators should only see people who are in this group as primary.
     if ($context['group']['can_moderate']) {
         $where = $context['group']['is_post_group'] ? 'in_post_group' : 'in_group';
     } else {
         $where = $context['group']['is_post_group'] ? 'in_post_group' : 'in_group_no_add';
     }
     // Count members of the group.
     $context['total_members'] = countMembersBy($where, array($where => $current_group));
     $context['total_members'] = comma_format($context['total_members']);
     // Create the page index.
     $context['page_index'] = constructPageIndex($scripturl . '?action=' . ($context['group']['can_moderate'] ? 'moderate;area=viewgroups' : 'groups') . ';sa=members;group=' . $current_group . ';sort=' . $context['sort_by'] . (isset($_REQUEST['desc']) ? ';desc' : ''), $_REQUEST['start'], $context['total_members'], $modSettings['defaultMaxMembers']);
     // Fetch the members that meet the where criteria
     $context['members'] = membersBy($where, array($where => $current_group, 'order' => $querySort), true);
     foreach ($context['members'] as $id => $row) {
         $last_online = empty($row['last_login']) ? $txt['never'] : standardTime($row['last_login']);
         // Italicize the online note if they aren't activated.
         if ($row['is_activated'] % 10 != 1) {
             $last_online = '<em title="' . $txt['not_activated'] . '">' . $last_online . '</em>';
         }
         $context['members'][$id] = array('id' => $row['id_member'], 'name' => '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>', 'email' => $row['email_address'], 'show_email' => showEmailAddress(!empty($row['hide_email']), $row['id_member']), 'ip' => '<a href="' . $scripturl . '?action=trackip;searchip=' . $row['member_ip'] . '">' . $row['member_ip'] . '</a>', 'registered' => standardTime($row['date_registered']), 'last_online' => $last_online, 'posts' => comma_format($row['posts']), 'is_activated' => $row['is_activated'] % 10 == 1);
     }
     if (!empty($context['group']['assignable'])) {
         loadJavascriptFile('suggest.js', array('defer' => true));
     }
     // Select the template.
     $context['sub_template'] = 'group_members';
     $context['page_title'] = $txt['membergroups_members_title'] . ': ' . $context['group']['name'];
     createToken('mod-mgm');
 }