Example #1
5
 /**
  * Remove the like that was given
  */
 function testRemoveLikeTopic()
 {
     $liked_message = basicMessageInfo($this->id_topic, true, true);
     // Lets remove the like from the topic
     likePost(1, $liked_message, '-');
     // get the number of likes, better be none now
     $likescount = messageLikeCount($this->id_topic);
     $this->assertEqual($likescount, 0);
 }
    /**
     * Issue/manage an user's warning status.
     * @uses ProfileAccount template issueWarning sub template
     * @uses Profile template
     */
    public function action_issuewarning()
    {
        global $txt, $scripturl, $modSettings, $mbname, $context, $cur_profile;
        $memID = currentMemberID();
        // make sure the sub-template is set...
        loadTemplate('ProfileAccount');
        $context['sub_template'] = 'issueWarning';
        // We need this because of template_load_warning_variables
        loadTemplate('Profile');
        loadJavascriptFile('profile.js');
        // jQuery-UI FTW!
        $modSettings['jquery_include_ui'] = true;
        loadCSSFile('jquery.ui.slider.css');
        loadCSSFile('jquery.ui.theme.css');
        // Get all the actual settings.
        list($modSettings['warning_enable'], $modSettings['user_limit']) = explode(',', $modSettings['warning_settings']);
        // This stores any legitimate errors.
        $issueErrors = array();
        // Doesn't hurt to be overly cautious.
        if (empty($modSettings['warning_enable']) || $context['user']['is_owner'] && !$cur_profile['warning'] || !allowedTo('issue_warning')) {
            fatal_lang_error('no_access', false);
        }
        // Get the base (errors related) stuff done.
        loadLanguage('Errors');
        $context['custom_error_title'] = $txt['profile_warning_errors_occurred'];
        // Make sure things which are disabled stay disabled.
        $modSettings['warning_watch'] = !empty($modSettings['warning_watch']) ? $modSettings['warning_watch'] : 110;
        $modSettings['warning_moderate'] = !empty($modSettings['warning_moderate']) && !empty($modSettings['postmod_active']) ? $modSettings['warning_moderate'] : 110;
        $modSettings['warning_mute'] = !empty($modSettings['warning_mute']) ? $modSettings['warning_mute'] : 110;
        $context['warning_limit'] = allowedTo('admin_forum') ? 0 : $modSettings['user_limit'];
        $context['member']['warning'] = $cur_profile['warning'];
        $context['member']['name'] = $cur_profile['real_name'];
        // What are the limits we can apply?
        $context['min_allowed'] = 0;
        $context['max_allowed'] = 100;
        if ($context['warning_limit'] > 0) {
            require_once SUBSDIR . '/Moderation.subs.php';
            $current_applied = warningDailyLimit($memID);
            $context['min_allowed'] = max(0, $cur_profile['warning'] - $current_applied - $context['warning_limit']);
            $context['max_allowed'] = min(100, $cur_profile['warning'] - $current_applied + $context['warning_limit']);
        }
        // Defaults.
        $context['warning_data'] = array('reason' => '', 'notify' => '', 'notify_subject' => '', 'notify_body' => '');
        // Are we saving?
        if (isset($_POST['save'])) {
            // Security is good here.
            checkSession('post');
            // This cannot be empty!
            $_POST['warn_reason'] = isset($_POST['warn_reason']) ? trim($_POST['warn_reason']) : '';
            if ($_POST['warn_reason'] == '' && !$context['user']['is_owner']) {
                $issueErrors[] = 'warning_no_reason';
            }
            $_POST['warn_reason'] = Util::htmlspecialchars($_POST['warn_reason']);
            // If the value hasn't changed it's either no JS or a real no change (Which this will pass)
            if ($_POST['warning_level'] == 'SAME') {
                $_POST['warning_level'] = $_POST['warning_level_nojs'];
            }
            $_POST['warning_level'] = (int) $_POST['warning_level'];
            $_POST['warning_level'] = max(0, min(100, $_POST['warning_level']));
            if ($_POST['warning_level'] < $context['min_allowed']) {
                $_POST['warning_level'] = $context['min_allowed'];
            } elseif ($_POST['warning_level'] > $context['max_allowed']) {
                $_POST['warning_level'] = $context['max_allowed'];
            }
            require_once SUBSDIR . '/Moderation.subs.php';
            // Do we actually have to issue them with a PM?
            $id_notice = 0;
            if (!empty($_POST['warn_notify']) && empty($issueErrors)) {
                $_POST['warn_sub'] = trim($_POST['warn_sub']);
                $_POST['warn_body'] = trim($_POST['warn_body']);
                if (empty($_POST['warn_sub']) || empty($_POST['warn_body'])) {
                    $issueErrors[] = 'warning_notify_blank';
                } else {
                    require_once SUBSDIR . '/PersonalMessage.subs.php';
                    $from = array('id' => 0, 'name' => $context['forum_name'], 'username' => $context['forum_name']);
                    sendpm(array('to' => array($memID), 'bcc' => array()), $_POST['warn_sub'], $_POST['warn_body'], false, $from);
                    // Log the notice.
                    $id_notice = logWarningNotice($_POST['warn_sub'], $_POST['warn_body']);
                }
            }
            // Just in case - make sure notice is valid!
            $id_notice = (int) $id_notice;
            // What have we changed?
            $level_change = $_POST['warning_level'] - $cur_profile['warning'];
            // No errors? Proceed! Only log if you're not the owner.
            if (empty($issueErrors)) {
                // Log what we've done!
                if (!$context['user']['is_owner']) {
                    logWarning($memID, $cur_profile['real_name'], $id_notice, $level_change, $_POST['warn_reason']);
                }
                // Make the change.
                updateMemberData($memID, array('warning' => $_POST['warning_level']));
                // Leave a lovely message.
                $context['profile_updated'] = $context['user']['is_owner'] ? $txt['profile_updated_own'] : $txt['profile_warning_success'];
            } else {
                // Try to remember some bits.
                $context['warning_data'] = array('reason' => $_POST['warn_reason'], 'notify' => !empty($_POST['warn_notify']), 'notify_subject' => isset($_POST['warn_sub']) ? $_POST['warn_sub'] : '', 'notify_body' => isset($_POST['warn_body']) ? $_POST['warn_body'] : '');
            }
            // Show the new improved warning level.
            $context['member']['warning'] = $_POST['warning_level'];
        }
        // Taking a look first, good idea that one.
        if (isset($_POST['preview'])) {
            $warning_body = !empty($_POST['warn_body']) ? trim(censorText($_POST['warn_body'])) : '';
            $context['preview_subject'] = !empty($_POST['warn_sub']) ? trim(Util::htmlspecialchars($_POST['warn_sub'])) : '';
            if (empty($_POST['warn_sub']) || empty($_POST['warn_body'])) {
                $issueErrors[] = 'warning_notify_blank';
            }
            if (!empty($_POST['warn_body'])) {
                require_once SUBSDIR . '/Post.subs.php';
                preparsecode($warning_body);
                $warning_body = parse_bbc($warning_body, true);
            }
            // Try to remember some bits.
            $context['warning_data'] = array('reason' => $_POST['warn_reason'], 'notify' => !empty($_POST['warn_notify']), 'notify_subject' => isset($_POST['warn_sub']) ? $_POST['warn_sub'] : '', 'notify_body' => isset($_POST['warn_body']) ? $_POST['warn_body'] : '', 'body_preview' => $warning_body);
        }
        if (!empty($issueErrors)) {
            // Fill in the suite of errors.
            $context['post_errors'] = array();
            foreach ($issueErrors as $error) {
                $context['post_errors'][] = $txt[$error];
            }
        }
        $context['page_title'] = $txt['profile_issue_warning'];
        // Let's use a generic list to get all the current warnings
        require_once SUBSDIR . '/GenericList.class.php';
        require_once SUBSDIR . '/Profile.subs.php';
        // Work our the various levels.
        $context['level_effects'] = array(0 => $txt['profile_warning_effect_none'], $modSettings['warning_watch'] => $txt['profile_warning_effect_watch'], $modSettings['warning_moderate'] => $txt['profile_warning_effect_moderation'], $modSettings['warning_mute'] => $txt['profile_warning_effect_mute']);
        $context['current_level'] = 0;
        foreach ($context['level_effects'] as $limit => $dummy) {
            if ($context['member']['warning'] >= $limit) {
                $context['current_level'] = $limit;
            }
        }
        // Build a list to view the warnings
        $listOptions = array('id' => 'issued_warnings', 'title' => $txt['profile_viewwarning_previous_warnings'], 'items_per_page' => $modSettings['defaultMaxMessages'], 'no_items_label' => $txt['profile_viewwarning_no_warnings'], 'base_href' => $scripturl . '?action=profile;area=issuewarning;sa=user;u=' . $memID, 'default_sort_col' => 'log_time', 'get_items' => array('function' => 'list_getUserWarnings', 'params' => array($memID)), 'get_count' => array('function' => 'list_getUserWarningCount', 'params' => array($memID)), 'columns' => array('issued_by' => array('header' => array('value' => $txt['profile_warning_previous_issued'], 'style' => 'width: 20%;'), 'data' => array('function' => create_function('$warning', '
							return $warning[\'issuer\'][\'link\'];
						')), 'sort' => array('default' => 'lc.member_name DESC', 'reverse' => 'lc.member_name')), 'log_time' => array('header' => array('value' => $txt['profile_warning_previous_time'], 'style' => 'width: 30%;'), 'data' => array('db' => 'time'), 'sort' => array('default' => 'lc.log_time DESC', 'reverse' => 'lc.log_time')), 'reason' => array('header' => array('value' => $txt['profile_warning_previous_reason']), 'data' => array('function' => create_function('$warning', '
							global $scripturl, $txt, $settings;

							$ret = \'
							<div class="floatleft">
								\' . $warning[\'reason\'] . \'
							</div>\';

							// If a notice was sent, provide a way to view it
							if (!empty($warning[\'id_notice\']))
								$ret .= \'
							<div class="floatright">
								<a href="\' . $scripturl . \'?action=moderate;area=notice;nid=\' . $warning[\'id_notice\'] . \'" onclick="window.open(this.href, \\\'\\\', \\\'scrollbars=yes,resizable=yes,width=400,height=250\\\');return false;" target="_blank" class="new_win" title="\' . $txt[\'profile_warning_previous_notice\'] . \'"><img src="\' . $settings[\'images_url\'] . \'/filter.png" alt="" /></a>
							</div>\';

							return $ret;'))), 'level' => array('header' => array('value' => $txt['profile_warning_previous_level'], 'style' => 'width: 6%;'), 'data' => array('db' => 'counter'), 'sort' => array('default' => 'lc.counter DESC', 'reverse' => 'lc.counter'))));
        // Create the list for viewing.
        createList($listOptions);
        $warning_for_message = isset($_REQUEST['msg']) ? (int) $_REQUEST['msg'] : false;
        $warned_message_subject = '';
        // Are they warning because of a message?
        if (isset($_REQUEST['msg']) && 0 < (int) $_REQUEST['msg']) {
            require_once SUBSDIR . '/Messages.subs.php';
            $message = basicMessageInfo((int) $_REQUEST['msg']);
            if (!empty($message)) {
                $warned_message_subject = $message['subject'];
            }
        }
        require_once SUBSDIR . '/Maillist.subs.php';
        // Any custom templates?
        $context['notification_templates'] = array();
        $notification_templates = maillist_templates('warntpl');
        foreach ($notification_templates as $row) {
            // If we're not warning for a message skip any that are.
            if (!$warning_for_message && strpos($row['body'], '{MESSAGE}') !== false) {
                continue;
            }
            $context['notification_templates'][] = array('title' => $row['title'], 'body' => $row['body']);
        }
        // Setup the "default" templates.
        foreach (array('spamming', 'offence', 'insulting') as $type) {
            $context['notification_templates'][] = array('title' => $txt['profile_warning_notify_title_' . $type], 'body' => sprintf($txt['profile_warning_notify_template_outline' . (!empty($warning_for_message) ? '_post' : '')], $txt['profile_warning_notify_for_' . $type]));
        }
        // Replace all the common variables in the templates.
        foreach ($context['notification_templates'] as $k => $name) {
            $context['notification_templates'][$k]['body'] = strtr($name['body'], array('{MEMBER}' => un_htmlspecialchars($context['member']['name']), '{MESSAGE}' => '[url=' . $scripturl . '?msg=' . $warning_for_message . ']' . un_htmlspecialchars($warned_message_subject) . '[/url]', '{SCRIPTURL}' => $scripturl, '{FORUMNAME}' => $mbname, '{REGARDS}' => replaceBasicActionUrl($txt['regards_team'])));
        }
    }
Example #3
0
/**
 * Modifying a post...
 *
 * @package Posts
 * @param mixed[] $msgOptions
 * @param mixed[] $topicOptions
 * @param mixed[] $posterOptions
 */
function modifyPost(&$msgOptions, &$topicOptions, &$posterOptions)
{
    global $user_info, $modSettings;
    $db = database();
    $topicOptions['poll'] = isset($topicOptions['poll']) ? (int) $topicOptions['poll'] : null;
    $topicOptions['lock_mode'] = isset($topicOptions['lock_mode']) ? $topicOptions['lock_mode'] : null;
    $topicOptions['sticky_mode'] = isset($topicOptions['sticky_mode']) ? $topicOptions['sticky_mode'] : null;
    // This is longer than it has to be, but makes it so we only set/change what we have to.
    $messages_columns = array();
    if (isset($posterOptions['name'])) {
        $messages_columns['poster_name'] = $posterOptions['name'];
    }
    if (isset($posterOptions['email'])) {
        $messages_columns['poster_email'] = $posterOptions['email'];
    }
    if (isset($msgOptions['icon'])) {
        $messages_columns['icon'] = $msgOptions['icon'];
    }
    if (isset($msgOptions['subject'])) {
        $messages_columns['subject'] = $msgOptions['subject'];
    }
    if (isset($msgOptions['body'])) {
        $messages_columns['body'] = $msgOptions['body'];
        // using a custom search index, then lets get the old message so we can update our index as needed
        if (!empty($modSettings['search_custom_index_config'])) {
            require_once SUBSDIR . '/Messages.subs.php';
            $message = basicMessageInfo($msgOptions['id'], true);
            $msgOptions['old_body'] = $message['body'];
        }
    }
    if (!empty($msgOptions['modify_time'])) {
        $messages_columns['modified_time'] = $msgOptions['modify_time'];
        $messages_columns['modified_name'] = $msgOptions['modify_name'];
        $messages_columns['id_msg_modified'] = $modSettings['maxMsgID'];
    }
    if (isset($msgOptions['smileys_enabled'])) {
        $messages_columns['smileys_enabled'] = empty($msgOptions['smileys_enabled']) ? 0 : 1;
    }
    // Which columns need to be ints?
    $messageInts = array('modified_time', 'id_msg_modified', 'smileys_enabled');
    $update_parameters = array('id_msg' => $msgOptions['id']);
    call_integration_hook('integrate_before_modify_post', array(&$messages_columns, &$update_parameters, &$msgOptions, &$topicOptions, &$posterOptions, &$messageInts));
    foreach ($messages_columns as $var => $val) {
        $messages_columns[$var] = $var . ' = {' . (in_array($var, $messageInts) ? 'int' : 'string') . ':var_' . $var . '}';
        $update_parameters['var_' . $var] = $val;
    }
    // Nothing to do?
    if (empty($messages_columns)) {
        return true;
    }
    // Change the post.
    $db->query('', '
		UPDATE {db_prefix}messages
		SET ' . implode(', ', $messages_columns) . '
		WHERE id_msg = {int:id_msg}', $update_parameters);
    // Lock and or sticky the post.
    if ($topicOptions['sticky_mode'] !== null || $topicOptions['lock_mode'] !== null || $topicOptions['poll'] !== null) {
        $db->query('', '
			UPDATE {db_prefix}topics
			SET
				is_sticky = {raw:is_sticky},
				locked = {raw:locked},
				id_poll = {raw:id_poll}
			WHERE id_topic = {int:id_topic}', array('is_sticky' => $topicOptions['sticky_mode'] === null ? 'is_sticky' : (int) $topicOptions['sticky_mode'], 'locked' => $topicOptions['lock_mode'] === null ? 'locked' : (int) $topicOptions['lock_mode'], 'id_poll' => $topicOptions['poll'] === null ? 'id_poll' : (int) $topicOptions['poll'], 'id_topic' => $topicOptions['id']));
    }
    // Mark the edited post as read.
    if (!empty($topicOptions['mark_as_read']) && !$user_info['is_guest']) {
        // Since it's likely they *read* it before editing, let's try an UPDATE first.
        $db->query('', '
			UPDATE {db_prefix}log_topics
			SET id_msg = {int:id_msg}
			WHERE id_member = {int:current_member}
				AND id_topic = {int:id_topic}', array('current_member' => $user_info['id'], 'id_msg' => $modSettings['maxMsgID'], 'id_topic' => $topicOptions['id']));
        $flag = $db->affected_rows() != 0;
        if (empty($flag)) {
            require_once SUBSDIR . '/Topic.subs.php';
            markTopicsRead(array($user_info['id'], $topicOptions['id'], $modSettings['maxMsgID'], 0), false);
        }
    }
    // If there's a custom search index, it needs to be modified...
    require_once SUBSDIR . '/Search.subs.php';
    $searchAPI = findSearchAPI();
    if (is_callable(array($searchAPI, 'postModified'))) {
        $searchAPI->postModified($msgOptions, $topicOptions, $posterOptions);
    }
    if (isset($msgOptions['subject'])) {
        // Only update the subject if this was the first message in the topic.
        $request = $db->query('', '
			SELECT id_topic
			FROM {db_prefix}topics
			WHERE id_first_msg = {int:id_first_msg}
			LIMIT 1', array('id_first_msg' => $msgOptions['id']));
        if ($db->num_rows($request) == 1) {
            updateStats('subject', $topicOptions['id'], $msgOptions['subject']);
        }
        $db->free_result($request);
    }
    // Finally, if we are setting the approved state we need to do much more work :(
    if ($modSettings['postmod_active'] && isset($msgOptions['approved'])) {
        approvePosts($msgOptions['id'], $msgOptions['approved']);
    }
    return true;
}
 /**
  * Screen shown before the actual split.
  * is accessed with ?action=splittopics;sa=index.
  * default sub action for ?action=splittopics.
  * uses 'ask' sub template of the SplitTopics template.
  * redirects to action_splitSelectTopics if the message given turns out to be
  * the first message of a topic.
  * shows the user three ways to split the current topic.
  */
 public function action_splitIndex()
 {
     global $txt, $context, $modSettings;
     // Validate "at".
     if (empty($_GET['at'])) {
         fatal_lang_error('numbers_one_to_nine', false);
     }
     // Split at a specific topic
     $splitAt = (int) $_GET['at'];
     // We deal with topics here.
     require_once SUBSDIR . '/Boards.subs.php';
     require_once SUBSDIR . '/Messages.subs.php';
     // Let's load up the boards in case they are useful.
     $context += getBoardList(array('not_redirection' => true));
     // Retrieve message info for the message at the split point.
     $messageInfo = basicMessageInfo($splitAt, false, true);
     if ($messageInfo === false) {
         fatal_lang_error('cant_find_messages');
     }
     // If not approved validate they can approve it.
     if ($modSettings['postmod_active'] && !$messageInfo['topic_approved']) {
         isAllowedTo('approve_posts');
     }
     // If this topic has unapproved posts, we need to count them too...
     if ($modSettings['postmod_active'] && allowedTo('approve_posts')) {
         $messageInfo['num_replies'] += $messageInfo['unapproved_posts'] - ($messageInfo['topic_approved'] ? 0 : 1);
     }
     $context['can_move'] = allowedTo('move_any') || allowedTo('move_own');
     // Check if there is more than one message in the topic.  (there should be.)
     if ($messageInfo['num_replies'] < 1) {
         fatal_lang_error('topic_one_post', false);
     }
     // Check if this is the first message in the topic (if so, the first and second option won't be available)
     if ($messageInfo['id_first_msg'] == $splitAt) {
         $this->_new_topic_subject = $messageInfo['subject'];
         $this->_set_session_values();
         return $this->action_splitSelectTopics();
     }
     // Basic template information....
     $context['message'] = array('id' => $splitAt, 'subject' => $messageInfo['subject']);
     $context['sub_template'] = 'ask';
     $context['page_title'] = $txt['split_topic'];
 }
Example #5
0
 /**
  * In-topic quick moderation.
  * Accessed by ?action=quickmod2
  */
 public function action_quickmod2()
 {
     global $topic, $board, $user_info, $context;
     // Check the session = get or post.
     checkSession('request');
     require_once SUBSDIR . '/Messages.subs.php';
     if (empty($_REQUEST['msgs'])) {
         redirectexit('topic=' . $topic . '.' . $_REQUEST['start']);
     }
     $messages = array();
     foreach ($_REQUEST['msgs'] as $dummy) {
         $messages[] = (int) $dummy;
     }
     // We are restoring messages. We handle this in another place.
     if (isset($_REQUEST['restore_selected'])) {
         redirectexit('action=restoretopic;msgs=' . implode(',', $messages) . ';' . $context['session_var'] . '=' . $context['session_id']);
     }
     if (isset($_REQUEST['split_selection'])) {
         $mgsOptions = basicMessageInfo(min($messages), true);
         $_SESSION['split_selection'][$topic] = $messages;
         redirectexit('action=splittopics;sa=selectTopics;topic=' . $topic . '.0;subname_enc=' . urlencode($mgsOptions['subject']) . ';' . $context['session_var'] . '=' . $context['session_id']);
     }
     require_once SUBSDIR . '/Topic.subs.php';
     $topic_info = getTopicInfo($topic);
     // Allowed to delete any message?
     if (allowedTo('delete_any')) {
         $allowed_all = true;
     } elseif (allowedTo('delete_replies')) {
         $allowed_all = $topic_info['id_member_started'] == $user_info['id'];
     } else {
         $allowed_all = false;
     }
     // Make sure they're allowed to delete their own messages, if not any.
     if (!$allowed_all) {
         isAllowedTo('delete_own');
     }
     // Allowed to remove which messages?
     $messages = determineRemovableMessages($topic, $messages, $allowed_all);
     // Get the first message in the topic - because you can't delete that!
     $first_message = $topic_info['id_first_msg'];
     $last_message = $topic_info['id_last_msg'];
     // Delete all the messages we know they can delete. ($messages)
     foreach ($messages as $message => $info) {
         // Just skip the first message - if it's not the last.
         if ($message == $first_message && $message != $last_message) {
             continue;
         } elseif ($message == $first_message) {
             $topicGone = true;
         }
         removeMessage($message);
         // Log this moderation action ;).
         if (allowedTo('delete_any') && (!allowedTo('delete_own') || $info[1] != $user_info['id'])) {
             logAction('delete', array('topic' => $topic, 'subject' => $info[0], 'member' => $info[1], 'board' => $board));
         }
     }
     redirectexit(!empty($topicGone) ? 'board=' . $board : 'topic=' . $topic . '.' . $_REQUEST['start']);
 }
Example #6
0
/**
 * Load all the important user information.
 *
 * What it does:
 * - sets up the $user_info array
 * - assigns $user_info['query_wanna_see_board'] for what boards the user can see.
 * - first checks for cookie or integration validation.
 * - uses the current session if no integration function or cookie is found.
 * - checks password length, if member is activated and the login span isn't over.
 * - if validation fails for the user, $id_member is set to 0.
 * - updates the last visit time when needed.
 */
function loadUserSettings()
{
    global $context, $modSettings, $user_settings, $cookiename, $user_info, $language;
    $db = database();
    // Check first the integration, then the cookie, and last the session.
    if (count($integration_ids = call_integration_hook('integrate_verify_user')) > 0) {
        $id_member = 0;
        foreach ($integration_ids as $integration_id) {
            $integration_id = (int) $integration_id;
            if ($integration_id > 0) {
                $id_member = $integration_id;
                $already_verified = true;
                break;
            }
        }
    } else {
        $id_member = 0;
    }
    // We'll need IPs and user agent and stuff, they came to visit us with!
    $req = request();
    if (empty($id_member) && isset($_COOKIE[$cookiename])) {
        // Fix a security hole in PHP 4.3.9 and below...
        if (preg_match('~^a:[34]:\\{i:0;i:\\d{1,8};i:1;s:(0|64):"([a-fA-F0-9]{64})?";i:2;[id]:\\d{1,14};(i:3;i:\\d;)?\\}$~i', $_COOKIE[$cookiename]) == 1) {
            list($id_member, $password) = @unserialize($_COOKIE[$cookiename]);
            $id_member = !empty($id_member) && strlen($password) > 0 ? (int) $id_member : 0;
        } else {
            $id_member = 0;
        }
    } elseif (empty($id_member) && isset($_SESSION['login_' . $cookiename]) && ($_SESSION['USER_AGENT'] == $req->user_agent() || !empty($modSettings['disableCheckUA']))) {
        // @todo Perhaps we can do some more checking on this, such as on the first octet of the IP?
        list($id_member, $password, $login_span) = @unserialize($_SESSION['login_' . $cookiename]);
        $id_member = !empty($id_member) && strlen($password) == 64 && $login_span > time() ? (int) $id_member : 0;
    }
    // Only load this stuff if the user isn't a guest.
    if ($id_member != 0) {
        // Is the member data cached?
        if (empty($modSettings['cache_enable']) || $modSettings['cache_enable'] < 2 || ($user_settings = cache_get_data('user_settings-' . $id_member, 60)) == null) {
            $request = $db->query('', '
				SELECT mem.*, IFNULL(a.id_attach, 0) AS id_attach, a.filename, a.attachment_type
				FROM {db_prefix}members AS mem
					LEFT JOIN {db_prefix}attachments AS a ON (a.id_member = {int:id_member})
				WHERE mem.id_member = {int:id_member}
				LIMIT 1', array('id_member' => $id_member));
            $user_settings = $db->fetch_assoc($request);
            $db->free_result($request);
            // Make the ID specifically an integer
            $user_settings['id_member'] = (int) $user_settings['id_member'];
            if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2) {
                cache_put_data('user_settings-' . $id_member, $user_settings, 60);
            }
        }
        // Did we find 'im?  If not, junk it.
        if (!empty($user_settings)) {
            // As much as the password should be right, we can assume the integration set things up.
            if (!empty($already_verified) && $already_verified === true) {
                $check = true;
            } elseif (strlen($password) == 64) {
                $check = hash('sha256', $user_settings['passwd'] . $user_settings['password_salt']) == $password;
            } else {
                $check = false;
            }
            // Wrong password or not activated - either way, you're going nowhere.
            $id_member = $check && ($user_settings['is_activated'] == 1 || $user_settings['is_activated'] == 11) ? (int) $user_settings['id_member'] : 0;
        } else {
            $id_member = 0;
        }
        // If we no longer have the member maybe they're being all hackey, stop brute force!
        if (!$id_member) {
            validatePasswordFlood(!empty($user_settings['id_member']) ? $user_settings['id_member'] : $id_member, !empty($user_settings['passwd_flood']) ? $user_settings['passwd_flood'] : false, $id_member != 0);
        }
    }
    // Found 'im, let's set up the variables.
    if ($id_member != 0) {
        // Let's not update the last visit time in these cases...
        // 1. SSI doesn't count as visiting the forum.
        // 2. RSS feeds and XMLHTTP requests don't count either.
        // 3. If it was set within this session, no need to set it again.
        // 4. New session, yet updated < five hours ago? Maybe cache can help.
        if (ELK != 'SSI' && !isset($_REQUEST['xml']) && (!isset($_REQUEST['action']) || $_REQUEST['action'] != '.xml') && empty($_SESSION['id_msg_last_visit']) && (empty($modSettings['cache_enable']) || ($_SESSION['id_msg_last_visit'] = cache_get_data('user_last_visit-' . $id_member, 5 * 3600)) === null)) {
            // @todo can this be cached?
            // Do a quick query to make sure this isn't a mistake.
            require_once SUBSDIR . '/Messages.subs.php';
            $visitOpt = basicMessageInfo($user_settings['id_msg_last_visit'], true);
            $_SESSION['id_msg_last_visit'] = $user_settings['id_msg_last_visit'];
            // If it was *at least* five hours ago...
            if ($visitOpt['poster_time'] < time() - 5 * 3600) {
                updateMemberData($id_member, array('id_msg_last_visit' => (int) $modSettings['maxMsgID'], 'last_login' => time(), 'member_ip' => $req->client_ip(), 'member_ip2' => $req->ban_ip()));
                $user_settings['last_login'] = time();
                if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2) {
                    cache_put_data('user_settings-' . $id_member, $user_settings, 60);
                }
                if (!empty($modSettings['cache_enable'])) {
                    cache_put_data('user_last_visit-' . $id_member, $_SESSION['id_msg_last_visit'], 5 * 3600);
                }
            }
        } elseif (empty($_SESSION['id_msg_last_visit'])) {
            $_SESSION['id_msg_last_visit'] = $user_settings['id_msg_last_visit'];
        }
        $username = $user_settings['member_name'];
        if (empty($user_settings['additional_groups'])) {
            $user_info = array('groups' => array($user_settings['id_group'], $user_settings['id_post_group']));
        } else {
            $user_info = array('groups' => array_merge(array($user_settings['id_group'], $user_settings['id_post_group']), explode(',', $user_settings['additional_groups'])));
        }
        // Because history has proven that it is possible for groups to go bad - clean up in case.
        foreach ($user_info['groups'] as $k => $v) {
            $user_info['groups'][$k] = (int) $v;
        }
        // This is a logged in user, so definitely not a spider.
        $user_info['possibly_robot'] = false;
    } else {
        // This is what a guest's variables should be.
        $username = '';
        $user_info = array('groups' => array(-1));
        $user_settings = array();
        if (isset($_COOKIE[$cookiename])) {
            $_COOKIE[$cookiename] = '';
        }
        // Create a login token if it doesn't exist yet.
        if (!isset($_SESSION['token']['post-login'])) {
            createToken('login');
        } else {
            list($context['login_token_var'], , , $context['login_token']) = $_SESSION['token']['post-login'];
        }
        // Do we perhaps think this is a search robot? Check every five minutes just in case...
        if ((!empty($modSettings['spider_mode']) || !empty($modSettings['spider_group'])) && (!isset($_SESSION['robot_check']) || $_SESSION['robot_check'] < time() - 300)) {
            require_once SUBSDIR . '/SearchEngines.subs.php';
            $user_info['possibly_robot'] = spiderCheck();
        } elseif (!empty($modSettings['spider_mode'])) {
            $user_info['possibly_robot'] = isset($_SESSION['id_robot']) ? $_SESSION['id_robot'] : 0;
        } else {
            $ci_user_agent = strtolower($req->user_agent());
            $user_info['possibly_robot'] = strpos($ci_user_agent, 'mozilla') === false && strpos($ci_user_agent, 'opera') === false || preg_match('~(googlebot|slurp|crawl|msnbot|yandex|bingbot|baidu)~u', $ci_user_agent) == 1;
        }
    }
    // Set up the $user_info array.
    $user_info += array('id' => $id_member, 'username' => $username, 'name' => isset($user_settings['real_name']) ? $user_settings['real_name'] : '', 'email' => isset($user_settings['email_address']) ? $user_settings['email_address'] : '', 'passwd' => isset($user_settings['passwd']) ? $user_settings['passwd'] : '', 'language' => empty($user_settings['lngfile']) || empty($modSettings['userLanguage']) ? $language : $user_settings['lngfile'], 'is_guest' => $id_member == 0, 'is_admin' => in_array(1, $user_info['groups']), 'theme' => empty($user_settings['id_theme']) ? 0 : $user_settings['id_theme'], 'last_login' => empty($user_settings['last_login']) ? 0 : $user_settings['last_login'], 'ip' => $req->client_ip(), 'ip2' => $req->ban_ip(), 'posts' => empty($user_settings['posts']) ? 0 : $user_settings['posts'], 'time_format' => empty($user_settings['time_format']) ? $modSettings['time_format'] : $user_settings['time_format'], 'time_offset' => empty($user_settings['time_offset']) ? 0 : $user_settings['time_offset'], 'avatar' => array_merge(array('url' => isset($user_settings['avatar']) ? $user_settings['avatar'] : '', 'filename' => empty($user_settings['filename']) ? '' : $user_settings['filename'], 'custom_dir' => !empty($user_settings['attachment_type']) && $user_settings['attachment_type'] == 1, 'id_attach' => isset($user_settings['id_attach']) ? $user_settings['id_attach'] : 0), determineAvatar($user_settings)), 'smiley_set' => isset($user_settings['smiley_set']) ? $user_settings['smiley_set'] : '', 'messages' => empty($user_settings['personal_messages']) ? 0 : $user_settings['personal_messages'], 'mentions' => empty($user_settings['mentions']) ? 0 : max(0, $user_settings['mentions']), 'unread_messages' => empty($user_settings['unread_messages']) ? 0 : $user_settings['unread_messages'], 'total_time_logged_in' => empty($user_settings['total_time_logged_in']) ? 0 : $user_settings['total_time_logged_in'], 'buddies' => !empty($modSettings['enable_buddylist']) && !empty($user_settings['buddy_list']) ? explode(',', $user_settings['buddy_list']) : array(), 'ignoreboards' => !empty($user_settings['ignore_boards']) && !empty($modSettings['allow_ignore_boards']) ? explode(',', $user_settings['ignore_boards']) : array(), 'ignoreusers' => !empty($user_settings['pm_ignore_list']) ? explode(',', $user_settings['pm_ignore_list']) : array(), 'warning' => isset($user_settings['warning']) ? $user_settings['warning'] : 0, 'permissions' => array());
    $user_info['groups'] = array_unique($user_info['groups']);
    // Make sure that the last item in the ignore boards array is valid.  If the list was too long it could have an ending comma that could cause problems.
    if (!empty($user_info['ignoreboards']) && empty($user_info['ignoreboards'][$tmp = count($user_info['ignoreboards']) - 1])) {
        unset($user_info['ignoreboards'][$tmp]);
    }
    // Do we have any languages to validate this?
    if (!empty($modSettings['userLanguage']) && (!empty($_GET['language']) || !empty($_SESSION['language']))) {
        $languages = getLanguages();
    }
    // Allow the user to change their language if its valid.
    if (!empty($modSettings['userLanguage']) && !empty($_GET['language']) && isset($languages[strtr($_GET['language'], './\\:', '____')])) {
        $user_info['language'] = strtr($_GET['language'], './\\:', '____');
        $_SESSION['language'] = $user_info['language'];
    } elseif (!empty($modSettings['userLanguage']) && !empty($_SESSION['language']) && isset($languages[strtr($_SESSION['language'], './\\:', '____')])) {
        $user_info['language'] = strtr($_SESSION['language'], './\\:', '____');
    }
    // Just build this here, it makes it easier to change/use - administrators can see all boards.
    if ($user_info['is_admin']) {
        $user_info['query_see_board'] = '1=1';
    } else {
        $user_info['query_see_board'] = '((FIND_IN_SET(' . implode(', b.member_groups) != 0 OR FIND_IN_SET(', $user_info['groups']) . ', b.member_groups) != 0)' . (!empty($modSettings['deny_boards_access']) ? ' AND (FIND_IN_SET(' . implode(', b.deny_member_groups) = 0 AND FIND_IN_SET(', $user_info['groups']) . ', b.deny_member_groups) = 0)' : '') . (isset($user_info['mod_cache']) ? ' OR ' . $user_info['mod_cache']['mq'] : '') . ')';
    }
    // Build the list of boards they WANT to see.
    // This will take the place of query_see_boards in certain spots, so it better include the boards they can see also
    // If they aren't ignoring any boards then they want to see all the boards they can see
    if (empty($user_info['ignoreboards'])) {
        $user_info['query_wanna_see_board'] = $user_info['query_see_board'];
    } else {
        $user_info['query_wanna_see_board'] = '(' . $user_info['query_see_board'] . ' AND b.id_board NOT IN (' . implode(',', $user_info['ignoreboards']) . '))';
    }
    call_integration_hook('integrate_user_info');
}
Example #7
0
    /**
     * Report a post to the moderator... ask for a comment.
     *
     * what is does:
     * - Gathers data from the user to report abuse to the moderator(s).
     * - Uses the ReportToModerator template, main sub template.
     * - Requires the report_any permission.
     * - Uses action_reporttm2() if post data was sent.
     * - Accessed through ?action=reporttm.
     */
    public function action_reporttm()
    {
        global $txt, $modSettings, $user_info, $context;
        $context['robot_no_index'] = true;
        // You can't use this if it's off or you are not allowed to do it.
        isAllowedTo('report_any');
        // No errors, yet.
        $report_errors = Error_Context::context('report', 1);
        // ...or maybe some.
        $context['report_error'] = array('errors' => $report_errors->prepareErrors(), 'type' => $report_errors->getErrorType() == 0 ? 'minor' : 'serious');
        // If they're posting, it should be processed by action_reporttm2.
        if ((isset($_POST[$context['session_var']]) || isset($_POST['save'])) && !$report_errors->hasErrors()) {
            $this->action_reporttm2();
        }
        // We need a message ID to check!
        if (empty($_REQUEST['msg'])) {
            fatal_lang_error('no_access', false);
        }
        // Check the message's ID - don't want anyone reporting a post that does not exist
        require_once SUBSDIR . '/Messages.subs.php';
        $message_id = (int) $_REQUEST['msg'];
        $message_info = basicMessageInfo($message_id, true, true);
        if ($message_info === false) {
            fatal_lang_error('no_board', false);
        }
        // Do we need to show the visual verification image?
        $context['require_verification'] = $user_info['is_guest'] && !empty($modSettings['guests_report_require_captcha']);
        if ($context['require_verification']) {
            require_once SUBSDIR . '/VerificationControls.class.php';
            $verificationOptions = array('id' => 'report');
            $context['require_verification'] = create_control_verification($verificationOptions);
            $context['visual_verification_id'] = $verificationOptions['id'];
        }
        // Show the inputs for the comment, etc.
        loadLanguage('Post');
        loadLanguage('Errors');
        loadTemplate('Emailuser');
        addInlineJavascript('
		error_txts[\'post_too_long\'] = ' . JavaScriptEscape($txt['error_post_too_long']) . ';

		var report_errors = new errorbox_handler({
			self: \'report_errors\',
			error_box_id: \'report_error\',
			error_checks: [{
				code: \'post_too_long\',
				efunction: function(box_value) {
					if (box_value.length > 254)
						return true;
					else
						return false;
				}
			}],
			check_id: "report_comment"
		});', true);
        $context['comment_body'] = !isset($_POST['comment']) ? '' : trim($_POST['comment']);
        $context['email_address'] = !isset($_POST['email']) ? '' : trim($_POST['email']);
        // This is here so that the user could, in theory, be redirected back to the topic.
        $context['start'] = $_REQUEST['start'];
        $context['message_id'] = $message_id;
        $context['page_title'] = $txt['report_to_mod'];
        $context['sub_template'] = 'report';
    }
Example #8
0
 /**
  * Unlikes a post that you previously liked ... no negatives though, hurts feelings :'(
  * It redirects back to the referrer afterward.
  * It is accessed via ?action=like,sa=unlikepost.
  */
 public function action_unlikepost()
 {
     global $user_info, $topic, $txt, $modSettings;
     $this->_id_liked = !empty($_REQUEST['msg']) ? (int) $_REQUEST['msg'] : 0;
     // We used to like these
     require_once SUBSDIR . '/Likes.subs.php';
     require_once SUBSDIR . '/Messages.subs.php';
     // Have to be able to access it to unlike it now
     if ($this->prepare_like() && canAccessMessage($this->_id_liked)) {
         $liked_message = basicMessageInfo($this->_id_liked, true, true);
         if ($liked_message) {
             $likeResult = likePost($user_info['id'], $liked_message, '-');
             if ($likeResult === true) {
                 // Oh noes, taking the like back, let them know so they can complain
                 if (!empty($modSettings['mentions_enabled'])) {
                     require_once CONTROLLERDIR . '/Mentions.controller.php';
                     $mentions = new Mentions_Controller();
                     $mentions->setData(array('id_member' => $liked_message['id_member'], 'type' => 'rlike', 'id_msg' => $this->_id_liked));
                     // Notifying that likes were removed ?
                     if (!empty($modSettings['mentions_dont_notify_rlike'])) {
                         $mentions->action_rlike();
                     } else {
                         $mentions->action_add();
                     }
                 }
             } elseif ($this->_api) {
                 $this->_likes_response = array('result' => false, 'data' => $likeResult);
             }
         } elseif ($this->_api) {
             loadLanguage('Errors');
             $this->_likes_response = array('result' => false, 'data' => $txt['like_unlike_error']);
         }
     }
     // Back we go
     if ($this->_api) {
         $this->likeResponse();
     } elseif (!isset($_REQUEST['profile'])) {
         redirectexit('topic=' . $topic . '.msg' . $this->_id_liked . '#msg' . $this->_id_liked);
     } else {
         redirectexit('action=profile;area=showlikes;sa=given;u=' . $user_info['id']);
     }
 }
Example #9
0
/**
 * Small function that simply verifies if the current
 * user can access a specific message
 *
 * @param int $id_msg a message id
 * @param bool $check_approval if true messages are checked for approval (default true)
 * @return boolean
 */
function canAccessMessage($id_msg, $check_approval = true)
{
    global $user_info;
    $message_info = basicMessageInfo($id_msg);
    // Do we even have a message to speak of?
    if (empty($message_info)) {
        return false;
    }
    // Check for approval status?
    if ($check_approval) {
        // The user can access this message if it's approved or they're owner
        return !empty($message_info['approved']) || $message_info['id_member'] == $user_info['id'];
    }
    // Otherwise, nope.
    return false;
}
Example #10
0
/**
 * Get the id_member associated with the specified message ID.
 *
 * @package Boards
 * @param int $messageID message ID
 * @return int the member id
 */
function getMsgMemberID($messageID)
{
    require_once SUBSDIR . '/Messages.subs.php';
    $message_info = basicMessageInfo((int) $messageID, true);
    return empty($message_info['id_member']) ? 0 : (int) $message_info['id_member'];
}
 /**
  * Show all posts by the current user.
  *
  * @todo This function needs to be split up properly.
  */
 public function action_showPosts()
 {
     global $txt, $user_info, $scripturl, $modSettings, $context, $user_profile, $board;
     $memID = currentMemberID();
     // Some initial context.
     $context['start'] = (int) $_REQUEST['start'];
     $context['current_member'] = $memID;
     loadTemplate('ProfileInfo');
     // Create the tabs for the template.
     $context[$context['profile_menu_name']]['tab_data'] = array('title' => $txt['showPosts'], 'description' => $txt['showPosts_help'], 'class' => 'profile', 'tabs' => array('messages' => array(), 'topics' => array(), 'unwatchedtopics' => array(), 'attach' => array()));
     // Set the page title
     $context['page_title'] = $txt['showPosts'] . ' - ' . $user_profile[$memID]['real_name'];
     // Is the load average too high to allow searching just now?
     if (!empty($modSettings['loadavg_show_posts']) && $modSettings['current_load'] >= $modSettings['loadavg_show_posts']) {
         fatal_lang_error('loadavg_show_posts_disabled', false);
     }
     // If we're specifically dealing with attachments use that function!
     if (isset($_GET['sa']) && $_GET['sa'] == 'attach') {
         return $this->action_showAttachments();
     } elseif (isset($_GET['sa']) && $_GET['sa'] == 'unwatchedtopics' && $modSettings['enable_unwatch']) {
         return $this->action_showUnwatched();
     }
     // Are we just viewing topics?
     $context['is_topics'] = isset($_GET['sa']) && $_GET['sa'] == 'topics' ? true : false;
     // If just deleting a message, do it and then redirect back.
     if (isset($_GET['delete']) && !$context['is_topics']) {
         checkSession('get');
         // We need msg info for logging.
         require_once SUBSDIR . '/Messages.subs.php';
         $info = basicMessageInfo((int) $_GET['delete'], true);
         // Trying to remove a message that doesn't exist.
         if (empty($info)) {
             redirectexit('action=profile;u=' . $memID . ';area=showposts;start=' . $_GET['start']);
         }
         // We can be lazy, since removeMessage() will check the permissions for us.
         removeMessage((int) $_GET['delete']);
         // Add it to the mod log.
         if (allowedTo('delete_any') && (!allowedTo('delete_own') || $info['id_member'] != $user_info['id'])) {
             logAction('delete', array('topic' => $info['id_topic'], 'subject' => $info['subject'], 'member' => $info['id_member'], 'board' => $info['id_board']));
         }
         // Back to... where we are now ;).
         redirectexit('action=profile;u=' . $memID . ';area=showposts;start=' . $_GET['start']);
     }
     // Default to 10.
     if (empty($_REQUEST['viewscount']) || !is_numeric($_REQUEST['viewscount'])) {
         $_REQUEST['viewscount'] = '10';
     }
     if ($context['is_topics']) {
         $msgCount = count_user_topics($memID, $board);
     } else {
         $msgCount = count_user_posts($memID, $board);
     }
     list($min_msg_member, $max_msg_member) = findMinMaxUserMessage($memID, $board);
     $range_limit = '';
     $maxIndex = (int) $modSettings['defaultMaxMessages'];
     // Make sure the starting place makes sense and construct our friend the page index.
     $context['page_index'] = constructPageIndex($scripturl . '?action=profile;u=' . $memID . ';area=showposts' . ($context['is_topics'] ? ';sa=topics' : ';sa=messages') . (!empty($board) ? ';board=' . $board : ''), $context['start'], $msgCount, $maxIndex);
     $context['current_page'] = $context['start'] / $maxIndex;
     // Reverse the query if we're past 50% of the pages for better performance.
     $start = $context['start'];
     $reverse = $_REQUEST['start'] > $msgCount / 2;
     if ($reverse) {
         $maxIndex = $msgCount < $context['start'] + $modSettings['defaultMaxMessages'] + 1 && $msgCount > $context['start'] ? $msgCount - $context['start'] : (int) $modSettings['defaultMaxMessages'];
         $start = $msgCount < $context['start'] + $modSettings['defaultMaxMessages'] + 1 || $msgCount < $context['start'] + $modSettings['defaultMaxMessages'] ? 0 : $msgCount - $context['start'] - $modSettings['defaultMaxMessages'];
     }
     // Guess the range of messages to be shown to help minimize what the query needs to do
     if ($msgCount > 1000) {
         $margin = floor(($max_msg_member - $min_msg_member) * (($start + $modSettings['defaultMaxMessages']) / $msgCount) + 0.1 * ($max_msg_member - $min_msg_member));
         // Make a bigger margin for topics only.
         if ($context['is_topics']) {
             $margin *= 5;
             $range_limit = $reverse ? 't.id_first_msg < ' . ($min_msg_member + $margin) : 't.id_first_msg > ' . ($max_msg_member - $margin);
         } else {
             $range_limit = $reverse ? 'm.id_msg < ' . ($min_msg_member + $margin) : 'm.id_msg > ' . ($max_msg_member - $margin);
         }
     }
     // Find this user's posts or topics started
     if ($context['is_topics']) {
         $rows = load_user_topics($memID, $start, $maxIndex, $range_limit, $reverse, $board);
     } else {
         $rows = load_user_posts($memID, $start, $maxIndex, $range_limit, $reverse, $board);
     }
     // Start counting at the number of the first message displayed.
     $counter = $reverse ? $context['start'] + $maxIndex + 1 : $context['start'];
     $context['posts'] = array();
     $board_ids = array('own' => array(), 'any' => array());
     foreach ($rows as $row) {
         // Censor....
         censorText($row['body']);
         censorText($row['subject']);
         // Do the code.
         $row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']);
         // And the array...
         $context['posts'][$counter += $reverse ? -1 : 1] = array('body' => $row['body'], 'counter' => $counter, 'alternate' => $counter % 2, 'category' => array('name' => $row['cname'], 'id' => $row['id_cat']), 'board' => array('name' => $row['bname'], 'id' => $row['id_board'], 'link' => '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['bname'] . '</a>'), 'topic' => array('id' => $row['id_topic'], 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'] . '">' . $row['subject'] . '</a>'), 'subject' => $row['subject'], 'start' => 'msg' . $row['id_msg'], 'time' => standardTime($row['poster_time']), 'html_time' => htmlTime($row['poster_time']), 'timestamp' => forum_time(true, $row['poster_time']), 'id' => $row['id_msg'], 'tests' => array('can_reply' => false, 'can_mark_notify' => false, 'can_delete' => false), 'delete_possible' => ($row['id_first_msg'] != $row['id_msg'] || $row['id_last_msg'] == $row['id_msg']) && (empty($modSettings['edit_disable_time']) || $row['poster_time'] + $modSettings['edit_disable_time'] * 60 >= time()), 'approved' => $row['approved'], 'buttons' => array('remove' => array('href' => $scripturl . '?action=deletemsg;msg=' . $row['id_msg'] . ';topic=' . $row['id_topic'] . ';profile;u=' . $context['member']['id'] . ';start=' . $context['start'], 'text' => $txt['remove'], 'test' => 'can_delete', 'custom' => 'onclick="return confirm(' . JavaScriptEscape($txt['remove_message'] . '?') . ');"'), 'notify' => array('href' => $scripturl . '?action=notify;topic=' . $row['id_topic'] . '.msg' . $row['id_msg'], 'text' => $txt['notify'], 'test' => 'can_mark_notify'), 'reply' => array('href' => $scripturl . '?action=post;topic=' . $row['id_topic'] . '.msg' . $row['id_msg'], 'text' => $txt['reply'], 'test' => 'can_reply'), 'quote' => array('href' => $scripturl . '?action=post;topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . ';quote=' . $row['id_msg'], 'text' => $txt['quote'], 'test' => 'can_quote')));
         if ($user_info['id'] == $row['id_member_started']) {
             $board_ids['own'][$row['id_board']][] = $counter;
         }
         $board_ids['any'][$row['id_board']][] = $counter;
     }
     // All posts were retrieved in reverse order, get them right again.
     if ($reverse) {
         $context['posts'] = array_reverse($context['posts'], true);
     }
     // These are all the permissions that are different from board to board..
     if ($context['is_topics']) {
         $permissions = array('own' => array('post_reply_own' => 'can_reply'), 'any' => array('post_reply_any' => 'can_reply', 'mark_any_notify' => 'can_mark_notify'));
     } else {
         $permissions = array('own' => array('post_reply_own' => 'can_reply', 'delete_own' => 'can_delete'), 'any' => array('post_reply_any' => 'can_reply', 'mark_any_notify' => 'can_mark_notify', 'delete_any' => 'can_delete'));
     }
     // For every permission in the own/any lists...
     foreach ($permissions as $type => $list) {
         foreach ($list as $permission => $allowed) {
             // Get the boards they can do this on...
             $boards = boardsAllowedTo($permission);
             // Hmm, they can do it on all boards, can they?
             if (!empty($boards) && $boards[0] == 0) {
                 $boards = array_keys($board_ids[$type]);
             }
             // Now go through each board they can do the permission on.
             foreach ($boards as $board_id) {
                 // There aren't any posts displayed from this board.
                 if (!isset($board_ids[$type][$board_id])) {
                     continue;
                 }
                 // Set the permission to true ;).
                 foreach ($board_ids[$type][$board_id] as $counter) {
                     $context['posts'][$counter]['tests'][$allowed] = true;
                 }
             }
         }
     }
     // Clean up after posts that cannot be deleted and quoted.
     $quote_enabled = empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC']));
     foreach ($context['posts'] as $counter => $dummy) {
         $context['posts'][$counter]['tests']['can_delete'] &= $context['posts'][$counter]['delete_possible'];
         $context['posts'][$counter]['tests']['can_quote'] = $context['posts'][$counter]['tests']['can_reply'] && $quote_enabled;
     }
 }
Example #12
0
    /**
     * Posts or saves the message composed with Post().
     *
     * requires various permissions depending on the action.
     * handles attachment, post, and calendar saving.
     * sends off notifications, and allows for announcements and moderation.
     * accessed from ?action=post2.
     */
    public function action_post2()
    {
        global $board, $topic, $txt, $modSettings, $context, $user_settings;
        global $user_info, $board_info, $options, $ignore_temp;
        // Sneaking off, are we?
        if (empty($_POST) && empty($topic)) {
            if (empty($_SERVER['CONTENT_LENGTH'])) {
                redirectexit('action=post;board=' . $board . '.0');
            } else {
                fatal_lang_error('post_upload_error', false);
            }
        } elseif (empty($_POST) && !empty($topic)) {
            redirectexit('action=post;topic=' . $topic . '.0');
        }
        // No need!
        $context['robot_no_index'] = true;
        // We are now in post2 action
        $context['current_action'] = 'post2';
        require_once SOURCEDIR . '/AttachmentErrorContext.class.php';
        // No errors as yet.
        $post_errors = Error_Context::context('post', 1);
        $attach_errors = Attachment_Error_Context::context();
        // If the session has timed out, let the user re-submit their form.
        if (checkSession('post', '', false) != '') {
            $post_errors->addError('session_timeout');
            // Disable the preview so that any potentially malicious code is not executed
            $_REQUEST['preview'] = false;
            return $this->action_post();
        }
        // Wrong verification code?
        if (!$user_info['is_admin'] && !$user_info['is_mod'] && !empty($modSettings['posts_require_captcha']) && ($user_info['posts'] < $modSettings['posts_require_captcha'] || $user_info['is_guest'] && $modSettings['posts_require_captcha'] == -1)) {
            require_once SUBSDIR . '/VerificationControls.class.php';
            $verificationOptions = array('id' => 'post');
            $context['require_verification'] = create_control_verification($verificationOptions, true);
            if (is_array($context['require_verification'])) {
                foreach ($context['require_verification'] as $verification_error) {
                    $post_errors->addError($verification_error);
                }
            }
        }
        require_once SUBSDIR . '/Boards.subs.php';
        require_once SUBSDIR . '/Post.subs.php';
        loadLanguage('Post');
        // Drafts enabled and needed?
        if (!empty($modSettings['drafts_enabled']) && (isset($_POST['save_draft']) || isset($_POST['id_draft']))) {
            require_once SUBSDIR . '/Drafts.subs.php';
        }
        // First check to see if they are trying to delete any current attachments.
        if (isset($_POST['attach_del'])) {
            $keep_temp = array();
            $keep_ids = array();
            foreach ($_POST['attach_del'] as $dummy) {
                if (strpos($dummy, 'post_tmp_' . $user_info['id']) !== false) {
                    $keep_temp[] = $dummy;
                } else {
                    $keep_ids[] = (int) $dummy;
                }
            }
            if (isset($_SESSION['temp_attachments'])) {
                foreach ($_SESSION['temp_attachments'] as $attachID => $attachment) {
                    if (isset($_SESSION['temp_attachments']['post']['files'], $attachment['name']) && in_array($attachment['name'], $_SESSION['temp_attachments']['post']['files']) || in_array($attachID, $keep_temp) || strpos($attachID, 'post_tmp_' . $user_info['id']) === false) {
                        continue;
                    }
                    unset($_SESSION['temp_attachments'][$attachID]);
                    @unlink($attachment['tmp_name']);
                }
            }
            if (!empty($_REQUEST['msg'])) {
                require_once SUBSDIR . '/ManageAttachments.subs.php';
                $attachmentQuery = array('attachment_type' => 0, 'id_msg' => (int) $_REQUEST['msg'], 'not_id_attach' => $keep_ids);
                removeAttachments($attachmentQuery);
            }
        }
        // Then try to upload any attachments.
        $context['attachments']['can']['post'] = !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1 && (allowedTo('post_attachment') || $modSettings['postmod_active'] && allowedTo('post_unapproved_attachments'));
        if ($context['attachments']['can']['post'] && empty($_POST['from_qr'])) {
            require_once SUBSDIR . '/Attachments.subs.php';
            if (isset($_REQUEST['msg'])) {
                processAttachments((int) $_REQUEST['msg']);
            } else {
                processAttachments();
            }
        }
        // Previewing? Go back to start.
        if (isset($_REQUEST['preview'])) {
            return $this->action_post();
        }
        // Prevent double submission of this form.
        checkSubmitOnce('check');
        // If this isn't a new topic load the topic info that we need.
        if (!empty($topic)) {
            require_once SUBSDIR . '/Topic.subs.php';
            $topic_info = getTopicInfo($topic);
            // Though the topic should be there, it might have vanished.
            if (empty($topic_info)) {
                fatal_lang_error('topic_doesnt_exist');
            }
            // Did this topic suddenly move? Just checking...
            if ($topic_info['id_board'] != $board) {
                fatal_lang_error('not_a_topic');
            }
        }
        // Replying to a topic?
        if (!empty($topic) && !isset($_REQUEST['msg'])) {
            // Don't allow a post if it's locked.
            if ($topic_info['locked'] != 0 && !allowedTo('moderate_board')) {
                fatal_lang_error('topic_locked', false);
            }
            // Sorry, multiple polls aren't allowed... yet.  You should stop giving me ideas :P.
            if (isset($_REQUEST['poll']) && $topic_info['id_poll'] > 0) {
                unset($_REQUEST['poll']);
            }
            // Do the permissions and approval stuff...
            $becomesApproved = true;
            if ($topic_info['id_member_started'] != $user_info['id']) {
                if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_any') && !allowedTo('post_reply_any')) {
                    $becomesApproved = false;
                } else {
                    isAllowedTo('post_reply_any');
                }
            } elseif (!allowedTo('post_reply_any')) {
                if ($modSettings['postmod_active']) {
                    if (allowedTo('post_unapproved_replies_own') && !allowedTo('post_reply_own')) {
                        $becomesApproved = false;
                    } elseif ($user_info['is_guest'] && allowedTo('post_unapproved_replies_any')) {
                        $becomesApproved = false;
                    } else {
                        isAllowedTo('post_reply_own');
                    }
                }
            }
            if (isset($_POST['lock'])) {
                // Nothing is changed to the lock.
                if (empty($topic_info['locked']) && empty($_POST['lock']) || !empty($_POST['lock']) && !empty($topic_info['locked'])) {
                    unset($_POST['lock']);
                } elseif (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']) {
                    unset($_POST['lock']);
                } elseif (!allowedTo('lock_any')) {
                    // You cannot override a moderator lock.
                    if ($topic_info['locked'] == 1) {
                        unset($_POST['lock']);
                    } else {
                        $_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
                    }
                } else {
                    $_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
                }
            }
            // So you wanna (un)sticky this...let's see.
            if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || $_POST['sticky'] == $topic_info['is_sticky'] || !allowedTo('make_sticky'))) {
                unset($_POST['sticky']);
            }
            // If drafts are enabled, then pass this off
            if (!empty($modSettings['drafts_enabled']) && isset($_POST['save_draft'])) {
                saveDraft();
                return $this->action_post();
            }
            // If the number of replies has changed, if the setting is enabled, go back to action_post() - which handles the error.
            if (empty($options['no_new_reply_warning']) && isset($_POST['last_msg']) && $topic_info['id_last_msg'] > $_POST['last_msg']) {
                addInlineJavascript('
					$(document).ready(function () {
						$("html,body").scrollTop($(\'.category_header:visible:first\').offset().top);
					});');
                return $this->action_post();
            }
            $posterIsGuest = $user_info['is_guest'];
        } elseif (empty($topic)) {
            // Now don't be silly, new topics will get their own id_msg soon enough.
            unset($_REQUEST['msg'], $_POST['msg'], $_GET['msg']);
            // Do like, the permissions, for safety and stuff...
            $becomesApproved = true;
            if ($modSettings['postmod_active'] && !allowedTo('post_new') && allowedTo('post_unapproved_topics')) {
                $becomesApproved = false;
            } else {
                isAllowedTo('post_new');
            }
            if (isset($_POST['lock'])) {
                // New topics are by default not locked.
                if (empty($_POST['lock'])) {
                    unset($_POST['lock']);
                } elseif (!allowedTo(array('lock_any', 'lock_own'))) {
                    unset($_POST['lock']);
                } else {
                    $_POST['lock'] = allowedTo('lock_any') ? 1 : 2;
                }
            }
            if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || empty($_POST['sticky']) || !allowedTo('make_sticky'))) {
                unset($_POST['sticky']);
            }
            // Saving your new topic as a draft first?
            if (!empty($modSettings['drafts_enabled']) && isset($_POST['save_draft'])) {
                saveDraft();
                return $this->action_post();
            }
            $posterIsGuest = $user_info['is_guest'];
        } elseif (isset($_REQUEST['msg']) && !empty($topic)) {
            $_REQUEST['msg'] = (int) $_REQUEST['msg'];
            require_once SUBSDIR . '/Messages.subs.php';
            $msgInfo = basicMessageInfo($_REQUEST['msg'], true);
            if (empty($msgInfo)) {
                fatal_lang_error('cant_find_messages', false);
            }
            if (!empty($topic_info['locked']) && !allowedTo('moderate_board')) {
                fatal_lang_error('topic_locked', false);
            }
            if (isset($_POST['lock'])) {
                // Nothing changes to the lock status.
                if (empty($_POST['lock']) && empty($topic_info['locked']) || !empty($_POST['lock']) && !empty($topic_info['locked'])) {
                    unset($_POST['lock']);
                } elseif (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']) {
                    unset($_POST['lock']);
                } elseif (!allowedTo('lock_any')) {
                    // You're not allowed to break a moderator's lock.
                    if ($topic_info['locked'] == 1) {
                        unset($_POST['lock']);
                    } else {
                        $_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
                    }
                } else {
                    $_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
                }
            }
            // Change the sticky status of this topic?
            if (isset($_POST['sticky']) && (!allowedTo('make_sticky') || $_POST['sticky'] == $topic_info['is_sticky'])) {
                unset($_POST['sticky']);
            }
            if ($msgInfo['id_member'] == $user_info['id'] && !allowedTo('modify_any')) {
                if ((!$modSettings['postmod_active'] || $msgInfo['approved']) && !empty($modSettings['edit_disable_time']) && $msgInfo['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time()) {
                    fatal_lang_error('modify_post_time_passed', false);
                } elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_own')) {
                    isAllowedTo('modify_replies');
                } else {
                    isAllowedTo('modify_own');
                }
            } elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_any')) {
                isAllowedTo('modify_replies');
                // If you're modifying a reply, I say it better be logged...
                $moderationAction = true;
            } else {
                isAllowedTo('modify_any');
                // Log it, assuming you're not modifying your own post.
                if ($msgInfo['id_member'] != $user_info['id']) {
                    $moderationAction = true;
                }
            }
            // If drafts are enabled, then lets send this off to save
            if (!empty($modSettings['drafts_enabled']) && isset($_POST['save_draft'])) {
                saveDraft();
                return $this->action_post();
            }
            $posterIsGuest = empty($msgInfo['id_member']);
            // Can they approve it?
            $can_approve = allowedTo('approve_posts');
            $becomesApproved = $modSettings['postmod_active'] ? $can_approve && !$msgInfo['approved'] ? !empty($_REQUEST['approve']) ? 1 : 0 : $msgInfo['approved'] : 1;
            $approve_has_changed = $msgInfo['approved'] != $becomesApproved;
            if (!allowedTo('moderate_forum') || !$posterIsGuest) {
                $_POST['guestname'] = $msgInfo['poster_name'];
                $_POST['email'] = $msgInfo['poster_email'];
            }
        }
        // In case we want to override
        if (allowedTo('approve_posts')) {
            $becomesApproved = !isset($_REQUEST['approve']) || !empty($_REQUEST['approve']) ? 1 : 0;
            $approve_has_changed = isset($msgInfo['approved']) ? $msgInfo['approved'] != $becomesApproved : false;
        }
        // If the poster is a guest evaluate the legality of name and email.
        if ($posterIsGuest) {
            $_POST['guestname'] = !isset($_POST['guestname']) ? '' : Util::htmlspecialchars(trim($_POST['guestname']));
            $_POST['email'] = !isset($_POST['email']) ? '' : Util::htmlspecialchars(trim($_POST['email']));
            if ($_POST['guestname'] == '' || $_POST['guestname'] == '_') {
                $post_errors->addError('no_name');
            }
            if (Util::strlen($_POST['guestname']) > 25) {
                $post_errors->addError('long_name');
            }
            if (empty($modSettings['guest_post_no_email'])) {
                // Only check if they changed it!
                if (!isset($msgInfo) || $msgInfo['poster_email'] != $_POST['email']) {
                    require_once SUBSDIR . '/DataValidator.class.php';
                    if (!allowedTo('moderate_forum') && !Data_Validator::is_valid($_POST, array('email' => 'valid_email|required'), array('email' => 'trim'))) {
                        empty($_POST['email']) ? $post_errors->addError('no_email') : $post_errors->addError('bad_email');
                    }
                }
                // Now make sure this email address is not banned from posting.
                isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt['guest_title']));
            }
            // In case they are making multiple posts this visit, help them along by storing their name.
            if (!$post_errors->hasErrors()) {
                $_SESSION['guest_name'] = $_POST['guestname'];
                $_SESSION['guest_email'] = $_POST['email'];
            }
        }
        // Check the subject and message.
        if (!isset($_POST['subject']) || Util::htmltrim(Util::htmlspecialchars($_POST['subject'])) === '') {
            $post_errors->addError('no_subject');
        }
        if (!isset($_POST['message']) || Util::htmltrim(Util::htmlspecialchars($_POST['message'], ENT_QUOTES)) === '') {
            $post_errors->addError('no_message');
        } elseif (!empty($modSettings['max_messageLength']) && Util::strlen($_POST['message']) > $modSettings['max_messageLength']) {
            $post_errors->addError(array('long_message', array($modSettings['max_messageLength'])));
        } else {
            // Prepare the message a bit for some additional testing.
            $_POST['message'] = Util::htmlspecialchars($_POST['message'], ENT_QUOTES);
            // Preparse code. (Zef)
            if ($user_info['is_guest']) {
                $user_info['name'] = $_POST['guestname'];
            }
            preparsecode($_POST['message']);
            // Let's see if there's still some content left without the tags.
            if (Util::htmltrim(strip_tags(parse_bbc($_POST['message'], false), '<img>')) === '' && (!allowedTo('admin_forum') || strpos($_POST['message'], '[html]') === false)) {
                $post_errors->addError('no_message');
            }
        }
        if (isset($_POST['calendar']) && !isset($_REQUEST['deleteevent']) && Util::htmltrim($_POST['evtitle']) === '') {
            $post_errors->addError('no_event');
        }
        // Validate the poll...
        if (isset($_REQUEST['poll']) && !empty($modSettings['pollMode'])) {
            if (!empty($topic) && !isset($_REQUEST['msg'])) {
                fatal_lang_error('no_access', false);
            }
            // This is a new topic... so it's a new poll.
            if (empty($topic)) {
                isAllowedTo('poll_post');
            } elseif ($user_info['id'] == $topic_info['id_member_started'] && !allowedTo('poll_add_any')) {
                isAllowedTo('poll_add_own');
            } else {
                isAllowedTo('poll_add_any');
            }
            if (!isset($_POST['question']) || trim($_POST['question']) == '') {
                $post_errors->addError('no_question');
            }
            $_POST['options'] = empty($_POST['options']) ? array() : htmltrim__recursive($_POST['options']);
            // Get rid of empty ones.
            foreach ($_POST['options'] as $k => $option) {
                if ($option == '') {
                    unset($_POST['options'][$k], $_POST['options'][$k]);
                }
            }
            // What are you going to vote between with one choice?!?
            if (count($_POST['options']) < 2) {
                $post_errors->addError('poll_few');
            } elseif (count($_POST['options']) > 256) {
                $post_errors->addError('poll_many');
            }
        }
        if ($posterIsGuest) {
            // If user is a guest, make sure the chosen name isn't taken.
            require_once SUBSDIR . '/Members.subs.php';
            if (isReservedName($_POST['guestname'], 0, true, false) && (!isset($msgInfo['poster_name']) || $_POST['guestname'] != $msgInfo['poster_name'])) {
                $post_errors->addError('bad_name');
            }
        } elseif (!isset($_REQUEST['msg'])) {
            $_POST['guestname'] = $user_info['username'];
            $_POST['email'] = $user_info['email'];
        }
        // Posting somewhere else? Are we sure you can?
        if (!empty($_REQUEST['post_in_board'])) {
            $new_board = (int) $_REQUEST['post_in_board'];
            if (!allowedTo('post_new', $new_board)) {
                $post_in_board = boardInfo($new_board);
                if (!empty($post_in_board)) {
                    $post_errors->addError(array('post_new_board', array($post_in_board['name'])));
                } else {
                    $post_errors->addError('post_new');
                }
            }
        }
        // Any mistakes?
        if ($post_errors->hasErrors() || $attach_errors->hasErrors()) {
            addInlineJavascript('
				$(document).ready(function () {
					$("html,body").scrollTop($(\'.category_header:visible:first\').offset().top);
				});');
            return $this->action_post();
        }
        // Make sure the user isn't spamming the board.
        if (!isset($_REQUEST['msg'])) {
            spamProtection('post');
        }
        // At about this point, we're posting and that's that.
        ignore_user_abort(true);
        @set_time_limit(300);
        // Add special html entities to the subject, name, and email.
        $_POST['subject'] = strtr(Util::htmlspecialchars($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
        $_POST['guestname'] = htmlspecialchars($_POST['guestname'], ENT_COMPAT, 'UTF-8');
        $_POST['email'] = htmlspecialchars($_POST['email'], ENT_COMPAT, 'UTF-8');
        // At this point, we want to make sure the subject isn't too long.
        if (Util::strlen($_POST['subject']) > 100) {
            $_POST['subject'] = Util::substr($_POST['subject'], 0, 100);
        }
        if (!empty($modSettings['mentions_enabled']) && !empty($_REQUEST['uid'])) {
            $query_params = array();
            $query_params['member_ids'] = array_unique(array_map('intval', $_REQUEST['uid']));
            require_once SUBSDIR . '/Members.subs.php';
            $mentioned_members = membersBy('member_ids', $query_params, true);
            $replacements = 0;
            $actually_mentioned = array();
            foreach ($mentioned_members as $member) {
                $_POST['message'] = str_replace('@' . $member['real_name'], '[member=' . $member['id_member'] . ']' . $member['real_name'] . '[/member]', $_POST['message'], $replacements);
                if ($replacements > 0) {
                    $actually_mentioned[] = $member['id_member'];
                }
            }
        }
        // Make the poll...
        if (isset($_REQUEST['poll'])) {
            // Make sure that the user has not entered a ridiculous number of options..
            if (empty($_POST['poll_max_votes']) || $_POST['poll_max_votes'] <= 0) {
                $_POST['poll_max_votes'] = 1;
            } elseif ($_POST['poll_max_votes'] > count($_POST['options'])) {
                $_POST['poll_max_votes'] = count($_POST['options']);
            } else {
                $_POST['poll_max_votes'] = (int) $_POST['poll_max_votes'];
            }
            $_POST['poll_expire'] = (int) $_POST['poll_expire'];
            $_POST['poll_expire'] = $_POST['poll_expire'] > 9999 ? 9999 : ($_POST['poll_expire'] < 0 ? 0 : $_POST['poll_expire']);
            // Just set it to zero if it's not there..
            if (!isset($_POST['poll_hide'])) {
                $_POST['poll_hide'] = 0;
            } else {
                $_POST['poll_hide'] = (int) $_POST['poll_hide'];
            }
            $_POST['poll_change_vote'] = isset($_POST['poll_change_vote']) ? 1 : 0;
            $_POST['poll_guest_vote'] = isset($_POST['poll_guest_vote']) ? 1 : 0;
            // Make sure guests are actually allowed to vote generally.
            if ($_POST['poll_guest_vote']) {
                require_once SUBSDIR . '/Members.subs.php';
                $allowedVoteGroups = groupsAllowedTo('poll_vote', $board);
                if (!in_array(-1, $allowedVoteGroups['allowed'])) {
                    $_POST['poll_guest_vote'] = 0;
                }
            }
            // If the user tries to set the poll too far in advance, don't let them.
            if (!empty($_POST['poll_expire']) && $_POST['poll_expire'] < 1) {
                fatal_lang_error('poll_range_error', false);
            } elseif (empty($_POST['poll_expire']) && $_POST['poll_hide'] == 2) {
                $_POST['poll_hide'] = 1;
            }
            // Clean up the question and answers.
            $_POST['question'] = htmlspecialchars($_POST['question'], ENT_COMPAT, 'UTF-8');
            $_POST['question'] = Util::substr($_POST['question'], 0, 255);
            $_POST['question'] = preg_replace('~&amp;#(\\d{4,5}|[2-9]\\d{2,4}|1[2-9]\\d);~', '&#$1;', $_POST['question']);
            $_POST['options'] = htmlspecialchars__recursive($_POST['options']);
            // Finally, make the poll.
            require_once SUBSDIR . '/Poll.subs.php';
            $id_poll = createPoll($_POST['question'], $user_info['id'], $_POST['guestname'], $_POST['poll_max_votes'], $_POST['poll_hide'], $_POST['poll_expire'], $_POST['poll_change_vote'], $_POST['poll_guest_vote'], $_POST['options']);
        } else {
            $id_poll = 0;
        }
        // ...or attach a new file...
        if (empty($ignore_temp) && $context['attachments']['can']['post'] && !empty($_SESSION['temp_attachments']) && empty($_POST['from_qr'])) {
            $attachIDs = array();
            foreach ($_SESSION['temp_attachments'] as $attachID => $attachment) {
                if ($attachID != 'initial_error' && strpos($attachID, 'post_tmp_' . $user_info['id']) === false) {
                    continue;
                }
                // If there was an initial error just show that message.
                if ($attachID == 'initial_error') {
                    unset($_SESSION['temp_attachments']);
                    break;
                }
                // No errors, then try to create the attachment
                if (empty($attachment['errors'])) {
                    // Load the attachmentOptions array with the data needed to create an attachment
                    $attachmentOptions = array('post' => isset($_REQUEST['msg']) ? $_REQUEST['msg'] : 0, 'poster' => $user_info['id'], 'name' => $attachment['name'], 'tmp_name' => $attachment['tmp_name'], 'size' => isset($attachment['size']) ? $attachment['size'] : 0, 'mime_type' => isset($attachment['type']) ? $attachment['type'] : '', 'id_folder' => isset($attachment['id_folder']) ? $attachment['id_folder'] : 0, 'approved' => !$modSettings['postmod_active'] || allowedTo('post_attachment'), 'errors' => array());
                    if (createAttachment($attachmentOptions)) {
                        $attachIDs[] = $attachmentOptions['id'];
                        if (!empty($attachmentOptions['thumb'])) {
                            $attachIDs[] = $attachmentOptions['thumb'];
                        }
                    }
                } else {
                    @unlink($attachment['tmp_name']);
                }
            }
            unset($_SESSION['temp_attachments']);
        }
        // Creating a new topic?
        $newTopic = empty($_REQUEST['msg']) && empty($topic);
        $_POST['icon'] = !empty($attachIDs) && $_POST['icon'] == 'xx' ? 'clip' : $_POST['icon'];
        // Collect all parameters for the creation or modification of a post.
        $msgOptions = array('id' => empty($_REQUEST['msg']) ? 0 : (int) $_REQUEST['msg'], 'subject' => $_POST['subject'], 'body' => $_POST['message'], 'icon' => preg_replace('~[\\./\\\\*:"\'<>]~', '', $_POST['icon']), 'smileys_enabled' => !isset($_POST['ns']), 'attachments' => empty($attachIDs) ? array() : $attachIDs, 'approved' => $becomesApproved);
        $topicOptions = array('id' => empty($topic) ? 0 : $topic, 'board' => $board, 'poll' => isset($_REQUEST['poll']) ? $id_poll : null, 'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null, 'sticky_mode' => isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics']) ? (int) $_POST['sticky'] : null, 'mark_as_read' => true, 'is_approved' => !$modSettings['postmod_active'] || empty($topic) || !empty($board_info['cur_topic_approved']));
        $posterOptions = array('id' => $user_info['id'], 'name' => $_POST['guestname'], 'email' => $_POST['email'], 'update_post_count' => !$user_info['is_guest'] && !isset($_REQUEST['msg']) && $board_info['posts_count']);
        // This is an already existing message. Edit it.
        if (!empty($_REQUEST['msg'])) {
            // Have admins allowed people to hide their screwups?
            if (time() - $msgInfo['poster_time'] > $modSettings['edit_wait_time'] || $user_info['id'] != $msgInfo['id_member']) {
                $msgOptions['modify_time'] = time();
                $msgOptions['modify_name'] = $user_info['name'];
            }
            // This will save some time...
            if (empty($approve_has_changed)) {
                unset($msgOptions['approved']);
            }
            modifyPost($msgOptions, $topicOptions, $posterOptions);
        } else {
            if (!empty($modSettings['enableFollowup']) && !empty($_REQUEST['followup'])) {
                $original_post = (int) $_REQUEST['followup'];
            }
            // We also have to fake the board:
            // if it's valid and it's not the current, let's forget about the "current" and load the new one
            if (!empty($new_board) && $board !== $new_board) {
                $board = $new_board;
                loadBoard();
                // Some details changed
                $topicOptions['board'] = $board;
                $topicOptions['is_approved'] = !$modSettings['postmod_active'] || empty($topic) || !empty($board_info['cur_topic_approved']);
                $posterOptions['update_post_count'] = !$user_info['is_guest'] && !isset($_REQUEST['msg']) && $board_info['posts_count'];
            }
            createPost($msgOptions, $topicOptions, $posterOptions);
            if (isset($topicOptions['id'])) {
                $topic = $topicOptions['id'];
            }
            if (!empty($modSettings['enableFollowup'])) {
                require_once SUBSDIR . '/FollowUps.subs.php';
                require_once SUBSDIR . '/Messages.subs.php';
                // Time to update the original message with a pointer to the new one
                if (!empty($original_post) && canAccessMessage($original_post)) {
                    linkMessages($original_post, $topic);
                }
            }
        }
        // If we had a draft for this, its time to remove it since it was just posted
        if (!empty($modSettings['drafts_enabled']) && !empty($_POST['id_draft'])) {
            deleteDrafts($_POST['id_draft'], $user_info['id']);
        }
        // Editing or posting an event?
        if (isset($_POST['calendar']) && (!isset($_REQUEST['eventid']) || $_REQUEST['eventid'] == -1)) {
            require_once SUBSDIR . '/Calendar.subs.php';
            // Make sure they can link an event to this post.
            canLinkEvent();
            // Insert the event.
            $eventOptions = array('id_board' => $board, 'id_topic' => $topic, 'title' => $_POST['evtitle'], 'member' => $user_info['id'], 'start_date' => sprintf('%04d-%02d-%02d', $_POST['year'], $_POST['month'], $_POST['day']), 'span' => isset($_POST['span']) && $_POST['span'] > 0 ? min((int) $modSettings['cal_maxspan'], (int) $_POST['span'] - 1) : 0);
            insertEvent($eventOptions);
        } elseif (isset($_POST['calendar'])) {
            $_REQUEST['eventid'] = (int) $_REQUEST['eventid'];
            // Validate the post...
            require_once SUBSDIR . '/Calendar.subs.php';
            validateEventPost();
            // If you're not allowed to edit any events, you have to be the poster.
            if (!allowedTo('calendar_edit_any')) {
                $event_poster = getEventPoster($_REQUEST['eventid']);
                // Silly hacker, Trix are for kids. ...probably trademarked somewhere, this is FAIR USE! (parody...)
                isAllowedTo('calendar_edit_' . ($event_poster == $user_info['id'] ? 'own' : 'any'));
            }
            // Delete it?
            if (isset($_REQUEST['deleteevent'])) {
                removeEvent($_REQUEST['eventid']);
            } else {
                $span = !empty($modSettings['cal_allowspan']) && !empty($_REQUEST['span']) ? min((int) $modSettings['cal_maxspan'], (int) $_REQUEST['span'] - 1) : 0;
                $start_time = mktime(0, 0, 0, (int) $_REQUEST['month'], (int) $_REQUEST['day'], (int) $_REQUEST['year']);
                $eventOptions = array('start_date' => strftime('%Y-%m-%d', $start_time), 'end_date' => strftime('%Y-%m-%d', $start_time + $span * 86400), 'title' => $_REQUEST['evtitle']);
                modifyEvent($_REQUEST['eventid'], $eventOptions);
            }
        }
        // Marking boards as read.
        // (You just posted and they will be unread.)
        if (!$user_info['is_guest']) {
            $board_list = !empty($board_info['parent_boards']) ? array_keys($board_info['parent_boards']) : array();
            // Returning to the topic?
            if (!empty($_REQUEST['goback'])) {
                $board_list[] = $board;
            }
            if (!empty($board_list)) {
                markBoardsRead($board_list, false, false);
            }
        }
        // Turn notification on or off.
        if (!empty($_POST['notify']) && allowedTo('mark_any_notify')) {
            setTopicNotification($user_info['id'], $topic, true);
        } elseif (!$newTopic) {
            setTopicNotification($user_info['id'], $topic, false);
        }
        // Log an act of moderation - modifying.
        if (!empty($moderationAction)) {
            logAction('modify', array('topic' => $topic, 'message' => (int) $_REQUEST['msg'], 'member' => $msgInfo['id_member'], 'board' => $board));
        }
        if (isset($_POST['lock']) && $_POST['lock'] != 2) {
            logAction(empty($_POST['lock']) ? 'unlock' : 'lock', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board']));
        }
        if (isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics'])) {
            logAction(empty($_POST['sticky']) ? 'unsticky' : 'sticky', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board']));
        }
        // Notify any members who have notification turned on for this topic/board - only do this if it's going to be approved(!)
        if ($becomesApproved) {
            require_once SUBSDIR . '/Notification.subs.php';
            if ($newTopic) {
                $notifyData = array('body' => $_POST['message'], 'subject' => $_POST['subject'], 'name' => $user_info['name'], 'poster' => $user_info['id'], 'msg' => $msgOptions['id'], 'board' => $board, 'topic' => $topic, 'signature' => isset($user_settings['signature']) ? $user_settings['signature'] : '');
                sendBoardNotifications($notifyData);
            } elseif (empty($_REQUEST['msg'])) {
                // Only send it to everyone if the topic is approved, otherwise just to the topic starter if they want it.
                if ($topic_info['approved']) {
                    sendNotifications($topic, 'reply');
                } else {
                    sendNotifications($topic, 'reply', array(), $topic_info['id_member_started']);
                }
            }
        }
        if (!empty($modSettings['mentions_enabled']) && !empty($actually_mentioned)) {
            require_once CONTROLLERDIR . '/Mentions.controller.php';
            $mentions = new Mentions_Controller();
            $mentions->setData(array('id_member' => $actually_mentioned, 'type' => 'men', 'id_msg' => $msgOptions['id'], 'status' => $becomesApproved ? 'new' : 'unapproved'));
            $mentions->action_add();
        }
        if ($board_info['num_topics'] == 0) {
            cache_put_data('board-' . $board, null, 120);
        }
        if (!empty($_POST['announce_topic'])) {
            redirectexit('action=announce;sa=selectgroup;topic=' . $topic . (!empty($_POST['move']) && allowedTo('move_any') ? ';move' : '') . (empty($_REQUEST['goback']) ? '' : ';goback'));
        }
        if (!empty($_POST['move']) && allowedTo('move_any')) {
            redirectexit('action=movetopic;topic=' . $topic . '.0' . (empty($_REQUEST['goback']) ? '' : ';goback'));
        }
        // Return to post if the mod is on.
        if (isset($_REQUEST['msg']) && !empty($_REQUEST['goback'])) {
            redirectexit('topic=' . $topic . '.msg' . $_REQUEST['msg'] . '#msg' . $_REQUEST['msg'], isBrowser('ie'));
        } elseif (!empty($_REQUEST['goback'])) {
            redirectexit('topic=' . $topic . '.new#new', isBrowser('ie'));
        } else {
            redirectexit('board=' . $board . '.0');
        }
    }
 /**
  * Approve a post, just the one.
  */
 public function action_approve()
 {
     global $user_info, $topic, $board;
     checkSession('get');
     $current_msg = (int) $_REQUEST['msg'];
     require_once SUBSDIR . '/Topic.subs.php';
     require_once SUBSDIR . '/Post.subs.php';
     require_once SUBSDIR . '/Messages.subs.php';
     isAllowedTo('approve_posts');
     $message_info = basicMessageInfo($current_msg, false, true);
     // If it's the first in a topic then the whole topic gets approved!
     if ($message_info['id_first_msg'] == $current_msg) {
         approveTopics($topic, !$message_info['approved']);
         if ($message_info['id_member_started'] != $user_info['id']) {
             logAction(($message_info['approved'] ? 'un' : '') . 'approve_topic', array('topic' => $topic, 'subject' => $message_info['subject'], 'member' => $message_info['id_member_started'], 'board' => $board));
         }
     } else {
         approvePosts($current_msg, !$message_info['approved']);
         if ($message_info['id_member'] != $user_info['id']) {
             logAction(($message_info['approved'] ? 'un' : '') . 'approve', array('topic' => $topic, 'subject' => $message_info['subject'], 'member' => $message_info['id_member'], 'board' => $board));
         }
     }
     cache_put_data('num_menu_errors', null, 900);
     redirectexit('topic=' . $topic . '.msg' . $current_msg . '#msg' . $current_msg);
 }