Esempio n. 1
0
function Display()
{
    global $scripturl, $txt, $modSettings, $context, $settings;
    global $options, $sourcedir, $user_info, $board_info, $topic, $board;
    global $attachments, $messages_request, $topicinfo, $language, $smcFunc;
    // What are you gonna display if these are empty?!
    if (empty($topic)) {
        fatal_lang_error('no_board', false);
    }
    // Load the proper template and/or sub template.
    if (WIRELESS) {
        $context['sub_template'] = WIRELESS_PROTOCOL . '_display';
    } else {
        loadTemplate('Display');
    }
    // Not only does a prefetch make things slower for the server, but it makes it impossible to know if they read it.
    if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') {
        ob_end_clean();
        header('HTTP/1.1 403 Prefetch Forbidden');
        die;
    }
    // How much are we sticking on each page?
    $context['messages_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) && !WIRELESS ? $options['messages_per_page'] : $modSettings['defaultMaxMessages'];
    // Let's do some work on what to search index.
    if (count($_GET) > 2) {
        foreach ($_GET as $k => $v) {
            if (!in_array($k, array('topic', 'board', 'start', session_name()))) {
                $context['robot_no_index'] = true;
            }
        }
    }
    if (!empty($_REQUEST['start']) && (!is_numeric($_REQUEST['start']) || $_REQUEST['start'] % $context['messages_per_page'] != 0)) {
        $context['robot_no_index'] = true;
    }
    // Find the previous or next topic.  Make a fuss if there are no more.
    if (isset($_REQUEST['prev_next']) && ($_REQUEST['prev_next'] == 'prev' || $_REQUEST['prev_next'] == 'next')) {
        // No use in calculating the next topic if there's only one.
        if ($board_info['num_topics'] > 1) {
            // Just prepare some variables that are used in the query.
            $gt_lt = $_REQUEST['prev_next'] == 'prev' ? '>' : '<';
            $order = $_REQUEST['prev_next'] == 'prev' ? '' : ' DESC';
            $request = $smcFunc['db_query']('', '
				SELECT t2.id_topic
				FROM {db_prefix}topics AS t
					INNER JOIN {db_prefix}topics AS t2 ON (' . (empty($modSettings['enableStickyTopics']) ? '
					t2.id_last_msg ' . $gt_lt . ' t.id_last_msg' : '
					(t2.id_last_msg ' . $gt_lt . ' t.id_last_msg AND t2.is_sticky ' . $gt_lt . '= t.is_sticky) OR t2.is_sticky ' . $gt_lt . ' t.is_sticky') . ')
				WHERE t.id_topic = {int:current_topic}
					AND t2.id_board = {int:current_board}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
					AND (t2.approved = {int:is_approved} OR (t2.id_member_started != {int:id_member_started} AND t2.id_member_started = {int:current_member}))') . '
				ORDER BY' . (empty($modSettings['enableStickyTopics']) ? '' : ' t2.is_sticky' . $order . ',') . ' t2.id_last_msg' . $order . '
				LIMIT 1', array('current_board' => $board, 'current_member' => $user_info['id'], 'current_topic' => $topic, 'is_approved' => 1, 'id_member_started' => 0));
            // No more left.
            if ($smcFunc['db_num_rows']($request) == 0) {
                $smcFunc['db_free_result']($request);
                // Roll over - if we're going prev, get the last - otherwise the first.
                $request = $smcFunc['db_query']('', '
					SELECT id_topic
					FROM {db_prefix}topics
					WHERE id_board = {int:current_board}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
						AND (approved = {int:is_approved} OR (id_member_started != {int:id_member_started} AND id_member_started = {int:current_member}))') . '
					ORDER BY' . (empty($modSettings['enableStickyTopics']) ? '' : ' is_sticky' . $order . ',') . ' id_last_msg' . $order . '
					LIMIT 1', array('current_board' => $board, 'current_member' => $user_info['id'], 'is_approved' => 1, 'id_member_started' => 0));
            }
            // Now you can be sure $topic is the id_topic to view.
            list($topic) = $smcFunc['db_fetch_row']($request);
            $smcFunc['db_free_result']($request);
            $context['current_topic'] = $topic;
        }
        // Go to the newest message on this topic.
        $_REQUEST['start'] = 'new';
    }
    // Add 1 to the number of views of this topic.
    if (empty($_SESSION['last_read_topic']) || $_SESSION['last_read_topic'] != $topic) {
        $smcFunc['db_query']('', '
			UPDATE {db_prefix}topics
			SET num_views = num_views + 1
			WHERE id_topic = {int:current_topic}', array('current_topic' => $topic));
        $_SESSION['last_read_topic'] = $topic;
    }
    // Get all the important topic info.
    $request = $smcFunc['db_query']('', '
		SELECT
			t.num_replies, t.num_views, t.locked, ms.subject, t.is_sticky, t.id_poll,
			t.id_member_started, t.id_first_msg, t.id_last_msg, t.approved, t.unapproved_posts,
			' . ($user_info['is_guest'] ? 't.id_last_msg + 1' : 'IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1') . ' AS new_from
			' . (!empty($modSettings['recycle_board']) && $modSettings['recycle_board'] == $board ? ', id_previous_board, id_previous_topic' : '') . '
		FROM {db_prefix}topics AS t
			INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg)' . ($user_info['is_guest'] ? '' : '
			LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = {int:current_topic} AND lt.id_member = {int:current_member})
			LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = {int:current_board} AND lmr.id_member = {int:current_member})') . '
		WHERE t.id_topic = {int:current_topic}
		LIMIT 1', array('current_member' => $user_info['id'], 'current_topic' => $topic, 'current_board' => $board));
    if ($smcFunc['db_num_rows']($request) == 0) {
        fatal_lang_error('not_a_topic', false);
    }
    $topicinfo = $smcFunc['db_fetch_assoc']($request);
    $smcFunc['db_free_result']($request);
    $context['real_num_replies'] = $context['num_replies'] = $topicinfo['num_replies'];
    $context['topic_first_message'] = $topicinfo['id_first_msg'];
    $context['topic_last_message'] = $topicinfo['id_last_msg'];
    // Add up unapproved replies to get real number of replies...
    if ($modSettings['postmod_active'] && allowedTo('approve_posts')) {
        $context['real_num_replies'] += $topicinfo['unapproved_posts'] - ($topicinfo['approved'] ? 0 : 1);
    }
    // If this topic has unapproved posts, we need to work out how many posts the user can see, for page indexing.
    if ($modSettings['postmod_active'] && $topicinfo['unapproved_posts'] && !$user_info['is_guest'] && !allowedTo('approve_posts')) {
        $request = $smcFunc['db_query']('', '
			SELECT COUNT(id_member) AS my_unapproved_posts
			FROM {db_prefix}messages
			WHERE id_topic = {int:current_topic}
				AND id_member = {int:current_member}
				AND approved = 0', array('current_topic' => $topic, 'current_member' => $user_info['id']));
        list($myUnapprovedPosts) = $smcFunc['db_fetch_row']($request);
        $smcFunc['db_free_result']($request);
        $context['total_visible_posts'] = $context['num_replies'] + $myUnapprovedPosts + ($topicinfo['approved'] ? 1 : 0);
    } else {
        $context['total_visible_posts'] = $context['num_replies'] + $topicinfo['unapproved_posts'] + ($topicinfo['approved'] ? 1 : 0);
    }
    // When was the last time this topic was replied to?  Should we warn them about it?
    $request = $smcFunc['db_query']('', '
		SELECT poster_time
		FROM {db_prefix}messages
		WHERE id_msg = {int:id_last_msg}
		LIMIT 1', array('id_last_msg' => $topicinfo['id_last_msg']));
    list($lastPostTime) = $smcFunc['db_fetch_row']($request);
    $smcFunc['db_free_result']($request);
    $context['oldTopicError'] = !empty($modSettings['oldTopicDays']) && $lastPostTime + $modSettings['oldTopicDays'] * 86400 < time() && empty($sticky);
    // The start isn't a number; it's information about what to do, where to go.
    if (!is_numeric($_REQUEST['start'])) {
        // Redirect to the page and post with new messages, originally by Omar Bazavilvazo.
        if ($_REQUEST['start'] == 'new') {
            // Guests automatically go to the last post.
            if ($user_info['is_guest']) {
                $context['start_from'] = $context['total_visible_posts'] - 1;
                $_REQUEST['start'] = empty($options['view_newest_first']) ? $context['start_from'] : 0;
            } else {
                // Find the earliest unread message in the topic. (the use of topics here is just for both tables.)
                $request = $smcFunc['db_query']('', '
					SELECT IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1 AS new_from
					FROM {db_prefix}topics AS t
						LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = {int:current_topic} AND lt.id_member = {int:current_member})
						LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = {int:current_board} AND lmr.id_member = {int:current_member})
					WHERE t.id_topic = {int:current_topic}
					LIMIT 1', array('current_board' => $board, 'current_member' => $user_info['id'], 'current_topic' => $topic));
                list($new_from) = $smcFunc['db_fetch_row']($request);
                $smcFunc['db_free_result']($request);
                // Fall through to the next if statement.
                $_REQUEST['start'] = 'msg' . $new_from;
            }
        }
        // Start from a certain time index, not a message.
        if (substr($_REQUEST['start'], 0, 4) == 'from') {
            $timestamp = (int) substr($_REQUEST['start'], 4);
            if ($timestamp === 0) {
                $_REQUEST['start'] = 0;
            } else {
                // Find the number of messages posted before said time...
                $request = $smcFunc['db_query']('', '
					SELECT COUNT(*)
					FROM {db_prefix}messages
					WHERE poster_time < {int:timestamp}
						AND id_topic = {int:current_topic}' . ($modSettings['postmod_active'] && $topicinfo['unapproved_posts'] && !allowedTo('approve_posts') ? '
						AND (approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR id_member = {int:current_member}') . ')' : ''), array('current_topic' => $topic, 'current_member' => $user_info['id'], 'is_approved' => 1, 'timestamp' => $timestamp));
                list($context['start_from']) = $smcFunc['db_fetch_row']($request);
                $smcFunc['db_free_result']($request);
                // Handle view_newest_first options, and get the correct start value.
                $_REQUEST['start'] = empty($options['view_newest_first']) ? $context['start_from'] : $context['total_visible_posts'] - $context['start_from'] - 1;
            }
        } elseif (substr($_REQUEST['start'], 0, 3) == 'msg') {
            $virtual_msg = (int) substr($_REQUEST['start'], 3);
            if (!$topicinfo['unapproved_posts'] && $virtual_msg >= $topicinfo['id_last_msg']) {
                $context['start_from'] = $context['total_visible_posts'] - 1;
            } elseif (!$topicinfo['unapproved_posts'] && $virtual_msg <= $topicinfo['id_first_msg']) {
                $context['start_from'] = 0;
            } else {
                // Find the start value for that message......
                $request = $smcFunc['db_query']('', '
					SELECT COUNT(*)
					FROM {db_prefix}messages
					WHERE id_msg < {int:virtual_msg}
						AND id_topic = {int:current_topic}' . ($modSettings['postmod_active'] && $topicinfo['unapproved_posts'] && !allowedTo('approve_posts') ? '
						AND (approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR id_member = {int:current_member}') . ')' : ''), array('current_member' => $user_info['id'], 'current_topic' => $topic, 'virtual_msg' => $virtual_msg, 'is_approved' => 1, 'no_member' => 0));
                list($context['start_from']) = $smcFunc['db_fetch_row']($request);
                $smcFunc['db_free_result']($request);
            }
            // We need to reverse the start as well in this case.
            $_REQUEST['start'] = empty($options['view_newest_first']) ? $context['start_from'] : $context['total_visible_posts'] - $context['start_from'] - 1;
        }
    }
    // Create a previous next string if the selected theme has it as a selected option.
    $context['previous_next'] = $modSettings['enablePreviousNext'] ? '<a href="' . $scripturl . '?topic=' . $topic . '.0;prev_next=prev#new">' . $txt['previous_next_back'] . '</a> <a href="' . $scripturl . '?topic=' . $topic . '.0;prev_next=next#new">' . $txt['previous_next_forward'] . '</a>' : '';
    // Check if spellchecking is both enabled and actually working. (for quick reply.)
    $context['show_spellchecking'] = !empty($modSettings['enableSpellChecking']) && function_exists('pspell_new');
    // Do we need to show the visual verification image?
    $context['require_verification'] = !$user_info['is_mod'] && !$user_info['is_admin'] && !empty($modSettings['posts_require_captcha']) && ($user_info['posts'] < $modSettings['posts_require_captcha'] || $user_info['is_guest'] && $modSettings['posts_require_captcha'] == -1);
    if ($context['require_verification']) {
        require_once $sourcedir . '/Subs-Editor.php';
        $verificationOptions = array('id' => 'post');
        $context['require_verification'] = create_control_verification($verificationOptions);
        $context['visual_verification_id'] = $verificationOptions['id'];
    }
    // Are we showing signatures - or disabled fields?
    $context['signature_enabled'] = substr($modSettings['signature_settings'], 0, 1) == 1;
    $context['disabled_fields'] = isset($modSettings['disabled_profile_fields']) ? array_flip(explode(',', $modSettings['disabled_profile_fields'])) : array();
    // Censor the title...
    censorText($topicinfo['subject']);
    $context['page_title'] = $topicinfo['subject'];
    // Is this already an article?
    $request = $smcFunc['db_query']('', '
		SELECT id_message
		FROM {db_prefix}sp_articles
		WHERE id_message = {int:message}', array('message' => $context['topic_first_message']));
    list($context['topic_is_article']) = $smcFunc['db_fetch_row']($request);
    $smcFunc['db_free_result']($request);
    // Is this topic sticky, or can it even be?
    $topicinfo['is_sticky'] = empty($modSettings['enableStickyTopics']) ? '0' : $topicinfo['is_sticky'];
    // Default this topic to not marked for notifications... of course...
    $context['is_marked_notify'] = false;
    // Did we report a post to a moderator just now?
    $context['report_sent'] = isset($_GET['reportsent']);
    // Let's get nosey, who is viewing this topic?
    if (!empty($settings['display_who_viewing'])) {
        // Start out with no one at all viewing it.
        $context['view_members'] = array();
        $context['view_members_list'] = array();
        $context['view_num_hidden'] = 0;
        // Search for members who have this topic set in their GET data.
        $request = $smcFunc['db_query']('', '
			SELECT
				lo.id_member, lo.log_time, mem.real_name, mem.member_name, mem.show_online,
				mg.online_color, mg.id_group, mg.group_name
			FROM {db_prefix}log_online AS lo
				LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lo.id_member)
				LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = CASE WHEN mem.id_group = {int:reg_id_group} THEN mem.id_post_group ELSE mem.id_group END)
			WHERE INSTR(lo.url, {string:in_url_string}) > 0 OR lo.session = {string:session}', array('reg_id_group' => 0, 'in_url_string' => 's:5:"topic";i:' . $topic . ';', 'session' => $user_info['is_guest'] ? 'ip' . $user_info['ip'] : session_id()));
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            if (empty($row['id_member'])) {
                continue;
            }
            if (!empty($row['online_color'])) {
                $link = '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '" style="color: ' . $row['online_color'] . ';">' . $row['real_name'] . '</a>';
            } else {
                $link = '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>';
            }
            $is_buddy = in_array($row['id_member'], $user_info['buddies']);
            if ($is_buddy) {
                $link = '<strong>' . $link . '</strong>';
            }
            // Add them both to the list and to the more detailed list.
            if (!empty($row['show_online']) || allowedTo('moderate_forum')) {
                $context['view_members_list'][$row['log_time'] . $row['member_name']] = empty($row['show_online']) ? '<em>' . $link . '</em>' : $link;
            }
            $context['view_members'][$row['log_time'] . $row['member_name']] = array('id' => $row['id_member'], 'username' => $row['member_name'], 'name' => $row['real_name'], 'group' => $row['id_group'], 'href' => $scripturl . '?action=profile;u=' . $row['id_member'], 'link' => $link, 'is_buddy' => $is_buddy, 'hidden' => empty($row['show_online']));
            if (empty($row['show_online'])) {
                $context['view_num_hidden']++;
            }
        }
        // The number of guests is equal to the rows minus the ones we actually used ;).
        $context['view_num_guests'] = $smcFunc['db_num_rows']($request) - count($context['view_members']);
        $smcFunc['db_free_result']($request);
        // Sort the list.
        krsort($context['view_members']);
        krsort($context['view_members_list']);
    }
    // If all is set, but not allowed... just unset it.
    $can_show_all = !empty($modSettings['enableAllMessages']) && $context['total_visible_posts'] > $context['messages_per_page'] && $context['total_visible_posts'] < $modSettings['enableAllMessages'];
    if (isset($_REQUEST['all']) && !$can_show_all) {
        unset($_REQUEST['all']);
    } elseif (isset($_REQUEST['all'])) {
        $_REQUEST['start'] = -1;
    }
    // Construct the page index, allowing for the .START method...
    $context['page_index'] = constructPageIndex($scripturl . '?topic=' . $topic . '.%1$d', $_REQUEST['start'], $context['total_visible_posts'], $context['messages_per_page'], true);
    $context['start'] = $_REQUEST['start'];
    // This is information about which page is current, and which page we're on - in case you don't like the constructed page index. (again, wireles..)
    $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['messages_per_page'] + 1, 'num_pages' => floor(($context['total_visible_posts'] - 1) / $context['messages_per_page']) + 1);
    // Figure out all the link to the next/prev/first/last/etc. for wireless mainly.
    $context['links'] = array('first' => $_REQUEST['start'] >= $context['messages_per_page'] ? $scripturl . '?topic=' . $topic . '.0' : '', 'prev' => $_REQUEST['start'] >= $context['messages_per_page'] ? $scripturl . '?topic=' . $topic . '.' . ($_REQUEST['start'] - $context['messages_per_page']) : '', 'next' => $_REQUEST['start'] + $context['messages_per_page'] < $context['total_visible_posts'] ? $scripturl . '?topic=' . $topic . '.' . ($_REQUEST['start'] + $context['messages_per_page']) : '', 'last' => $_REQUEST['start'] + $context['messages_per_page'] < $context['total_visible_posts'] ? $scripturl . '?topic=' . $topic . '.' . floor($context['total_visible_posts'] / $context['messages_per_page']) * $context['messages_per_page'] : '', 'up' => $scripturl . '?board=' . $board . '.0');
    // If they are viewing all the posts, show all the posts, otherwise limit the number.
    if ($can_show_all) {
        if (isset($_REQUEST['all'])) {
            // No limit! (actually, there is a limit, but...)
            $context['messages_per_page'] = -1;
            $context['page_index'] .= empty($modSettings['compactTopicPagesEnable']) ? '<strong>' . $txt['all'] . '</strong> ' : '[<strong>' . $txt['all'] . '</strong>] ';
            // Set start back to 0...
            $_REQUEST['start'] = 0;
        } else {
            $context['page_index'] .= '&nbsp;<a href="' . $scripturl . '?topic=' . $topic . '.0;all">' . $txt['all'] . '</a> ';
        }
    }
    // Build the link tree.
    $context['linktree'][] = array('url' => $scripturl . '?topic=' . $topic . '.0', 'name' => $topicinfo['subject'], 'extra_before' => $settings['linktree_inline'] ? $txt['topic'] . ': ' : '');
    // Build a list of this board's moderators.
    $context['moderators'] =& $board_info['moderators'];
    $context['link_moderators'] = array();
    if (!empty($board_info['moderators'])) {
        // Add a link for each moderator...
        foreach ($board_info['moderators'] as $mod) {
            $context['link_moderators'][] = '<a href="' . $scripturl . '?action=profile;u=' . $mod['id'] . '" title="' . $txt['board_moderator'] . '">' . $mod['name'] . '</a>';
        }
        // And show it after the board's name.
        $context['linktree'][count($context['linktree']) - 2]['extra_after'] = ' (' . (count($context['link_moderators']) == 1 ? $txt['moderator'] : $txt['moderators']) . ': ' . implode(', ', $context['link_moderators']) . ')';
    }
    // Information about the current topic...
    $context['is_locked'] = $topicinfo['locked'];
    $context['is_sticky'] = $topicinfo['is_sticky'];
    $context['is_very_hot'] = $topicinfo['num_replies'] >= $modSettings['hotTopicVeryPosts'];
    $context['is_hot'] = $topicinfo['num_replies'] >= $modSettings['hotTopicPosts'];
    $context['is_approved'] = $topicinfo['approved'];
    // We don't want to show the poll icon in the topic class here, so pretend it's not one.
    $context['is_poll'] = false;
    determineTopicClass($context);
    $context['is_poll'] = $topicinfo['id_poll'] > 0 && $modSettings['pollMode'] == '1' && allowedTo('poll_view');
    // Did this user start the topic or not?
    $context['user']['started'] = $user_info['id'] == $topicinfo['id_member_started'] && !$user_info['is_guest'];
    $context['topic_starter_id'] = $topicinfo['id_member_started'];
    // Set the topic's information for the template.
    $context['subject'] = $topicinfo['subject'];
    $context['num_views'] = $topicinfo['num_views'];
    $context['mark_unread_time'] = $topicinfo['new_from'];
    // Set a canonical URL for this page.
    $context['canonical_url'] = $scripturl . '?topic=' . $topic . '.' . $context['start'];
    // For quick reply we need a response prefix in the default forum language.
    if (!isset($context['response_prefix']) && !($context['response_prefix'] = cache_get_data('response_prefix', 600))) {
        if ($language === $user_info['language']) {
            $context['response_prefix'] = $txt['response_prefix'];
        } else {
            loadLanguage('index', $language, false);
            $context['response_prefix'] = $txt['response_prefix'];
            loadLanguage('index');
        }
        cache_put_data('response_prefix', $context['response_prefix'], 600);
    }
    // If we want to show event information in the topic, prepare the data.
    if (allowedTo('calendar_view') && !empty($modSettings['cal_showInTopic']) && !empty($modSettings['cal_enabled'])) {
        // First, try create a better time format, ignoring the "time" elements.
        if (preg_match('~%[AaBbCcDdeGghjmuYy](?:[^%]*%[AaBbCcDdeGghjmuYy])*~', $user_info['time_format'], $matches) == 0 || empty($matches[0])) {
            $date_string = $user_info['time_format'];
        } else {
            $date_string = $matches[0];
        }
        // Any calendar information for this topic?
        $request = $smcFunc['db_query']('', '
			SELECT cal.id_event, cal.start_date, cal.end_date, cal.title, cal.id_member, mem.real_name
			FROM {db_prefix}calendar AS cal
				LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = cal.id_member)
			WHERE cal.id_topic = {int:current_topic}
			ORDER BY start_date', array('current_topic' => $topic));
        $context['linked_calendar_events'] = array();
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            // Prepare the dates for being formatted.
            $start_date = sscanf($row['start_date'], '%04d-%02d-%02d');
            $start_date = mktime(12, 0, 0, $start_date[1], $start_date[2], $start_date[0]);
            $end_date = sscanf($row['end_date'], '%04d-%02d-%02d');
            $end_date = mktime(12, 0, 0, $end_date[1], $end_date[2], $end_date[0]);
            $context['linked_calendar_events'][] = array('id' => $row['id_event'], 'title' => $row['title'], 'can_edit' => allowedTo('calendar_edit_any') || $row['id_member'] == $user_info['id'] && allowedTo('calendar_edit_own'), 'modify_href' => $scripturl . '?action=post;msg=' . $topicinfo['id_first_msg'] . ';topic=' . $topic . '.0;calendar;eventid=' . $row['id_event'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'start_date' => timeformat($start_date, $date_string, 'none'), 'start_timestamp' => $start_date, 'end_date' => timeformat($end_date, $date_string, 'none'), 'end_timestamp' => $end_date, 'is_last' => false);
        }
        $smcFunc['db_free_result']($request);
        if (!empty($context['linked_calendar_events'])) {
            $context['linked_calendar_events'][count($context['linked_calendar_events']) - 1]['is_last'] = true;
        }
    }
    // Create the poll info if it exists.
    if ($context['is_poll']) {
        // Get the question and if it's locked.
        $request = $smcFunc['db_query']('', '
			SELECT
				p.question, p.voting_locked, p.hide_results, p.expire_time, p.max_votes, p.change_vote,
				p.guest_vote, p.id_member, IFNULL(mem.real_name, p.poster_name) AS poster_name, p.num_guest_voters, p.reset_poll
			FROM {db_prefix}polls AS p
				LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = p.id_member)
			WHERE p.id_poll = {int:id_poll}
			LIMIT 1', array('id_poll' => $topicinfo['id_poll']));
        $pollinfo = $smcFunc['db_fetch_assoc']($request);
        $smcFunc['db_free_result']($request);
        $request = $smcFunc['db_query']('', '
			SELECT COUNT(DISTINCT id_member) AS total
			FROM {db_prefix}log_polls
			WHERE id_poll = {int:id_poll}
				AND id_member != {int:not_guest}', array('id_poll' => $topicinfo['id_poll'], 'not_guest' => 0));
        list($pollinfo['total']) = $smcFunc['db_fetch_row']($request);
        $smcFunc['db_free_result']($request);
        // Total voters needs to include guest voters
        $pollinfo['total'] += $pollinfo['num_guest_voters'];
        // Get all the options, and calculate the total votes.
        $request = $smcFunc['db_query']('', '
			SELECT pc.id_choice, pc.label, pc.votes, IFNULL(lp.id_choice, -1) AS voted_this
			FROM {db_prefix}poll_choices AS pc
				LEFT JOIN {db_prefix}log_polls AS lp ON (lp.id_choice = pc.id_choice AND lp.id_poll = {int:id_poll} AND lp.id_member = {int:current_member} AND lp.id_member != {int:not_guest})
			WHERE pc.id_poll = {int:id_poll}', array('current_member' => $user_info['id'], 'id_poll' => $topicinfo['id_poll'], 'not_guest' => 0));
        $pollOptions = array();
        $realtotal = 0;
        $pollinfo['has_voted'] = false;
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            censorText($row['label']);
            $pollOptions[$row['id_choice']] = $row;
            $realtotal += $row['votes'];
            $pollinfo['has_voted'] |= $row['voted_this'] != -1;
        }
        $smcFunc['db_free_result']($request);
        // If this is a guest we need to do our best to work out if they have voted, and what they voted for.
        if ($user_info['is_guest'] && $pollinfo['guest_vote'] && allowedTo('poll_vote')) {
            if (!empty($_COOKIE['guest_poll_vote']) && preg_match('~^[0-9,;]+$~', $_COOKIE['guest_poll_vote']) && strpos($_COOKIE['guest_poll_vote'], ';' . $topicinfo['id_poll'] . ',') !== false) {
                // ;id,timestamp,[vote,vote...]; etc
                $guestinfo = explode(';', $_COOKIE['guest_poll_vote']);
                // Find the poll we're after.
                foreach ($guestinfo as $i => $guestvoted) {
                    $guestvoted = explode(',', $guestvoted);
                    if ($guestvoted[0] == $topicinfo['id_poll']) {
                        break;
                    }
                }
                // Has the poll been reset since guest voted?
                if ($pollinfo['reset_poll'] > $guestvoted[1]) {
                    // Remove the poll info from the cookie to allow guest to vote again
                    unset($guestinfo[$i]);
                    if (!empty($guestinfo)) {
                        $_COOKIE['guest_poll_vote'] = ';' . implode(';', $guestinfo);
                    } else {
                        unset($_COOKIE['guest_poll_vote']);
                    }
                } else {
                    // What did they vote for?
                    unset($guestvoted[0], $guestvoted[1]);
                    foreach ($pollOptions as $choice => $details) {
                        $pollOptions[$choice]['voted_this'] = in_array($choice, $guestvoted) ? 1 : -1;
                        $pollinfo['has_voted'] |= $pollOptions[$choice]['voted_this'] != -1;
                    }
                    unset($choice, $details, $guestvoted);
                }
                unset($guestinfo, $guestvoted, $i);
            }
        }
        // Set up the basic poll information.
        $context['poll'] = array('id' => $topicinfo['id_poll'], 'image' => 'normal_' . (empty($pollinfo['voting_locked']) ? 'poll' : 'locked_poll'), 'question' => parse_bbc($pollinfo['question']), 'total_votes' => $pollinfo['total'], 'change_vote' => !empty($pollinfo['change_vote']), 'is_locked' => !empty($pollinfo['voting_locked']), 'options' => array(), 'lock' => allowedTo('poll_lock_any') || $context['user']['started'] && allowedTo('poll_lock_own'), 'edit' => allowedTo('poll_edit_any') || $context['user']['started'] && allowedTo('poll_edit_own'), 'allowed_warning' => $pollinfo['max_votes'] > 1 ? sprintf($txt['poll_options6'], min(count($pollOptions), $pollinfo['max_votes'])) : '', 'is_expired' => !empty($pollinfo['expire_time']) && $pollinfo['expire_time'] < time(), 'expire_time' => !empty($pollinfo['expire_time']) ? timeformat($pollinfo['expire_time']) : 0, 'has_voted' => !empty($pollinfo['has_voted']), 'starter' => array('id' => $pollinfo['id_member'], 'name' => $row['poster_name'], 'href' => $pollinfo['id_member'] == 0 ? '' : $scripturl . '?action=profile;u=' . $pollinfo['id_member'], 'link' => $pollinfo['id_member'] == 0 ? $row['poster_name'] : '<a href="' . $scripturl . '?action=profile;u=' . $pollinfo['id_member'] . '">' . $row['poster_name'] . '</a>'));
        // Make the lock and edit permissions defined above more directly accessible.
        $context['allow_lock_poll'] = $context['poll']['lock'];
        $context['allow_edit_poll'] = $context['poll']['edit'];
        // You're allowed to vote if:
        // 1. the poll did not expire, and
        // 2. you're either not a guest OR guest voting is enabled... and
        // 3. you're not trying to view the results, and
        // 4. the poll is not locked, and
        // 5. you have the proper permissions, and
        // 6. you haven't already voted before.
        $context['allow_vote'] = !$context['poll']['is_expired'] && (!$user_info['is_guest'] || $pollinfo['guest_vote'] && allowedTo('poll_vote')) && empty($pollinfo['voting_locked']) && allowedTo('poll_vote') && !$context['poll']['has_voted'];
        // You're allowed to view the results if:
        // 1. you're just a super-nice-guy, or
        // 2. anyone can see them (hide_results == 0), or
        // 3. you can see them after you voted (hide_results == 1), or
        // 4. you've waited long enough for the poll to expire. (whether hide_results is 1 or 2.)
        $context['allow_poll_view'] = allowedTo('moderate_board') || $pollinfo['hide_results'] == 0 || $pollinfo['hide_results'] == 1 && $context['poll']['has_voted'] || $context['poll']['is_expired'];
        $context['poll']['show_results'] = $context['allow_poll_view'] && (isset($_REQUEST['viewresults']) || isset($_REQUEST['viewResults']));
        $context['show_view_results_button'] = $context['allow_vote'] && (!$context['allow_poll_view'] || !$context['poll']['show_results'] || !$context['poll']['has_voted']);
        // You're allowed to change your vote if:
        // 1. the poll did not expire, and
        // 2. you're not a guest... and
        // 3. the poll is not locked, and
        // 4. you have the proper permissions, and
        // 5. you have already voted, and
        // 6. the poll creator has said you can!
        $context['allow_change_vote'] = !$context['poll']['is_expired'] && !$user_info['is_guest'] && empty($pollinfo['voting_locked']) && allowedTo('poll_vote') && $context['poll']['has_voted'] && $context['poll']['change_vote'];
        // You're allowed to return to voting options if:
        // 1. you are (still) allowed to vote.
        // 2. you are currently seeing the results.
        $context['allow_return_vote'] = $context['allow_vote'] && $context['poll']['show_results'];
        // Calculate the percentages and bar lengths...
        $divisor = $realtotal == 0 ? 1 : $realtotal;
        // Determine if a decimal point is needed in order for the options to add to 100%.
        $precision = $realtotal == 100 ? 0 : 1;
        // Now look through each option, and...
        foreach ($pollOptions as $i => $option) {
            // First calculate the percentage, and then the width of the bar...
            $bar = round($option['votes'] * 100 / $divisor, $precision);
            $barWide = $bar == 0 ? 1 : floor($bar * 8 / 3);
            // Now add it to the poll's contextual theme data.
            $context['poll']['options'][$i] = array('id' => 'options-' . $i, 'percent' => $bar, 'votes' => $option['votes'], 'voted_this' => $option['voted_this'] != -1, 'bar' => '<span style="white-space: nowrap;"><img src="' . $settings['images_url'] . '/poll_' . ($context['right_to_left'] ? 'right' : 'left') . '.gif" alt="" /><img src="' . $settings['images_url'] . '/poll_middle.gif" width="' . $barWide . '" height="12" alt="-" /><img src="' . $settings['images_url'] . '/poll_' . ($context['right_to_left'] ? 'left' : 'right') . '.gif" alt="" /></span>', 'bar_ndt' => $bar > 0 ? '<div class="bar" style="width: ' . ($bar * 3.5 + 4) . 'px;"><div style="width: ' . $bar * 3.5 . 'px;"></div></div>' : '', 'bar_width' => $barWide, 'option' => parse_bbc($option['label']), 'vote_button' => '<input type="' . ($pollinfo['max_votes'] > 1 ? 'checkbox' : 'radio') . '" name="options[]" id="options-' . $i . '" value="' . $i . '" class="input_' . ($pollinfo['max_votes'] > 1 ? 'check' : 'radio') . '" />');
        }
    }
    // Calculate the fastest way to get the messages!
    $ascending = empty($options['view_newest_first']);
    $start = $_REQUEST['start'];
    $limit = $context['messages_per_page'];
    $firstIndex = 0;
    if ($start >= $context['total_visible_posts'] / 2 && $context['messages_per_page'] != -1) {
        $ascending = !$ascending;
        $limit = $context['total_visible_posts'] <= $start + $limit ? $context['total_visible_posts'] - $start : $limit;
        $start = $context['total_visible_posts'] <= $start + $limit ? 0 : $context['total_visible_posts'] - $start - $limit;
        $firstIndex = $limit - 1;
    }
    // Get each post and poster in this topic.
    $request = $smcFunc['db_query']('display_get_post_poster', '
		SELECT id_msg, id_member, approved
		FROM {db_prefix}messages
		WHERE id_topic = {int:current_topic}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : (!empty($modSettings['db_mysql_group_by_fix']) ? '' : '
		GROUP BY id_msg') . '
		HAVING (approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR id_member = {int:current_member}') . ')') . '
		ORDER BY id_msg ' . ($ascending ? '' : 'DESC') . ($context['messages_per_page'] == -1 ? '' : '
		LIMIT ' . $start . ', ' . $limit), array('current_member' => $user_info['id'], 'current_topic' => $topic, 'is_approved' => 1, 'blank_id_member' => 0));
    $messages = array();
    $all_posters = array();
    while ($row = $smcFunc['db_fetch_assoc']($request)) {
        if (!empty($row['id_member'])) {
            $all_posters[$row['id_msg']] = $row['id_member'];
        }
        $messages[] = $row['id_msg'];
    }
    $smcFunc['db_free_result']($request);
    $posters = array_unique($all_posters);
    // Guests can't mark topics read or for notifications, just can't sorry.
    if (!$user_info['is_guest']) {
        $mark_at_msg = max($messages);
        if ($mark_at_msg >= $topicinfo['id_last_msg']) {
            $mark_at_msg = $modSettings['maxMsgID'];
        }
        if ($mark_at_msg >= $topicinfo['new_from']) {
            $smcFunc['db_insert']($topicinfo['new_from'] == 0 ? 'ignore' : 'replace', '{db_prefix}log_topics', array('id_member' => 'int', 'id_topic' => 'int', 'id_msg' => 'int'), array($user_info['id'], $topic, $mark_at_msg), array('id_member', 'id_topic'));
        }
        // Check for notifications on this topic OR board.
        $request = $smcFunc['db_query']('', '
			SELECT sent, id_topic
			FROM {db_prefix}log_notify
			WHERE (id_topic = {int:current_topic} OR id_board = {int:current_board})
				AND id_member = {int:current_member}
			LIMIT 2', array('current_board' => $board, 'current_member' => $user_info['id'], 'current_topic' => $topic));
        $do_once = true;
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            // Find if this topic is marked for notification...
            if (!empty($row['id_topic'])) {
                $context['is_marked_notify'] = true;
            }
            // Only do this once, but mark the notifications as "not sent yet" for next time.
            if (!empty($row['sent']) && $do_once) {
                $smcFunc['db_query']('', '
					UPDATE {db_prefix}log_notify
					SET sent = {int:is_not_sent}
					WHERE (id_topic = {int:current_topic} OR id_board = {int:current_board})
						AND id_member = {int:current_member}', array('current_board' => $board, 'current_member' => $user_info['id'], 'current_topic' => $topic, 'is_not_sent' => 0));
                $do_once = false;
            }
        }
        // Have we recently cached the number of new topics in this board, and it's still a lot?
        if (isset($_REQUEST['topicseen']) && isset($_SESSION['topicseen_cache'][$board]) && $_SESSION['topicseen_cache'][$board] > 5) {
            $_SESSION['topicseen_cache'][$board]--;
        } elseif (isset($_REQUEST['topicseen'])) {
            // Use the mark read tables... and the last visit to figure out if this should be read or not.
            $request = $smcFunc['db_query']('', '
				SELECT COUNT(*)
				FROM {db_prefix}topics AS t
					LEFT JOIN {db_prefix}log_boards AS lb ON (lb.id_board = {int:current_board} AND lb.id_member = {int:current_member})
					LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})
				WHERE t.id_board = {int:current_board}
					AND t.id_last_msg > IFNULL(lb.id_msg, 0)
					AND t.id_last_msg > IFNULL(lt.id_msg, 0)' . (empty($_SESSION['id_msg_last_visit']) ? '' : '
					AND t.id_last_msg > {int:id_msg_last_visit}'), array('current_board' => $board, 'current_member' => $user_info['id'], 'id_msg_last_visit' => (int) $_SESSION['id_msg_last_visit']));
            list($numNewTopics) = $smcFunc['db_fetch_row']($request);
            $smcFunc['db_free_result']($request);
            // If there're no real new topics in this board, mark the board as seen.
            if (empty($numNewTopics)) {
                $_REQUEST['boardseen'] = true;
            } else {
                $_SESSION['topicseen_cache'][$board] = $numNewTopics;
            }
        } elseif (isset($_SESSION['topicseen_cache'][$board])) {
            $_SESSION['topicseen_cache'][$board]--;
        }
        // Mark board as seen if we came using last post link from BoardIndex. (or other places...)
        if (isset($_REQUEST['boardseen'])) {
            $smcFunc['db_insert']('replace', '{db_prefix}log_boards', array('id_msg' => 'int', 'id_member' => 'int', 'id_board' => 'int'), array($modSettings['maxMsgID'], $user_info['id'], $board), array('id_member', 'id_board'));
        }
    }
    $attachments = array();
    // If there _are_ messages here... (probably an error otherwise :!)
    if (!empty($messages)) {
        // Fetch attachments.
        if (!empty($modSettings['attachmentEnable']) && allowedTo('view_attachments')) {
            $request = $smcFunc['db_query']('', '
				SELECT
					a.id_attach, a.id_folder, a.id_msg, a.filename, a.file_hash, IFNULL(a.size, 0) AS filesize, a.downloads, a.approved,
					a.width, a.height' . (empty($modSettings['attachmentShowImages']) || empty($modSettings['attachmentThumbnails']) ? '' : ',
					IFNULL(thumb.id_attach, 0) AS id_thumb, thumb.width AS thumb_width, thumb.height AS thumb_height') . '
				FROM {db_prefix}attachments AS a' . (empty($modSettings['attachmentShowImages']) || empty($modSettings['attachmentThumbnails']) ? '' : '
					LEFT JOIN {db_prefix}attachments AS thumb ON (thumb.id_attach = a.id_thumb)') . '
				WHERE a.id_msg IN ({array_int:message_list})
					AND a.attachment_type = {int:attachment_type}', array('message_list' => $messages, 'attachment_type' => 0, 'is_approved' => 1));
            $temp = array();
            while ($row = $smcFunc['db_fetch_assoc']($request)) {
                if (!$row['approved'] && $modSettings['postmod_active'] && !allowedTo('approve_posts') && (!isset($all_posters[$row['id_msg']]) || $all_posters[$row['id_msg']] != $user_info['id'])) {
                    continue;
                }
                $temp[$row['id_attach']] = $row;
                if (!isset($attachments[$row['id_msg']])) {
                    $attachments[$row['id_msg']] = array();
                }
            }
            $smcFunc['db_free_result']($request);
            // This is better than sorting it with the query...
            ksort($temp);
            foreach ($temp as $row) {
                $attachments[$row['id_msg']][] = $row;
            }
        }
        // What?  It's not like it *couldn't* be only guests in this topic...
        if (!empty($posters)) {
            loadMemberData($posters);
        }
        $messages_request = $smcFunc['db_query']('', '
			SELECT
				id_msg, icon, subject, poster_time, poster_ip, id_member, modified_time, modified_name, body,
				smileys_enabled, poster_name, poster_email, approved,
				id_msg_modified < {int:new_from} AS is_read
			FROM {db_prefix}messages
			WHERE id_msg IN ({array_int:message_list})
			ORDER BY id_msg' . (empty($options['view_newest_first']) ? '' : ' DESC'), array('message_list' => $messages, 'new_from' => $topicinfo['new_from']));
        // Go to the last message if the given time is beyond the time of the last message.
        if (isset($context['start_from']) && $context['start_from'] >= $topicinfo['num_replies']) {
            $context['start_from'] = $topicinfo['num_replies'];
        }
        // Since the anchor information is needed on the top of the page we load these variables beforehand.
        $context['first_message'] = isset($messages[$firstIndex]) ? $messages[$firstIndex] : $messages[0];
        if (empty($options['view_newest_first'])) {
            $context['first_new_message'] = isset($context['start_from']) && $_REQUEST['start'] == $context['start_from'];
        } else {
            $context['first_new_message'] = isset($context['start_from']) && $_REQUEST['start'] == $topicinfo['num_replies'] - $context['start_from'];
        }
    } else {
        $messages_request = false;
        $context['first_message'] = 0;
        $context['first_new_message'] = false;
    }
    $context['jump_to'] = array('label' => addslashes(un_htmlspecialchars($txt['jump_to'])), 'board_name' => htmlspecialchars(strtr(strip_tags($board_info['name']), array('&amp;' => '&'))), 'child_level' => $board_info['child_level']);
    // Set the callback.  (do you REALIZE how much memory all the messages would take?!?)
    $context['get_message'] = 'prepareDisplayContext';
    // Now set all the wonderful, wonderful permissions... like moderation ones...
    $common_permissions = array('can_approve' => 'approve_posts', 'can_ban' => 'manage_bans', 'can_sticky' => 'make_sticky', 'can_merge' => 'merge_any', 'can_split' => 'split_any', 'calendar_post' => 'calendar_post', 'can_mark_notify' => 'mark_any_notify', 'can_send_topic' => 'send_topic', 'can_send_pm' => 'pm_send', 'can_report_moderator' => 'report_any', 'can_moderate_forum' => 'moderate_forum', 'can_issue_warning' => 'issue_warning', 'can_restore_topic' => 'move_any', 'can_restore_msg' => 'move_any');
    foreach ($common_permissions as $contextual => $perm) {
        $context[$contextual] = allowedTo($perm);
    }
    // Permissions with _any/_own versions.  $context[YYY] => ZZZ_any/_own.
    $anyown_permissions = array('can_move' => 'move', 'can_lock' => 'lock', 'can_delete' => 'remove', 'can_add_poll' => 'poll_add', 'can_remove_poll' => 'poll_remove', 'can_reply' => 'post_reply', 'can_reply_unapproved' => 'post_unapproved_replies');
    foreach ($anyown_permissions as $contextual => $perm) {
        $context[$contextual] = allowedTo($perm . '_any') || $context['user']['started'] && allowedTo($perm . '_own');
    }
    // Cleanup all the permissions with extra stuff...
    $context['can_mark_notify'] &= !$context['user']['is_guest'];
    $context['can_sticky'] &= !empty($modSettings['enableStickyTopics']);
    $context['calendar_post'] &= !empty($modSettings['cal_enabled']);
    $context['can_add_poll'] &= $modSettings['pollMode'] == '1' && $topicinfo['id_poll'] <= 0;
    $context['can_remove_poll'] &= $modSettings['pollMode'] == '1' && $topicinfo['id_poll'] > 0;
    $context['can_reply'] &= empty($topicinfo['locked']) || allowedTo('moderate_board');
    $context['can_reply_unapproved'] &= $modSettings['postmod_active'] && (empty($topicinfo['locked']) || allowedTo('moderate_board'));
    $context['can_issue_warning'] &= in_array('w', $context['admin_features']) && $modSettings['warning_settings'][0] == 1;
    // Handle approval flags...
    $context['can_reply_approved'] = $context['can_reply'];
    $context['can_reply'] |= $context['can_reply_unapproved'];
    $context['can_quote'] = $context['can_reply'] && (empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC'])));
    $context['can_mark_unread'] = !$user_info['is_guest'] && $settings['show_mark_read'];
    $context['can_send_topic'] = (!$modSettings['postmod_active'] || $topicinfo['approved']) && allowedTo('send_topic');
    // Start this off for quick moderation - it will be or'd for each post.
    $context['can_remove_post'] = allowedTo('delete_any') || allowedTo('delete_replies') && $context['user']['started'];
    // Can restore topic?  That's if the topic is in the recycle board and has a previous restore state.
    $context['can_restore_topic'] &= !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board && !empty($topicinfo['id_previous_board']);
    $context['can_restore_msg'] &= !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board && !empty($topicinfo['id_previous_topic']);
    // Wireless shows a "more" if you can do anything special.
    if (WIRELESS && WIRELESS_PROTOCOL != 'wap') {
        $context['wireless_more'] = $context['can_sticky'] || $context['can_lock'] || allowedTo('modify_any');
        $context['wireless_moderate'] = isset($_GET['moderate']) ? ';moderate' : '';
    }
    // Load up the "double post" sequencing magic.
    if (!empty($options['display_quick_reply'])) {
        checkSubmitOnce('register');
        $context['name'] = isset($_SESSION['guest_name']) ? $_SESSION['guest_name'] : '';
        $context['email'] = isset($_SESSION['guest_email']) ? $_SESSION['guest_email'] : '';
    }
}
Esempio n. 2
0
function MessageIndex()
{
    global $txt, $scripturl, $board, $db_prefix;
    global $modSettings, $ID_MEMBER;
    global $context, $options, $settings, $board_info, $user_info, $func;
    if (WIRELESS) {
        $context['sub_template'] = WIRELESS_PROTOCOL . '_messageindex';
    } else {
        loadTemplate('MessageIndex');
    }
    $context['name'] = $board_info['name'];
    $context['description'] = $board_info['description'];
    // View all the topics, or just a few?
    $maxindex = isset($_REQUEST['all']) && !empty($modSettings['enableAllMessages']) ? $board_info['num_topics'] : $modSettings['defaultMaxTopics'];
    // Make sure the starting place makes sense and construct the page index.
    if (isset($_REQUEST['sort'])) {
        $context['page_index'] = constructPageIndex($scripturl . '?board=' . $board . '.%d;sort=' . $_REQUEST['sort'] . (isset($_REQUEST['desc']) ? ';desc' : ''), $_REQUEST['start'], $board_info['num_topics'], $maxindex, true);
    } else {
        $context['page_index'] = constructPageIndex($scripturl . '?board=' . $board . '.%d', $_REQUEST['start'], $board_info['num_topics'], $maxindex, true);
    }
    $context['start'] =& $_REQUEST['start'];
    $context['links'] = array('first' => $_REQUEST['start'] >= $modSettings['defaultMaxTopics'] ? $scripturl . '?board=' . $board . '.0' : '', 'prev' => $_REQUEST['start'] >= $modSettings['defaultMaxTopics'] ? $scripturl . '?board=' . $board . '.' . ($_REQUEST['start'] - $modSettings['defaultMaxTopics']) : '', 'next' => $_REQUEST['start'] + $modSettings['defaultMaxTopics'] < $board_info['num_topics'] ? $scripturl . '?board=' . $board . '.' . ($_REQUEST['start'] + $modSettings['defaultMaxTopics']) : '', 'last' => $_REQUEST['start'] + $modSettings['defaultMaxTopics'] < $board_info['num_topics'] ? $scripturl . '?board=' . $board . '.' . floor(($board_info['num_topics'] - 1) / $modSettings['defaultMaxTopics']) * $modSettings['defaultMaxTopics'] : '', 'up' => $board_info['parent'] == 0 ? $scripturl . '?' : $scripturl . '?board=' . $board_info['parent'] . '.0');
    $context['page_info'] = array('current_page' => $_REQUEST['start'] / $modSettings['defaultMaxTopics'] + 1, 'num_pages' => floor(($board_info['num_topics'] - 1) / $modSettings['defaultMaxTopics']) + 1);
    if (isset($_REQUEST['all']) && !empty($modSettings['enableAllMessages']) && $maxindex > $modSettings['enableAllMessages']) {
        $maxindex = $modSettings['enableAllMessages'];
        $_REQUEST['start'] = 0;
    }
    // Build a list of the board's moderators.
    $context['moderators'] =& $board_info['moderators'];
    $context['link_moderators'] = array();
    if (!empty($board_info['moderators'])) {
        foreach ($board_info['moderators'] as $mod) {
            $context['link_moderators'][] = '<a href="' . $scripturl . '?action=profile;u=' . $mod['id'] . '" title="' . $txt[62] . '">' . $mod['name'] . '</a>';
        }
        $context['linktree'][count($context['linktree']) - 1]['extra_after'] = ' (' . (count($context['link_moderators']) == 1 ? $txt[298] : $txt[299]) . ': ' . implode(', ', $context['link_moderators']) . ')';
    }
    // Mark current and parent boards as seen.
    if (!$user_info['is_guest']) {
        // We can't know they read it if we allow prefetches.
        if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') {
            ob_end_clean();
            header('HTTP/1.1 403 Prefetch Forbidden');
            die;
        }
        db_query("\n\t\t\tREPLACE INTO {$db_prefix}log_boards\n\t\t\t\t(ID_MSG, ID_MEMBER, ID_BOARD)\n\t\t\tVALUES ({$modSettings['maxMsgID']}, {$ID_MEMBER}, {$board})", __FILE__, __LINE__);
        if (!empty($board_info['parent_boards'])) {
            db_query("\n\t\t\t\tUPDATE {$db_prefix}log_boards\n\t\t\t\tSET ID_MSG = {$modSettings['maxMsgID']}\n\t\t\t\tWHERE ID_MEMBER = {$ID_MEMBER}\n\t\t\t\t\tAND ID_BOARD IN (" . implode(',', array_keys($board_info['parent_boards'])) . ")\n\t\t\t\tLIMIT " . count($board_info['parent_boards']), __FILE__, __LINE__);
            // We've seen all these boards now!
            foreach ($board_info['parent_boards'] as $k => $dummy) {
                if (isset($_SESSION['topicseen_cache'][$k])) {
                    unset($_SESSION['topicseen_cache'][$k]);
                }
            }
        }
        if (isset($_SESSION['topicseen_cache'][$board])) {
            unset($_SESSION['topicseen_cache'][$board]);
        }
        $request = db_query("\n\t\t\tSELECT sent\n\t\t\tFROM {$db_prefix}log_notify\n\t\t\tWHERE ID_BOARD = {$board}\n\t\t\t\tAND ID_MEMBER = {$ID_MEMBER}\n\t\t\tLIMIT 1", __FILE__, __LINE__);
        $context['is_marked_notify'] = mysql_num_rows($request) != 0;
        if ($context['is_marked_notify']) {
            list($sent) = mysql_fetch_row($request);
            if (!empty($sent)) {
                db_query("\n\t\t\t\t\tUPDATE {$db_prefix}log_notify\n\t\t\t\t\tSET sent = 0\n\t\t\t\t\tWHERE ID_BOARD = {$board}\n\t\t\t\t\t\tAND ID_MEMBER = {$ID_MEMBER}\n\t\t\t\t\tLIMIT 1", __FILE__, __LINE__);
            }
        }
        mysql_free_result($request);
    } else {
        $context['is_marked_notify'] = false;
    }
    // 'Print' the header and board info.
    $context['page_title'] = strip_tags($board_info['name']);
    // Set the variables up for the template.
    $context['can_mark_notify'] = allowedTo('mark_notify') && !$user_info['is_guest'];
    $context['can_post_new'] = allowedTo('post_new');
    $context['can_post_poll'] = $modSettings['pollMode'] == '1' && allowedTo('poll_post');
    $context['can_moderate_forum'] = allowedTo('moderate_forum');
    // Aren't children wonderful things?
    $result = db_query("\n\t\tSELECT\n\t\t\tb.ID_BOARD, b.name, b.description, b.numTopics, b.numPosts,\n\t\t\tm.posterName, m.posterTime, m.subject, m.ID_MSG, m.ID_TOPIC,\n\t\t\tIFNULL(mem.realName, m.posterName) AS realName, " . (!$user_info['is_guest'] ? "\n\t\t\t(IFNULL(lb.ID_MSG, 0) >= b.ID_MSG_UPDATED) AS isRead," : "1 AS isRead,") . "\n\t\t\tIFNULL(mem.ID_MEMBER, 0) AS ID_MEMBER, IFNULL(mem2.ID_MEMBER, 0) AS ID_MODERATOR,\n\t\t\tmem2.realName AS modRealName\n\t\tFROM {$db_prefix}boards AS b\n\t\t\tLEFT JOIN {$db_prefix}messages AS m ON (m.ID_MSG = b.ID_LAST_MSG)\n\t\t\tLEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = m.ID_MEMBER)" . (!$user_info['is_guest'] ? "\n\t\t\tLEFT JOIN {$db_prefix}log_boards AS lb ON (lb.ID_BOARD = b.ID_BOARD AND lb.ID_MEMBER = {$ID_MEMBER})" : '') . "\n\t\t\tLEFT JOIN {$db_prefix}moderators AS mods ON (mods.ID_BOARD = b.ID_BOARD)\n\t\t\tLEFT JOIN {$db_prefix}members AS mem2 ON (mem2.ID_MEMBER = mods.ID_MEMBER)\n\t\tWHERE b.ID_PARENT = {$board}\n\t\t\tAND {$user_info['query_see_board']}", __FILE__, __LINE__);
    if (mysql_num_rows($result) != 0) {
        $theboards = array();
        while ($row_board = mysql_fetch_assoc($result)) {
            if (!isset($context['boards'][$row_board['ID_BOARD']])) {
                $theboards[] = $row_board['ID_BOARD'];
                // Make sure the subject isn't too long.
                censorText($row_board['subject']);
                $short_subject = shorten_subject($row_board['subject'], 24);
                $context['boards'][$row_board['ID_BOARD']] = array('id' => $row_board['ID_BOARD'], 'last_post' => array('id' => $row_board['ID_MSG'], 'time' => $row_board['posterTime'] > 0 ? timeformat($row_board['posterTime']) : $txt[470], 'timestamp' => forum_time(true, $row_board['posterTime']), 'subject' => $short_subject, 'member' => array('id' => $row_board['ID_MEMBER'], 'username' => $row_board['posterName'] != '' ? $row_board['posterName'] : $txt[470], 'name' => $row_board['realName'], 'href' => !empty($row_board['ID_MEMBER']) ? $scripturl . '?action=profile;u=' . $row_board['ID_MEMBER'] : '', 'link' => $row_board['posterName'] != '' ? !empty($row_board['ID_MEMBER']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row_board['ID_MEMBER'] . '">' . $row_board['realName'] . '</a>' : $row_board['realName'] : $txt[470]), 'start' => 'new', 'topic' => $row_board['ID_TOPIC'], 'href' => $row_board['subject'] != '' ? $scripturl . '?topic=' . $row_board['ID_TOPIC'] . '.new' . (empty($row_board['isRead']) ? ';boardseen' : '') . '#new' : '', 'link' => $row_board['subject'] != '' ? '<a href="' . $scripturl . '?topic=' . $row_board['ID_TOPIC'] . '.new' . (empty($row_board['isRead']) ? ';boardseen' : '') . '#new" title="' . $row_board['subject'] . '">' . $short_subject . '</a>' : $txt[470]), 'new' => empty($row_board['isRead']) && $row_board['posterName'] != '', 'name' => $row_board['name'], 'description' => $row_board['description'], 'moderators' => array(), 'link_moderators' => array(), 'children' => array(), 'link_children' => array(), 'children_new' => false, 'topics' => $row_board['numTopics'], 'posts' => $row_board['numPosts'], 'href' => $scripturl . '?board=' . $row_board['ID_BOARD'] . '.0', 'link' => '<a href="' . $scripturl . '?board=' . $row_board['ID_BOARD'] . '.0">' . $row_board['name'] . '</a>');
            }
            if (!empty($row_board['ID_MODERATOR'])) {
                $context['boards'][$row_board['ID_BOARD']]['moderators'][$row_board['ID_MODERATOR']] = array('id' => $row_board['ID_MODERATOR'], 'name' => $row_board['modRealName'], 'href' => $scripturl . '?action=profile;u=' . $row_board['ID_MODERATOR'], 'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row_board['ID_MODERATOR'] . '" title="' . $txt[62] . '">' . $row_board['modRealName'] . '</a>');
                $context['boards'][$row_board['ID_BOARD']]['link_moderators'][] = '<a href="' . $scripturl . '?action=profile;u=' . $row_board['ID_MODERATOR'] . '" title="' . $txt[62] . '">' . $row_board['modRealName'] . '</a>';
            }
        }
        mysql_free_result($result);
        // Load up the child boards.
        $result = db_query("\n\t\t\tSELECT\n\t\t\t\tb.ID_BOARD, b.ID_PARENT, b.name, b.description, b.numTopics, b.numPosts,\n\t\t\t\tm.posterName, IFNULL(m.posterTime, 0) AS posterTime, m.subject, m.ID_MSG, m.ID_TOPIC,\n\t\t\t\tIFNULL(mem.realName, m.posterName) AS realName, ID_PARENT, \n\t\t\t\t" . ($user_info['is_guest'] ? '1' : '(IFNULL(lb.ID_MSG, 0) >= b.ID_MSG_UPDATED)') . " AS isRead,\n\t\t\t\tIFNULL(mem.ID_MEMBER, 0) AS ID_MEMBER\n\t\t\tFROM {$db_prefix}boards AS b\n\t\t\t\tLEFT JOIN {$db_prefix}messages AS m ON (m.ID_MSG = b.ID_LAST_MSG)\n\t\t\t\tLEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = m.ID_MEMBER)" . (!$user_info['is_guest'] ? "\n\t\t\t\tLEFT JOIN {$db_prefix}log_boards AS lb ON (lb.ID_BOARD = b.ID_BOARD AND lb.ID_MEMBER = {$ID_MEMBER})" : '') . "\n\t\t\tWHERE " . (empty($modSettings['countChildPosts']) ? "b.ID_PARENT IN (" . implode(',', $theboards) . ")" : "childLevel > 0") . "\n\t\t\t\tAND {$user_info['query_see_board']}", __FILE__, __LINE__);
        $parent_map = array();
        while ($row = mysql_fetch_assoc($result)) {
            // We've got a child of a child, then... possibly.
            if (!in_array($row['ID_PARENT'], $theboards)) {
                if (!isset($parent_map[$row['ID_PARENT']])) {
                    continue;
                }
                $parent_map[$row['ID_PARENT']][0]['posts'] += $row['numPosts'];
                $parent_map[$row['ID_PARENT']][0]['topics'] += $row['numTopics'];
                $parent_map[$row['ID_PARENT']][1]['posts'] += $row['numPosts'];
                $parent_map[$row['ID_PARENT']][1]['topics'] += $row['numTopics'];
                $parent_map[$row['ID_BOARD']] = $parent_map[$row['ID_PARENT']];
                continue;
            }
            if ($context['boards'][$row['ID_PARENT']]['last_post']['timestamp'] < forum_time(true, $row['posterTime'])) {
                // Make sure the subject isn't too long.
                censorText($row['subject']);
                $short_subject = shorten_subject($row['subject'], 24);
                $context['boards'][$row['ID_PARENT']]['last_post'] = array('id' => $row['ID_MSG'], 'time' => $row['posterTime'] > 0 ? timeformat($row['posterTime']) : $txt[470], 'timestamp' => forum_time(true, $row['posterTime']), 'subject' => $short_subject, 'member' => array('username' => $row['posterName'] != '' ? $row['posterName'] : $txt[470], 'name' => $row['realName'], 'id' => $row['ID_MEMBER'], 'href' => !empty($row['ID_MEMBER']) ? $scripturl . '?action=profile;u=' . $row['ID_MEMBER'] : '', 'link' => $row['posterName'] != '' ? !empty($row['ID_MEMBER']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['ID_MEMBER'] . '">' . $row['realName'] . '</a>' : $row['realName'] : $txt[470]), 'start' => 'new', 'topic' => $row['ID_TOPIC'], 'href' => $scripturl . '?topic=' . $row['ID_TOPIC'] . '.new' . (empty($row['isRead']) ? ';boardseen' : '') . '#new');
                $context['boards'][$row['ID_PARENT']]['last_post']['link'] = $row['subject'] != '' ? '<a href="' . $context['boards'][$row['ID_PARENT']]['last_post']['href'] . '" title="' . $row['subject'] . '">' . $short_subject . '</a>' : $txt[470];
            }
            $context['boards'][$row['ID_PARENT']]['children'][$row['ID_BOARD']] = array('id' => $row['ID_BOARD'], 'name' => $row['name'], 'description' => $row['description'], 'new' => empty($row['isRead']) && $row['posterName'] != '', 'topics' => $row['numTopics'], 'posts' => $row['numPosts'], 'href' => $scripturl . '?board=' . $row['ID_BOARD'] . '.0', 'link' => '<a href="' . $scripturl . '?board=' . $row['ID_BOARD'] . '.0">' . $row['name'] . '</a>');
            $context['boards'][$row['ID_PARENT']]['link_children'][] = '<a href="' . $scripturl . '?board=' . $row['ID_BOARD'] . '.0">' . $row['name'] . '</a>';
            $context['boards'][$row['ID_PARENT']]['children_new'] |= empty($row['isRead']) && $row['posterName'] != '';
            if (!empty($modSettings['countChildPosts'])) {
                $context['boards'][$row['ID_PARENT']]['posts'] += $row['numPosts'];
                $context['boards'][$row['ID_PARENT']]['topics'] += $row['numTopics'];
                $parent_map[$row['ID_BOARD']] = array(&$context['boards'][$row['ID_PARENT']], &$context['boards'][$row['ID_PARENT']]['children'][$row['ID_BOARD']]);
            }
        }
    }
    mysql_free_result($result);
    // Nosey, nosey - who's viewing this topic?
    if (!empty($settings['display_who_viewing'])) {
        $context['view_members'] = array();
        $context['view_members_list'] = array();
        $context['view_num_hidden'] = 0;
        $request = db_query("\n\t\t\tSELECT\n\t\t\t\tlo.ID_MEMBER, lo.logTime, mem.realName, mem.memberName, mem.showOnline,\n\t\t\t\tmg.onlineColor, mg.ID_GROUP, mg.groupName\n\t\t\tFROM {$db_prefix}log_online AS lo\n\t\t\t\tLEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = lo.ID_MEMBER)\n\t\t\t\tLEFT JOIN {$db_prefix}membergroups AS mg ON (mg.ID_GROUP = IF(mem.ID_GROUP = 0, mem.ID_POST_GROUP, mem.ID_GROUP))\n\t\t\tWHERE INSTR(lo.url, 's:5:\"board\";i:{$board};') OR lo.session = '" . ($user_info['is_guest'] ? 'ip' . $user_info['ip'] : session_id()) . "'", __FILE__, __LINE__);
        while ($row = mysql_fetch_assoc($request)) {
            if (empty($row['ID_MEMBER'])) {
                continue;
            }
            if (!empty($row['onlineColor'])) {
                $link = '<a href="' . $scripturl . '?action=profile;u=' . $row['ID_MEMBER'] . '" style="color: ' . $row['onlineColor'] . ';">' . $row['realName'] . '</a>';
            } else {
                $link = '<a href="' . $scripturl . '?action=profile;u=' . $row['ID_MEMBER'] . '">' . $row['realName'] . '</a>';
            }
            $is_buddy = in_array($row['ID_MEMBER'], $user_info['buddies']);
            if ($is_buddy) {
                $link = '<b>' . $link . '</b>';
            }
            if (!empty($row['showOnline']) || allowedTo('moderate_forum')) {
                $context['view_members_list'][$row['logTime'] . $row['memberName']] = empty($row['showOnline']) ? '<i>' . $link . '</i>' : $link;
            }
            $context['view_members'][$row['logTime'] . $row['memberName']] = array('id' => $row['ID_MEMBER'], 'username' => $row['memberName'], 'name' => $row['realName'], 'group' => $row['ID_GROUP'], 'href' => $scripturl . '?action=profile;u=' . $row['ID_MEMBER'], 'link' => $link, 'is_buddy' => $is_buddy, 'hidden' => empty($row['showOnline']));
            if (empty($row['showOnline'])) {
                $context['view_num_hidden']++;
            }
        }
        $context['view_num_guests'] = mysql_num_rows($request) - count($context['view_members']);
        mysql_free_result($request);
        // Put them in "last clicked" order.
        krsort($context['view_members_list']);
        krsort($context['view_members']);
    }
    // Default sort methods.
    $sort_methods = array('subject' => 'mf.subject', 'starter' => 'IFNULL(memf.realName, mf.posterName)', 'last_poster' => 'IFNULL(meml.realName, ml.posterName)', 'replies' => 't.numReplies', 'views' => 't.numViews', 'first_post' => 't.ID_TOPIC', 'last_post' => 't.ID_LAST_MSG');
    // They didn't pick one, default to by last post descending.
    if (!isset($_REQUEST['sort']) || !isset($sort_methods[$_REQUEST['sort']])) {
        $context['sort_by'] = 'last_post';
        $_REQUEST['sort'] = 'ID_LAST_MSG';
        $ascending = isset($_REQUEST['asc']);
    } else {
        $context['sort_by'] = $_REQUEST['sort'];
        $_REQUEST['sort'] = $sort_methods[$_REQUEST['sort']];
        $ascending = !isset($_REQUEST['desc']);
    }
    $context['sort_direction'] = $ascending ? 'up' : 'down';
    // Calculate the fastest way to get the topics.
    $start = $_REQUEST['start'];
    if ($start > ($board_info['num_topics'] - 1) / 2) {
        $ascending = !$ascending;
        $fake_ascending = true;
        $maxindex = $board_info['num_topics'] < $start + $maxindex + 1 ? $board_info['num_topics'] - $start : $maxindex;
        $start = $board_info['num_topics'] < $start + $maxindex + 1 ? 0 : $board_info['num_topics'] - $start - $maxindex;
    } else {
        $fake_ascending = false;
    }
    // Setup the default topic icons...
    $stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'moved', 'recycled', 'wireless');
    $context['icon_sources'] = array();
    foreach ($stable_icons as $icon) {
        $context['icon_sources'][$icon] = 'images_url';
    }
    $topic_ids = array();
    $context['topics'] = array();
    // Sequential pages are often not optimized, so we add an additional query.
    $pre_query = $start > 0;
    if ($pre_query) {
        $request = db_query("\n\t\t\tSELECT t.ID_TOPIC\n\t\t\tFROM ({$db_prefix}topics AS t" . ($context['sort_by'] === 'last_poster' ? ", {$db_prefix}messages AS ml" : (in_array($context['sort_by'], array('starter', 'subject')) ? ", {$db_prefix}messages AS mf" : '')) . ')' . ($context['sort_by'] === 'starter' ? "\n\t\t\t\tLEFT JOIN {$db_prefix}members AS memf ON (memf.ID_MEMBER = mf.ID_MEMBER)" : '') . ($context['sort_by'] === 'last_poster' ? "\n\t\t\t\tLEFT JOIN {$db_prefix}members AS meml ON (meml.ID_MEMBER = ml.ID_MEMBER)" : '') . "\n\t\t\tWHERE t.ID_BOARD = {$board}" . ($context['sort_by'] === 'last_poster' ? "\n\t\t\t\tAND ml.ID_MSG = t.ID_LAST_MSG" : (in_array($context['sort_by'], array('starter', 'subject')) ? "\n\t\t\t\tAND mf.ID_MSG = t.ID_FIRST_MSG" : '')) . "\n\t\t\tORDER BY " . (!empty($modSettings['enableStickyTopics']) ? 'isSticky' . ($fake_ascending ? '' : ' DESC') . ', ' : '') . $_REQUEST['sort'] . ($ascending ? '' : ' DESC') . "\n\t\t\tLIMIT {$start}, {$maxindex}", __FILE__, __LINE__);
        $topic_ids = array();
        while ($row = mysql_fetch_assoc($request)) {
            $topic_ids[] = $row['ID_TOPIC'];
        }
    }
    // Grab the appropriate topic information...
    if (!$pre_query || !empty($topic_ids)) {
        $result = db_query("\n\t\t\tSELECT\n\t\t\t\tt.ID_TOPIC, t.numReplies, t.locked, t.numViews, t.isSticky, t.ID_POLL,\n\t\t\t\t" . ($user_info['is_guest'] ? '0' : 'IFNULL(lt.ID_MSG, IFNULL(lmr.ID_MSG, -1)) + 1') . " AS new_from,\n\t\t\t\tt.ID_LAST_MSG, ml.posterTime AS lastPosterTime, ml.ID_MSG_MODIFIED,\n\t\t\t\tml.subject AS lastSubject, ml.icon AS lastIcon, ml.posterName AS lastMemberName,\n\t\t\t\tml.ID_MEMBER AS lastID_MEMBER, IFNULL(meml.realName, ml.posterName) AS lastDisplayName,\n\t\t\t\tt.ID_FIRST_MSG, mf.posterTime AS firstPosterTime,\n\t\t\t\tmf.subject AS firstSubject, mf.icon AS firstIcon, mf.posterName AS firstMemberName,\n\t\t\t\tmf.ID_MEMBER AS firstID_MEMBER, IFNULL(memf.realName, mf.posterName) AS firstDisplayName,\n\t\t\t\tLEFT(ml.body, 384) AS lastBody, LEFT(mf.body, 384) AS firstBody, ml.smileysEnabled AS lastSmileys,\n\t\t\t\tmf.smileysEnabled AS firstSmileys\n\t\t\tFROM ({$db_prefix}topics AS t, {$db_prefix}messages AS ml, {$db_prefix}messages AS mf)\n\t\t\t\tLEFT JOIN {$db_prefix}members AS meml ON (meml.ID_MEMBER = ml.ID_MEMBER)\n\t\t\t\tLEFT JOIN {$db_prefix}members AS memf ON (memf.ID_MEMBER = mf.ID_MEMBER)" . ($user_info['is_guest'] ? '' : "\n\t\t\t\tLEFT JOIN {$db_prefix}log_topics AS lt ON (lt.ID_TOPIC = t.ID_TOPIC AND lt.ID_MEMBER = {$ID_MEMBER})\n\t\t\t\tLEFT JOIN {$db_prefix}log_mark_read AS lmr ON (lmr.ID_BOARD = {$board} AND lmr.ID_MEMBER = {$ID_MEMBER})") . "\n\t\t\tWHERE " . ($pre_query ? 't.ID_TOPIC IN (' . implode(', ', $topic_ids) . ')' : "t.ID_BOARD = {$board}") . "\n\t\t\t\tAND ml.ID_MSG = t.ID_LAST_MSG\n\t\t\t\tAND mf.ID_MSG = t.ID_FIRST_MSG\n\t\t\tORDER BY " . ($pre_query ? "FIND_IN_SET(t.ID_TOPIC, '" . implode(',', $topic_ids) . "')" : (!empty($modSettings['enableStickyTopics']) ? 'isSticky' . ($fake_ascending ? '' : ' DESC') . ', ' : '') . $_REQUEST['sort'] . ($ascending ? '' : ' DESC')) . "\n\t\t\tLIMIT " . ($pre_query ? '' : "{$start}, ") . "{$maxindex}", __FILE__, __LINE__);
        // Begin 'printing' the message index for current board.
        while ($row = mysql_fetch_assoc($result)) {
            if ($row['ID_POLL'] > 0 && $modSettings['pollMode'] == '0') {
                continue;
            }
            if (!$pre_query) {
                $topic_ids[] = $row['ID_TOPIC'];
            }
            // Limit them to 128 characters - do this FIRST because it's a lot of wasted censoring otherwise.
            $row['firstBody'] = strip_tags(strtr(parse_bbc($row['firstBody'], $row['firstSmileys'], $row['ID_FIRST_MSG']), array('<br />' => '&#10;')));
            if ($func['strlen']($row['firstBody']) > 128) {
                $row['firstBody'] = $func['substr']($row['firstBody'], 0, 128) . '...';
            }
            $row['lastBody'] = strip_tags(strtr(parse_bbc($row['lastBody'], $row['lastSmileys'], $row['ID_LAST_MSG']), array('<br />' => '&#10;')));
            if ($func['strlen']($row['lastBody']) > 128) {
                $row['lastBody'] = $func['substr']($row['lastBody'], 0, 128) . '...';
            }
            // Censor the subject and message preview.
            censorText($row['firstSubject']);
            censorText($row['firstBody']);
            // Don't censor them twice!
            if ($row['ID_FIRST_MSG'] == $row['ID_LAST_MSG']) {
                $row['lastSubject'] = $row['firstSubject'];
                $row['lastBody'] = $row['firstBody'];
            } else {
                censorText($row['lastSubject']);
                censorText($row['lastBody']);
            }
            // Decide how many pages the topic should have.
            $topic_length = $row['numReplies'] + 1;
            if ($topic_length > $modSettings['defaultMaxMessages']) {
                $tmppages = array();
                $tmpa = 1;
                for ($tmpb = 0; $tmpb < $topic_length; $tmpb += $modSettings['defaultMaxMessages']) {
                    $tmppages[] = '<a href="' . $scripturl . '?topic=' . $row['ID_TOPIC'] . '.' . $tmpb . '">' . $tmpa . '</a>';
                    $tmpa++;
                }
                // Show links to all the pages?
                if (count($tmppages) <= 5) {
                    $pages = '&#171; ' . implode(' ', $tmppages);
                } else {
                    $pages = '&#171; ' . $tmppages[0] . ' ' . $tmppages[1] . ' ... ' . $tmppages[count($tmppages) - 2] . ' ' . $tmppages[count($tmppages) - 1];
                }
                if (!empty($modSettings['enableAllMessages']) && $topic_length < $modSettings['enableAllMessages']) {
                    $pages .= ' &nbsp;<a href="' . $scripturl . '?topic=' . $row['ID_TOPIC'] . '.0;all">' . $txt[190] . '</a>';
                }
                $pages .= ' &#187;';
            } else {
                $pages = '';
            }
            // We need to check the topic icons exist...
            if (empty($modSettings['messageIconChecks_disable'])) {
                if (!isset($context['icon_sources'][$row['firstIcon']])) {
                    $context['icon_sources'][$row['firstIcon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['firstIcon'] . '.gif') ? 'images_url' : 'default_images_url';
                }
                if (!isset($context['icon_sources'][$row['lastIcon']])) {
                    $context['icon_sources'][$row['lastIcon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['lastIcon'] . '.gif') ? 'images_url' : 'default_images_url';
                }
            } else {
                if (!isset($context['icon_sources'][$row['firstIcon']])) {
                    $context['icon_sources'][$row['firstIcon']] = 'images_url';
                }
                if (!isset($context['icon_sources'][$row['lastIcon']])) {
                    $context['icon_sources'][$row['lastIcon']] = 'images_url';
                }
            }
            // 'Print' the topic info.
            $context['topics'][$row['ID_TOPIC']] = array('id' => $row['ID_TOPIC'], 'first_post' => array('id' => $row['ID_FIRST_MSG'], 'member' => array('username' => $row['firstMemberName'], 'name' => $row['firstDisplayName'], 'id' => $row['firstID_MEMBER'], 'href' => !empty($row['firstID_MEMBER']) ? $scripturl . '?action=profile;u=' . $row['firstID_MEMBER'] : '', 'link' => !empty($row['firstID_MEMBER']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['firstID_MEMBER'] . '" title="' . $txt[92] . ' ' . $row['firstDisplayName'] . '">' . $row['firstDisplayName'] . '</a>' : $row['firstDisplayName']), 'time' => timeformat($row['firstPosterTime']), 'timestamp' => forum_time(true, $row['firstPosterTime']), 'subject' => $row['firstSubject'], 'preview' => $row['firstBody'], 'icon' => $row['firstIcon'], 'icon_url' => $settings[$context['icon_sources'][$row['firstIcon']]] . '/post/' . $row['firstIcon'] . '.gif', 'href' => $scripturl . '?topic=' . $row['ID_TOPIC'] . '.0', 'link' => '<a href="' . $scripturl . '?topic=' . $row['ID_TOPIC'] . '.0">' . $row['firstSubject'] . '</a>'), 'last_post' => array('id' => $row['ID_LAST_MSG'], 'member' => array('username' => $row['lastMemberName'], 'name' => $row['lastDisplayName'], 'id' => $row['lastID_MEMBER'], 'href' => !empty($row['lastID_MEMBER']) ? $scripturl . '?action=profile;u=' . $row['lastID_MEMBER'] : '', 'link' => !empty($row['lastID_MEMBER']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['lastID_MEMBER'] . '">' . $row['lastDisplayName'] . '</a>' : $row['lastDisplayName']), 'time' => timeformat($row['lastPosterTime']), 'timestamp' => forum_time(true, $row['lastPosterTime']), 'subject' => $row['lastSubject'], 'preview' => $row['lastBody'], 'icon' => $row['lastIcon'], 'icon_url' => $settings[$context['icon_sources'][$row['lastIcon']]] . '/post/' . $row['lastIcon'] . '.gif', 'href' => $scripturl . '?topic=' . $row['ID_TOPIC'] . ($row['numReplies'] == 0 ? '.0' : '.msg' . $row['ID_LAST_MSG']) . '#new', 'link' => '<a href="' . $scripturl . '?topic=' . $row['ID_TOPIC'] . ($row['numReplies'] == 0 ? '.0' : '.msg' . $row['ID_LAST_MSG']) . '#new">' . $row['lastSubject'] . '</a>'), 'tagCount' => 0, 'is_sticky' => !empty($modSettings['enableStickyTopics']) && !empty($row['isSticky']), 'is_locked' => !empty($row['locked']), 'is_poll' => $modSettings['pollMode'] == '1' && $row['ID_POLL'] > 0, 'is_hot' => $row['numReplies'] >= $modSettings['hotTopicPosts'], 'is_very_hot' => $row['numReplies'] >= $modSettings['hotTopicVeryPosts'], 'is_posted_in' => false, 'icon' => $row['firstIcon'], 'icon_url' => $settings[$context['icon_sources'][$row['firstIcon']]] . '/post/' . $row['firstIcon'] . '.gif', 'subject' => $row['firstSubject'], 'new' => $row['new_from'] <= $row['ID_MSG_MODIFIED'], 'new_from' => $row['new_from'], 'newtime' => $row['new_from'], 'new_href' => $scripturl . '?topic=' . $row['ID_TOPIC'] . '.msg' . $row['new_from'] . '#new', 'pages' => $pages, 'replies' => $row['numReplies'], 'views' => $row['numViews']);
            determineTopicClass($context['topics'][$row['ID_TOPIC']]);
        }
        mysql_free_result($result);
        // Tagging system
        if ($modSettings['smftags_set_display_messageindex'] && in_array($context['current_board'], explode(" ", $modSettings['smftags_set_taggable'])) && !empty($topic_ids)) {
            // this query is seperated due to lack of optimisation if integrated in to the main query above
            $result = db_query('
				SELECT ID_TOPIC, COUNT(ID_TAG) AS tagCount
				FROM smf_tags_log
				WHERE ID_TOPIC IN (' . implode(', ', $topic_ids) . ')
				GROUP BY ID_TOPIC
				', __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['topics'][$row['ID_TOPIC']]['tagCount'] = !empty($row['tagCount']) ? $row['tagCount'] : 0;
            }
            mysql_free_result($result);
        }
        // End tagging system
        // Fix the sequence of topics if they were retrieved in the wrong order. (for speed reasons...)
        if ($fake_ascending) {
            $context['topics'] = array_reverse($context['topics'], true);
        }
        if (!empty($modSettings['enableParticipation']) && !$user_info['is_guest'] && !empty($topic_ids)) {
            $result = db_query("\n\t\t\t\tSELECT ID_TOPIC\n\t\t\t\tFROM {$db_prefix}messages\n\t\t\t\tWHERE ID_TOPIC IN (" . implode(', ', $topic_ids) . ")\n\t\t\t\t\tAND ID_MEMBER = {$ID_MEMBER}\n\t\t\t\tGROUP BY ID_TOPIC\n\t\t\t\tLIMIT " . count($topic_ids), __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['topics'][$row['ID_TOPIC']]['is_posted_in'] = true;
                $context['topics'][$row['ID_TOPIC']]['class'] = 'my_' . $context['topics'][$row['ID_TOPIC']]['class'];
            }
            mysql_free_result($result);
        }
    }
    loadJumpTo();
    // Is Quick Moderation active?
    if (!empty($options['display_quick_mod'])) {
        $context['can_lock'] = allowedTo('lock_any');
        $context['can_sticky'] = allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']);
        $context['can_move'] = allowedTo('move_any');
        $context['can_remove'] = allowedTo('remove_any');
        $context['can_merge'] = allowedTo('merge_any');
        // Set permissions for all the topics.
        foreach ($context['topics'] as $t => $topic) {
            $started = $topic['first_post']['member']['id'] == $ID_MEMBER;
            $context['topics'][$t]['quick_mod'] = array('lock' => allowedTo('lock_any') || $started && allowedTo('lock_own'), 'sticky' => allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']), 'move' => allowedTo('move_any') || $started && allowedTo('move_own'), 'modify' => allowedTo('modify_any') || $started && allowedTo('modify_own'), 'remove' => allowedTo('remove_any') || $started && allowedTo('remove_own'));
            $context['can_lock'] |= $started && allowedTo('lock_own');
            $context['can_move'] |= $started && allowedTo('move_own');
            $context['can_remove'] |= $started && allowedTo('remove_own');
        }
        $board_count = 0;
        foreach ($context['jump_to'] as $id => $cat) {
            if (!empty($_SESSION['move_to_topic']) && isset($context['jump_to'][$id]['boards'][$_SESSION['move_to_topic']])) {
                $context['jump_to'][$id]['boards'][$_SESSION['move_to_topic']]['selected'] = true;
            }
            $board_count += count($context['jump_to'][$id]['boards']);
        }
        // You can only see just this one board?
        if ($board_count <= 1) {
            $context['can_move'] = false;
        }
    }
    // If there are children, but no topics and no ability to post topics...
    $context['no_topic_listing'] = !empty($context['boards']) && empty($context['topics']) && !$context['can_post_new'];
}
Esempio n. 3
0
/**
 * Show the list of topics in this board, along with any child boards.
 */
function MessageIndex()
{
    global $txt, $scripturl, $board, $modSettings, $context;
    global $options, $settings, $board_info, $user_info, $smcFunc, $sourcedir;
    // If this is a redirection board head off.
    if ($board_info['redirect']) {
        $smcFunc['db_query']('', '
			UPDATE {db_prefix}boards
			SET num_posts = num_posts + 1
			WHERE id_board = {int:current_board}', array('current_board' => $board));
        redirectexit($board_info['redirect']);
    }
    if (WIRELESS) {
        $context['sub_template'] = WIRELESS_PROTOCOL . '_messageindex';
    } else {
        loadTemplate('MessageIndex');
    }
    $context['name'] = $board_info['name'];
    $context['description'] = $board_info['description'];
    // How many topics do we have in total?
    $board_info['total_topics'] = allowedTo('approve_posts') ? $board_info['num_topics'] + $board_info['unapproved_topics'] : $board_info['num_topics'] + $board_info['unapproved_user_topics'];
    // View all the topics, or just a few?
    $context['topics_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['topics_per_page']) && !WIRELESS ? $options['topics_per_page'] : $modSettings['defaultMaxTopics'];
    $context['messages_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) && !WIRELESS ? $options['messages_per_page'] : $modSettings['defaultMaxMessages'];
    $maxindex = isset($_REQUEST['all']) && !empty($modSettings['enableAllMessages']) ? $board_info['total_topics'] : $context['topics_per_page'];
    // Right, let's only index normal stuff!
    if (count($_GET) > 1) {
        $session_name = session_name();
        foreach ($_GET as $k => $v) {
            if (!in_array($k, array('board', 'start', $session_name))) {
                $context['robot_no_index'] = true;
            }
        }
    }
    if (!empty($_REQUEST['start']) && (!is_numeric($_REQUEST['start']) || $_REQUEST['start'] % $context['messages_per_page'] != 0)) {
        $context['robot_no_index'] = true;
    }
    // If we can view unapproved messages and there are some build up a list.
    if (allowedTo('approve_posts') && ($board_info['unapproved_topics'] || $board_info['unapproved_posts'])) {
        $untopics = $board_info['unapproved_topics'] ? '<a href="' . $scripturl . '?action=moderate;area=postmod;sa=topics;brd=' . $board . '">' . $board_info['unapproved_topics'] . '</a>' : 0;
        $unposts = $board_info['unapproved_posts'] ? '<a href="' . $scripturl . '?action=moderate;area=postmod;sa=posts;brd=' . $board . '">' . ($board_info['unapproved_posts'] - $board_info['unapproved_topics']) . '</a>' : 0;
        $context['unapproved_posts_message'] = sprintf($txt['there_are_unapproved_topics'], $untopics, $unposts, $scripturl . '?action=moderate;area=postmod;sa=' . ($board_info['unapproved_topics'] ? 'topics' : 'posts') . ';brd=' . $board);
    }
    // Make sure the starting place makes sense and construct the page index.
    if (isset($_REQUEST['sort'])) {
        $context['page_index'] = constructPageIndex($scripturl . '?board=' . $board . '.%1$d;sort=' . $_REQUEST['sort'] . (isset($_REQUEST['desc']) ? ';desc' : ''), $_REQUEST['start'], $board_info['total_topics'], $maxindex, true);
    } else {
        $context['page_index'] = constructPageIndex($scripturl . '?board=' . $board . '.%1$d', $_REQUEST['start'], $board_info['total_topics'], $maxindex, true);
    }
    $context['start'] =& $_REQUEST['start'];
    // Set a canonical URL for this page.
    $context['canonical_url'] = $scripturl . '?board=' . $board . '.' . $context['start'];
    $context['links'] = array('first' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?board=' . $board . '.0' : '', 'prev' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?board=' . $board . '.' . ($_REQUEST['start'] - $context['topics_per_page']) : '', 'next' => $_REQUEST['start'] + $context['topics_per_page'] < $board_info['total_topics'] ? $scripturl . '?board=' . $board . '.' . ($_REQUEST['start'] + $context['topics_per_page']) : '', 'last' => $_REQUEST['start'] + $context['topics_per_page'] < $board_info['total_topics'] ? $scripturl . '?board=' . $board . '.' . floor(($board_info['total_topics'] - 1) / $context['topics_per_page']) * $context['topics_per_page'] : '', 'up' => $board_info['parent'] == 0 ? $scripturl . '?' : $scripturl . '?board=' . $board_info['parent'] . '.0');
    $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['topics_per_page'] + 1, 'num_pages' => floor(($board_info['total_topics'] - 1) / $context['topics_per_page']) + 1);
    if (isset($_REQUEST['all']) && !empty($modSettings['enableAllMessages']) && $maxindex > $modSettings['enableAllMessages']) {
        $maxindex = $modSettings['enableAllMessages'];
        $_REQUEST['start'] = 0;
    }
    // Build a list of the board's moderators.
    $context['moderators'] =& $board_info['moderators'];
    $context['link_moderators'] = array();
    if (!empty($board_info['moderators'])) {
        foreach ($board_info['moderators'] as $mod) {
            $context['link_moderators'][] = '<a href="' . $scripturl . '?action=profile;u=' . $mod['id'] . '" title="' . $txt['board_moderator'] . '">' . $mod['name'] . '</a>';
        }
        $context['linktree'][count($context['linktree']) - 1]['extra_after'] = '<span class="board_moderators"> (' . (count($context['link_moderators']) == 1 ? $txt['moderator'] : $txt['moderators']) . ': ' . implode(', ', $context['link_moderators']) . ')</span>';
    }
    // Mark current and parent boards as seen.
    if (!$user_info['is_guest']) {
        // We can't know they read it if we allow prefetches.
        if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') {
            ob_end_clean();
            header('HTTP/1.1 403 Prefetch Forbidden');
            die;
        }
        $smcFunc['db_insert']('replace', '{db_prefix}log_boards', array('id_msg' => 'int', 'id_member' => 'int', 'id_board' => 'int'), array($modSettings['maxMsgID'], $user_info['id'], $board), array('id_member', 'id_board'));
        if (!empty($board_info['parent_boards'])) {
            $smcFunc['db_query']('', '
				UPDATE {db_prefix}log_boards
				SET id_msg = {int:id_msg}
				WHERE id_member = {int:current_member}
					AND id_board IN ({array_int:board_list})', array('current_member' => $user_info['id'], 'board_list' => array_keys($board_info['parent_boards']), 'id_msg' => $modSettings['maxMsgID']));
            // We've seen all these boards now!
            foreach ($board_info['parent_boards'] as $k => $dummy) {
                if (isset($_SESSION['topicseen_cache'][$k])) {
                    unset($_SESSION['topicseen_cache'][$k]);
                }
            }
        }
        if (isset($_SESSION['topicseen_cache'][$board])) {
            unset($_SESSION['topicseen_cache'][$board]);
        }
        $request = $smcFunc['db_query']('', '
			SELECT sent
			FROM {db_prefix}log_notify
			WHERE id_board = {int:current_board}
				AND id_member = {int:current_member}
			LIMIT 1', array('current_board' => $board, 'current_member' => $user_info['id']));
        $context['is_marked_notify'] = $smcFunc['db_num_rows']($request) != 0;
        if ($context['is_marked_notify']) {
            list($sent) = $smcFunc['db_fetch_row']($request);
            if (!empty($sent)) {
                $smcFunc['db_query']('', '
					UPDATE {db_prefix}log_notify
					SET sent = {int:is_sent}
					WHERE id_board = {int:current_board}
						AND id_member = {int:current_member}', array('current_board' => $board, 'current_member' => $user_info['id'], 'is_sent' => 0));
            }
        }
        $smcFunc['db_free_result']($request);
    } else {
        $context['is_marked_notify'] = false;
    }
    // 'Print' the header and board info.
    $context['page_title'] = strip_tags($board_info['name']);
    // Set the variables up for the template.
    $context['can_mark_notify'] = allowedTo('mark_notify') && !$user_info['is_guest'];
    $context['can_post_new'] = allowedTo('post_new') || $modSettings['postmod_active'] && allowedTo('post_unapproved_topics');
    $context['can_post_poll'] = $modSettings['pollMode'] == '1' && allowedTo('poll_post') && $context['can_post_new'];
    $context['can_moderate_forum'] = allowedTo('moderate_forum');
    $context['can_approve_posts'] = allowedTo('approve_posts');
    require_once $sourcedir . '/Subs-BoardIndex.php';
    $boardIndexOptions = array('include_categories' => false, 'base_level' => $board_info['child_level'] + 1, 'parent_id' => $board_info['id'], 'set_latest_post' => false, 'countChildPosts' => !empty($modSettings['countChildPosts']));
    $context['boards'] = getBoardIndex($boardIndexOptions);
    // Nosey, nosey - who's viewing this topic?
    if (!empty($settings['display_who_viewing'])) {
        $context['view_members'] = array();
        $context['view_members_list'] = array();
        $context['view_num_hidden'] = 0;
        $request = $smcFunc['db_query']('', '
			SELECT
				lo.id_member, lo.log_time, mem.real_name, mem.member_name, mem.show_online,
				mg.online_color, mg.id_group, mg.group_name
			FROM {db_prefix}log_online AS lo
				LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lo.id_member)
				LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = CASE WHEN mem.id_group = {int:reg_member_group} THEN mem.id_post_group ELSE mem.id_group END)
			WHERE INSTR(lo.url, {string:in_url_string}) > 0 OR lo.session = {string:session}', array('reg_member_group' => 0, 'in_url_string' => 's:5:"board";i:' . $board . ';', 'session' => $user_info['is_guest'] ? 'ip' . $user_info['ip'] : session_id()));
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            if (empty($row['id_member'])) {
                continue;
            }
            if (!empty($row['online_color'])) {
                $link = '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '" style="color: ' . $row['online_color'] . ';">' . $row['real_name'] . '</a>';
            } else {
                $link = '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>';
            }
            $is_buddy = in_array($row['id_member'], $user_info['buddies']);
            if ($is_buddy) {
                $link = '<strong>' . $link . '</strong>';
            }
            if (!empty($row['show_online']) || allowedTo('moderate_forum')) {
                $context['view_members_list'][$row['log_time'] . $row['member_name']] = empty($row['show_online']) ? '<em>' . $link . '</em>' : $link;
            }
            $context['view_members'][$row['log_time'] . $row['member_name']] = array('id' => $row['id_member'], 'username' => $row['member_name'], 'name' => $row['real_name'], 'group' => $row['id_group'], 'href' => $scripturl . '?action=profile;u=' . $row['id_member'], 'link' => $link, 'is_buddy' => $is_buddy, 'hidden' => empty($row['show_online']));
            if (empty($row['show_online'])) {
                $context['view_num_hidden']++;
            }
        }
        $context['view_num_guests'] = $smcFunc['db_num_rows']($request) - count($context['view_members']);
        $smcFunc['db_free_result']($request);
        // Put them in "last clicked" order.
        krsort($context['view_members_list']);
        krsort($context['view_members']);
    }
    // Default sort methods.
    $sort_methods = array('subject' => 'mf.subject', 'starter' => 'IFNULL(memf.real_name, mf.poster_name)', 'last_poster' => 'IFNULL(meml.real_name, ml.poster_name)', 'replies' => 't.num_replies', 'views' => 't.num_views', 'first_post' => 't.id_topic', 'last_post' => 't.id_last_msg');
    // They didn't pick one, default to by last post descending.
    if (!isset($_REQUEST['sort']) || !isset($sort_methods[$_REQUEST['sort']])) {
        $context['sort_by'] = 'last_post';
        $_REQUEST['sort'] = 'id_last_msg';
        $ascending = isset($_REQUEST['asc']);
    } else {
        $context['sort_by'] = $_REQUEST['sort'];
        $_REQUEST['sort'] = $sort_methods[$_REQUEST['sort']];
        $ascending = !isset($_REQUEST['desc']);
    }
    $context['sort_direction'] = $ascending ? 'up' : 'down';
    // Calculate the fastest way to get the topics.
    $start = (int) $_REQUEST['start'];
    if ($start > ($board_info['total_topics'] - 1) / 2) {
        $ascending = !$ascending;
        $fake_ascending = true;
        $maxindex = $board_info['total_topics'] < $start + $maxindex + 1 ? $board_info['total_topics'] - $start : $maxindex;
        $start = $board_info['total_topics'] < $start + $maxindex + 1 ? 0 : $board_info['total_topics'] - $start - $maxindex;
    } else {
        $fake_ascending = false;
    }
    // Setup the default topic icons...
    $stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'poll', 'moved', 'recycled', 'wireless', 'clip');
    $context['icon_sources'] = array();
    foreach ($stable_icons as $icon) {
        $context['icon_sources'][$icon] = 'images_url';
    }
    $topic_ids = array();
    $context['topics'] = array();
    // Sequential pages are often not optimized, so we add an additional query.
    $pre_query = $start > 0;
    if ($pre_query && $maxindex > 0) {
        $request = $smcFunc['db_query']('', '
			SELECT t.id_topic
			FROM {db_prefix}topics AS t' . ($context['sort_by'] === 'last_poster' ? '
				INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)' : (in_array($context['sort_by'], array('starter', 'subject')) ? '
				INNER JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg)' : '')) . ($context['sort_by'] === 'starter' ? '
				LEFT JOIN {db_prefix}members AS memf ON (memf.id_member = mf.id_member)' : '') . ($context['sort_by'] === 'last_poster' ? '
				LEFT JOIN {db_prefix}members AS meml ON (meml.id_member = ml.id_member)' : '') . '
			WHERE t.id_board = {int:current_board}' . (!$modSettings['postmod_active'] || $context['can_approve_posts'] ? '' : '
				AND (t.approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR t.id_member_started = {int:current_member}') . ')') . '
			ORDER BY ' . (!empty($modSettings['enableStickyTopics']) ? 'is_sticky' . ($fake_ascending ? '' : ' DESC') . ', ' : '') . $_REQUEST['sort'] . ($ascending ? '' : ' DESC') . '
			LIMIT {int:start}, {int:maxindex}', array('current_board' => $board, 'current_member' => $user_info['id'], 'is_approved' => 1, 'id_member_guest' => 0, 'start' => $start, 'maxindex' => $maxindex));
        $topic_ids = array();
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            $topic_ids[] = $row['id_topic'];
        }
    }
    // Grab the appropriate topic information...
    if (!$pre_query || !empty($topic_ids)) {
        // For search engine effectiveness we'll link guests differently.
        $context['pageindex_multiplier'] = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) && !WIRELESS ? $options['messages_per_page'] : $modSettings['defaultMaxMessages'];
        $result = $smcFunc['db_query']('substring', '
			SELECT
				t.id_topic, t.num_replies, t.locked, t.num_views, t.is_sticky, t.id_poll, t.id_previous_board,
				' . ($user_info['is_guest'] ? '0' : 'IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1') . ' AS new_from,
				t.id_last_msg, t.approved, t.unapproved_posts, t.id_redirect_topic, ml.poster_time AS last_poster_time,
				ml.id_msg_modified, ml.subject AS last_subject, ml.icon AS last_icon,
				ml.poster_name AS last_member_name, ml.id_member AS last_id_member, ' . (!empty($settings['avatars_on_indexes']) ? 'meml.avatar,' : '') . '
				IFNULL(meml.real_name, ml.poster_name) AS last_display_name, t.id_first_msg,
				mf.poster_time AS first_poster_time, mf.subject AS first_subject, mf.icon AS first_icon,
				mf.poster_name AS first_member_name, mf.id_member AS first_id_member,
				IFNULL(memf.real_name, mf.poster_name) AS first_display_name, ' . (!empty($modSettings['preview_characters']) ? '
				SUBSTRING(ml.body, 1, ' . ($modSettings['preview_characters'] + 256) . ') AS last_body,
				SUBSTRING(mf.body, 1, ' . ($modSettings['preview_characters'] + 256) . ') AS first_body,' : '') . 'ml.smileys_enabled AS last_smileys, mf.smileys_enabled AS first_smileys' . (!empty($settings['avatars_on_indexes']) ? ',
				IFNULL(a.id_attach, 0) AS id_attach, a.filename, a.attachment_type' : '') . '
			FROM {db_prefix}topics AS t
				INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
				INNER JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg)
				LEFT JOIN {db_prefix}members AS meml ON (meml.id_member = ml.id_member)
				LEFT JOIN {db_prefix}members AS memf ON (memf.id_member = mf.id_member)' . ($user_info['is_guest'] ? '' : '
				LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})
				LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = {int:current_board} AND lmr.id_member = {int:current_member})') . (!empty($settings['avatars_on_indexes']) ? '
				LEFT JOIN {db_prefix}attachments AS a ON (a.id_member = ml.id_member)' : '') . '
			WHERE ' . ($pre_query ? 't.id_topic IN ({array_int:topic_list})' : 't.id_board = {int:current_board}') . (!$modSettings['postmod_active'] || $context['can_approve_posts'] ? '' : '
				AND (t.approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR t.id_member_started = {int:current_member}') . ')') . '
			ORDER BY ' . ($pre_query ? 'FIND_IN_SET(t.id_topic, {string:find_set_topics})' : (!empty($modSettings['enableStickyTopics']) ? 'is_sticky' . ($fake_ascending ? '' : ' DESC') . ', ' : '') . $_REQUEST['sort'] . ($ascending ? '' : ' DESC')) . '
			LIMIT ' . ($pre_query ? '' : '{int:start}, ') . '{int:maxindex}', array('current_board' => $board, 'current_member' => $user_info['id'], 'topic_list' => $topic_ids, 'is_approved' => 1, 'find_set_topics' => implode(',', $topic_ids), 'start' => $start, 'maxindex' => $maxindex));
        // Begin 'printing' the message index for current board.
        while ($row = $smcFunc['db_fetch_assoc']($result)) {
            if ($row['id_poll'] > 0 && $modSettings['pollMode'] == '0') {
                continue;
            }
            if (!$pre_query) {
                $topic_ids[] = $row['id_topic'];
            }
            // Does the theme support message previews?
            if (!empty($settings['message_index_preview']) && !empty($modSettings['preview_characters'])) {
                // Limit them to $modSettings['preview_characters'] characters
                $row['first_body'] = strip_tags(strtr(parse_bbc($row['first_body'], $row['first_smileys'], $row['id_first_msg']), array('<br />' => '&#10;')));
                if ($smcFunc['strlen']($row['first_body']) > $modSettings['preview_characters']) {
                    $row['first_body'] = $smcFunc['substr']($row['first_body'], 0, $modSettings['preview_characters']) . '...';
                }
                $row['last_body'] = strip_tags(strtr(parse_bbc($row['last_body'], $row['last_smileys'], $row['id_last_msg']), array('<br />' => '&#10;')));
                if ($smcFunc['strlen']($row['last_body']) > $modSettings['preview_characters']) {
                    $row['last_body'] = $smcFunc['substr']($row['last_body'], 0, $modSettings['preview_characters']) . '...';
                }
                // Censor the subject and message preview.
                censorText($row['first_subject']);
                censorText($row['first_body']);
                // Don't censor them twice!
                if ($row['id_first_msg'] == $row['id_last_msg']) {
                    $row['last_subject'] = $row['first_subject'];
                    $row['last_body'] = $row['first_body'];
                } else {
                    censorText($row['last_subject']);
                    censorText($row['last_body']);
                }
            } else {
                $row['first_body'] = '';
                $row['last_body'] = '';
                censorText($row['first_subject']);
                if ($row['id_first_msg'] == $row['id_last_msg']) {
                    $row['last_subject'] = $row['first_subject'];
                } else {
                    censorText($row['last_subject']);
                }
            }
            // Decide how many pages the topic should have.
            if ($row['num_replies'] + 1 > $context['messages_per_page']) {
                $pages = '&#171; ';
                // We can't pass start by reference.
                $start = -1;
                $pages .= constructPageIndex($scripturl . '?topic=' . $row['id_topic'] . '.%1$d', $start, $row['num_replies'] + 1, $context['messages_per_page'], true, false);
                // If we can use all, show all.
                if (!empty($modSettings['enableAllMessages']) && $row['num_replies'] + 1 < $modSettings['enableAllMessages']) {
                    $pages .= ' &nbsp;<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0;all">' . $txt['all'] . '</a>';
                }
                $pages .= ' &#187;';
            } else {
                $pages = '';
            }
            // We need to check the topic icons exist...
            if (!empty($modSettings['messageIconChecks_enable'])) {
                if (!isset($context['icon_sources'][$row['first_icon']])) {
                    $context['icon_sources'][$row['first_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['first_icon'] . '.png') ? 'images_url' : 'default_images_url';
                }
                if (!isset($context['icon_sources'][$row['last_icon']])) {
                    $context['icon_sources'][$row['last_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['last_icon'] . '.png') ? 'images_url' : 'default_images_url';
                }
            } else {
                if (!isset($context['icon_sources'][$row['first_icon']])) {
                    $context['icon_sources'][$row['first_icon']] = 'images_url';
                }
                if (!isset($context['icon_sources'][$row['last_icon']])) {
                    $context['icon_sources'][$row['last_icon']] = 'images_url';
                }
            }
            if (!empty($settings['avatars_on_indexes'])) {
                // Allow themers to show the latest poster's avatar along with the topic
                if (!empty($row['avatar'])) {
                    if ($modSettings['avatar_action_too_large'] == 'option_html_resize' || $modSettings['avatar_action_too_large'] == 'option_js_resize') {
                        $avatar_width = !empty($modSettings['avatar_max_width_external']) ? ' width="' . $modSettings['avatar_max_width_external'] . '"' : '';
                        $avatar_height = !empty($modSettings['avatar_max_height_external']) ? ' height="' . $modSettings['avatar_max_height_external'] . '"' : '';
                    } else {
                        $avatar_width = '';
                        $avatar_height = '';
                    }
                }
            }
            // 'Print' the topic info.
            $context['topics'][$row['id_topic']] = array('id' => $row['id_topic'], 'first_post' => array('id' => $row['id_first_msg'], 'member' => array('username' => $row['first_member_name'], 'name' => $row['first_display_name'], 'id' => $row['first_id_member'], 'href' => !empty($row['first_id_member']) ? $scripturl . '?action=profile;u=' . $row['first_id_member'] : '', 'link' => !empty($row['first_id_member']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['first_id_member'] . '" title="' . $txt['profile_of'] . ' ' . $row['first_display_name'] . '" class="preview">' . $row['first_display_name'] . '</a>' : $row['first_display_name']), 'time' => timeformat($row['first_poster_time']), 'timestamp' => forum_time(true, $row['first_poster_time']), 'subject' => $row['first_subject'], 'preview' => $row['first_body'], 'icon' => $row['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['first_icon']]] . '/post/' . $row['first_icon'] . '.png', 'href' => $scripturl . '?topic=' . (empty($row['id_redirect_topic']) ? $row['id_topic'] : $row['id_redirect_topic']) . '.0', 'link' => '<a href="' . $scripturl . '?topic=' . (empty($row['id_redirect_topic']) ? $row['id_topic'] : $row['id_redirect_topic']) . '.0">' . $row['first_subject'] . '</a>'), 'last_post' => array('id' => $row['id_last_msg'], 'member' => array('username' => $row['last_member_name'], 'name' => $row['last_display_name'], 'id' => $row['last_id_member'], 'href' => !empty($row['last_id_member']) ? $scripturl . '?action=profile;u=' . $row['last_id_member'] : '', 'link' => !empty($row['last_id_member']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['last_id_member'] . '">' . $row['last_display_name'] . '</a>' : $row['last_display_name']), 'time' => timeformat($row['last_poster_time']), 'timestamp' => forum_time(true, $row['last_poster_time']), 'subject' => $row['last_subject'], 'preview' => $row['last_body'], 'icon' => $row['last_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['last_icon']]] . '/post/' . $row['last_icon'] . '.png', 'href' => $scripturl . '?topic=' . (empty($row['id_redirect_topic']) ? $row['id_topic'] : $row['id_redirect_topic']) . ($user_info['is_guest'] ? '.' . (!empty($options['view_newest_first']) ? 0 : (int) ($row['num_replies'] / $context['pageindex_multiplier']) * $context['pageindex_multiplier']) . '#msg' . $row['id_last_msg'] : ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['id_last_msg']) . '#new'), 'link' => '<a href="' . $scripturl . '?topic=' . (empty($row['id_redirect_topic']) ? $row['id_topic'] : $row['id_redirect_topic']) . ($user_info['is_guest'] ? '.' . (!empty($options['view_newest_first']) ? 0 : (int) ($row['num_replies'] / $context['pageindex_multiplier']) * $context['pageindex_multiplier']) . '#msg' . $row['id_last_msg'] : ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['id_last_msg']) . '#new') . '" ' . ($row['num_replies'] == 0 ? '' : 'rel="nofollow"') . '>' . $row['last_subject'] . '</a>'), 'is_sticky' => !empty($modSettings['enableStickyTopics']) && !empty($row['is_sticky']), 'is_locked' => !empty($row['locked']), 'is_poll' => $modSettings['pollMode'] == '1' && $row['id_poll'] > 0, 'is_hot' => $row['num_replies'] >= $modSettings['hotTopicPosts'], 'is_very_hot' => $row['num_replies'] >= $modSettings['hotTopicVeryPosts'], 'is_posted_in' => false, 'icon' => $row['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['first_icon']]] . '/post/' . $row['first_icon'] . '.png', 'subject' => $row['first_subject'], 'new' => $row['new_from'] <= $row['id_msg_modified'], 'new_from' => $row['new_from'], 'newtime' => $row['new_from'], 'new_href' => $scripturl . '?topic=' . (empty($row['id_redirect_topic']) ? $row['id_topic'] : $row['id_redirect_topic']) . '.msg' . $row['new_from'] . '#new', 'pages' => $pages, 'replies' => comma_format($row['num_replies']), 'views' => comma_format($row['num_views']), 'approved' => $row['approved'], 'unapproved_posts' => $row['unapproved_posts']);
            if (!empty($settings['avatars_on_indexes'])) {
                $context['topics'][$row['id_topic']]['last_post']['member']['avatar'] = array('name' => $row['avatar'], 'image' => $row['avatar'] == '' ? $row['id_attach'] > 0 ? '<img class="avatar" src="' . (empty($row['attachment_type']) ? $scripturl . '?action=dlattach;attach=' . $row['id_attach'] . ';type=avatar' : $modSettings['custom_avatar_url'] . '/' . $row['filename']) . '" alt="" />' : '' : (stristr($row['avatar'], 'http://') ? '<img class="avatar" src="' . $row['avatar'] . '"' . $avatar_width . $avatar_height . ' alt="" />' : '<img class="avatar" src="' . $modSettings['avatar_url'] . '/' . htmlspecialchars($row['avatar']) . '" alt="" />'), 'href' => $row['avatar'] == '' ? $row['id_attach'] > 0 ? empty($row['attachment_type']) ? $scripturl . '?action=dlattach;attach=' . $row['id_attach'] . ';type=avatar' : $modSettings['custom_avatar_url'] . '/' . $row['filename'] : '' : (stristr($row['avatar'], 'http://') ? $row['avatar'] : $modSettings['avatar_url'] . '/' . $row['avatar']), 'url' => $row['avatar'] == '' ? '' : (stristr($row['avatar'], 'http://') ? $row['avatar'] : $modSettings['avatar_url'] . '/' . $row['avatar']));
            }
            determineTopicClass($context['topics'][$row['id_topic']]);
        }
        $smcFunc['db_free_result']($result);
        // Fix the sequence of topics if they were retrieved in the wrong order. (for speed reasons...)
        if ($fake_ascending) {
            $context['topics'] = array_reverse($context['topics'], true);
        }
        if (!empty($modSettings['enableParticipation']) && !$user_info['is_guest'] && !empty($topic_ids)) {
            $result = $smcFunc['db_query']('', '
				SELECT id_topic
				FROM {db_prefix}messages
				WHERE id_topic IN ({array_int:topic_list})
					AND id_member = {int:current_member}
				GROUP BY id_topic
				LIMIT ' . count($topic_ids), array('current_member' => $user_info['id'], 'topic_list' => $topic_ids));
            while ($row = $smcFunc['db_fetch_assoc']($result)) {
                $context['topics'][$row['id_topic']]['is_posted_in'] = true;
                $context['topics'][$row['id_topic']]['class'] = 'my_' . $context['topics'][$row['id_topic']]['class'];
            }
            $smcFunc['db_free_result']($result);
        }
    }
    $context['jump_to'] = array('label' => addslashes(un_htmlspecialchars($txt['jump_to'])), 'board_name' => htmlspecialchars(strtr(strip_tags($board_info['name']), array('&amp;' => '&'))), 'child_level' => $board_info['child_level']);
    // Is Quick Moderation active/needed?
    if (!empty($options['display_quick_mod']) && !empty($context['topics'])) {
        $context['can_markread'] = $context['user']['is_logged'];
        $context['can_lock'] = allowedTo('lock_any');
        $context['can_sticky'] = allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']);
        $context['can_move'] = allowedTo('move_any');
        $context['can_remove'] = allowedTo('remove_any');
        $context['can_merge'] = allowedTo('merge_any');
        // Ignore approving own topics as it's unlikely to come up...
        $context['can_approve'] = $modSettings['postmod_active'] && allowedTo('approve_posts') && !empty($board_info['unapproved_topics']);
        // Can we restore topics?
        $context['can_restore'] = allowedTo('move_any') && !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board;
        // Set permissions for all the topics.
        foreach ($context['topics'] as $t => $topic) {
            $started = $topic['first_post']['member']['id'] == $user_info['id'];
            $context['topics'][$t]['quick_mod'] = array('lock' => allowedTo('lock_any') || $started && allowedTo('lock_own'), 'sticky' => allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']), 'move' => allowedTo('move_any') || $started && allowedTo('move_own'), 'modify' => allowedTo('modify_any') || $started && allowedTo('modify_own'), 'remove' => allowedTo('remove_any') || $started && allowedTo('remove_own'), 'approve' => $context['can_approve'] && $topic['unapproved_posts']);
            $context['can_lock'] |= $started && allowedTo('lock_own');
            $context['can_move'] |= $started && allowedTo('move_own');
            $context['can_remove'] |= $started && allowedTo('remove_own');
        }
        // Find the boards/cateogories they can move their topic to.
        if ($options['display_quick_mod'] == 1 && $context['can_move'] && !empty($context['topics'])) {
            require_once $sourcedir . '/Subs-MessageIndex.php';
            $boardListOptions = array('excluded_boards' => array($board), 'not_redirection' => true, 'use_permissions' => true, 'selected_board' => empty($_SESSION['move_to_topic']) ? null : $_SESSION['move_to_topic']);
            // With no other boards to see, it's useless to move.
            if (empty($context['move_to_boards'])) {
                $context['can_move'] = false;
            }
        }
        // Can we use quick moderation checkboxes?
        if ($options['display_quick_mod'] == 1) {
            $context['can_quick_mod'] = $context['user']['is_logged'] || $context['can_approve'] || $context['can_remove'] || $context['can_lock'] || $context['can_sticky'] || $context['can_move'] || $context['can_merge'] || $context['can_restore'];
        } else {
            $context['can_quick_mod'] = $context['can_remove'] || $context['can_lock'] || $context['can_sticky'] || $context['can_move'];
        }
    }
    if (!empty($context['can_quick_mod']) && $options['display_quick_mod'] == 1) {
        $context['qmod_actions'] = array('approve', 'remove', 'lock', 'sticky', 'move', 'merge', 'restore', 'markread');
        call_integration_hook('integrate_quick_mod_actions');
    }
    // If there are children, but no topics and no ability to post topics...
    $context['no_topic_listing'] = !empty($context['boards']) && empty($context['topics']) && !$context['can_post_new'];
    // Build the message index button array.
    $context['normal_buttons'] = array('new_topic' => array('test' => 'can_post_new', 'text' => 'new_topic', 'image' => 'new_topic.png', 'lang' => true, 'url' => $scripturl . '?action=post;board=' . $context['current_board'] . '.0', 'active' => true), 'post_poll' => array('test' => 'can_post_poll', 'text' => 'new_poll', 'image' => 'new_poll.png', 'lang' => true, 'url' => $scripturl . '?action=post;board=' . $context['current_board'] . '.0;poll'), 'notify' => array('test' => 'can_mark_notify', 'text' => $context['is_marked_notify'] ? 'unnotify' : 'notify', 'image' => ($context['is_marked_notify'] ? 'un' : '') . 'notify.png', 'lang' => true, 'custom' => 'onclick="return confirm(\'' . ($context['is_marked_notify'] ? $txt['notification_disable_board'] : $txt['notification_enable_board']) . '\');"', 'url' => $scripturl . '?action=notifyboard;sa=' . ($context['is_marked_notify'] ? 'off' : 'on') . ';board=' . $context['current_board'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'markread' => array('text' => 'mark_read_short', 'image' => 'markread.png', 'lang' => true, 'url' => $scripturl . '?action=markasread;sa=board;board=' . $context['current_board'] . '.0;' . $context['session_var'] . '=' . $context['session_id']));
    // Allow adding new buttons easily.
    call_integration_hook('integrate_messageindex_buttons');
}
Esempio n. 4
0
function UnreadTopics()
{
    global $board, $txt, $scripturl, $db_prefix, $sourcedir;
    global $ID_MEMBER, $user_info, $context, $settings, $modSettings, $func;
    // Guests can't have unread things, we don't know anything about them.
    is_not_guest();
    // Prefetching + lots of MySQL work = bad mojo.
    if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') {
        ob_end_clean();
        header('HTTP/1.1 403 Forbidden');
        die;
    }
    $context['showing_all_topics'] = isset($_GET['all']);
    if ($_REQUEST['action'] == 'unread') {
        $context['page_title'] = $context['showing_all_topics'] ? $txt['unread_topics_all'] : $txt['unread_topics_visit'];
    } else {
        $context['page_title'] = $txt['unread_replies'];
    }
    if ($context['showing_all_topics'] && !empty($context['load_average']) && !empty($modSettings['loadavg_allunread']) && $context['load_average'] >= $modSettings['loadavg_allunread']) {
        fatal_lang_error('loadavg_allunread_disabled', false);
    } elseif ($_REQUEST['action'] != 'unread' && !empty($context['load_average']) && !empty($modSettings['loadavg_unreadreplies']) && $context['load_average'] >= $modSettings['loadavg_unreadreplies']) {
        fatal_lang_error('loadavg_unreadreplies_disabled', false);
    }
    // Are we specifying any specific board?
    if (!empty($board)) {
        $query_this_board = 'ID_BOARD = ' . $board;
        $context['querystring_board_limits'] = ';board=' . $board . '.%d';
    } elseif (!empty($_REQUEST['boards'])) {
        $_REQUEST['boards'] = explode(',', $_REQUEST['boards']);
        foreach ($_REQUEST['boards'] as $i => $b) {
            $_REQUEST['boards'][$i] = (int) $b;
        }
        $request = db_query("\n\t\t\tSELECT b.ID_BOARD\n\t\t\tFROM {$db_prefix}boards AS b\n\t\t\tWHERE {$user_info['query_see_board']}\n\t\t\t\tAND b.ID_BOARD IN (" . implode(', ', $_REQUEST['boards']) . ")", __FILE__, __LINE__);
        $boards = array();
        while ($row = mysql_fetch_assoc($request)) {
            $boards[] = $row['ID_BOARD'];
        }
        mysql_free_result($request);
        if (empty($boards)) {
            fatal_lang_error('error_no_boards_selected');
        }
        $query_this_board = 'ID_BOARD IN (' . implode(', ', $boards) . ')';
        $context['querystring_board_limits'] = ';boards=' . implode(',', $boards) . ';start=%d';
    } elseif (!empty($_REQUEST['c'])) {
        $_REQUEST['c'] = explode(',', $_REQUEST['c']);
        foreach ($_REQUEST['c'] as $i => $c) {
            $_REQUEST['c'][$i] = (int) $c;
        }
        $request = db_query("\n\t\t\tSELECT b.ID_BOARD\n\t\t\tFROM {$db_prefix}boards AS b\n\t\t\tWHERE {$user_info['query_see_board']}\n\t\t\t\tAND b.ID_CAT IN (" . implode(', ', $_REQUEST['c']) . ")", __FILE__, __LINE__);
        $boards = array();
        while ($row = mysql_fetch_assoc($request)) {
            $boards[] = $row['ID_BOARD'];
        }
        mysql_free_result($request);
        if (empty($boards)) {
            fatal_lang_error('error_no_boards_selected');
        }
        $query_this_board = 'ID_BOARD IN (' . implode(', ', $boards) . ')';
        $context['querystring_board_limits'] = ';c=' . implode(',', $_REQUEST['c']) . ';start=%d';
    } else {
        // Don't bother to show deleted posts!
        $request = db_query("\n\t\t\tSELECT b.ID_BOARD\n\t\t\tFROM {$db_prefix}boards AS b\n\t\t\tWHERE {$user_info['query_see_board']}" . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? "\n\t\t\t\tAND b.ID_BOARD != " . (int) $modSettings['recycle_board'] : ''), __FILE__, __LINE__);
        $boards = array();
        while ($row = mysql_fetch_assoc($request)) {
            $boards[] = $row['ID_BOARD'];
        }
        mysql_free_result($request);
        if (empty($boards)) {
            fatal_lang_error('error_no_boards_selected');
        }
        $query_this_board = 'ID_BOARD IN (' . implode(', ', $boards) . ')';
        $context['querystring_board_limits'] = ';start=%d';
        $context['no_board_limits'] = true;
    }
    $sort_methods = array('subject' => 'ms.subject', 'starter' => 'IFNULL(mems.realName, ms.posterName)', 'replies' => 't.numReplies', 'views' => 't.numViews', 'first_post' => 't.ID_TOPIC', 'last_post' => 't.ID_LAST_MSG');
    // The default is the most logical: newest first.
    if (!isset($_REQUEST['sort']) || !isset($sort_methods[$_REQUEST['sort']])) {
        $context['sort_by'] = 'last_post';
        $_REQUEST['sort'] = 't.ID_LAST_MSG';
        $ascending = isset($_REQUEST['asc']);
        $context['querystring_sort_limits'] = $ascending ? ';asc' : '';
    } else {
        $context['sort_by'] = $_REQUEST['sort'];
        $_REQUEST['sort'] = $sort_methods[$_REQUEST['sort']];
        $ascending = !isset($_REQUEST['desc']);
        $context['querystring_sort_limits'] = ';sort=' . $context['sort_by'] . ($ascending ? '' : ';desc');
    }
    $context['sort_direction'] = $ascending ? 'up' : 'down';
    if (!empty($_REQUEST['c']) && is_array($_REQUEST['c']) && count($_REQUEST['c']) == 1) {
        $request = db_query("\n\t\t\tSELECT name\n\t\t\tFROM {$db_prefix}categories\n\t\t\tWHERE ID_CAT = " . (int) $_REQUEST['c'][0] . "\n\t\t\tLIMIT 1", __FILE__, __LINE__);
        list($name) = mysql_fetch_row($request);
        mysql_free_result($request);
        $context['linktree'][] = array('url' => $scripturl . '#' . (int) $_REQUEST['c'][0], 'name' => $name);
    }
    $context['linktree'][] = array('url' => $scripturl . '?action=' . $_REQUEST['action'] . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits'], 'name' => $_REQUEST['action'] == 'unread' ? $txt['unread_topics_visit'] : $txt['unread_replies']);
    if ($context['showing_all_topics']) {
        $context['linktree'][] = array('url' => $scripturl . '?action=' . $_REQUEST['action'] . ';all' . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits'], 'name' => $txt['unread_topics_all']);
    } else {
        $txt['unread_topics_visit_none'] = strtr($txt['unread_topics_visit_none'], array('?action=unread;all' => '?action=unread;all' . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits']));
    }
    if (WIRELESS) {
        $context['sub_template'] = WIRELESS_PROTOCOL . '_recent';
    } else {
        loadTemplate('Recent');
        $context['sub_template'] = $_REQUEST['action'] == 'unread' ? 'unread' : 'replies';
    }
    // Setup the default topic icons... for checking they exist and the like ;)
    $stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'moved', 'recycled', 'wireless');
    $context['icon_sources'] = array();
    foreach ($stable_icons as $icon) {
        $context['icon_sources'][$icon] = 'images_url';
    }
    $is_topics = $_REQUEST['action'] == 'unread';
    // This part is the same for each query.
    $select_clause = '
				ms.subject AS firstSubject, ms.posterTime AS firstPosterTime, ms.ID_TOPIC, t.ID_BOARD, b.name AS bname,
				t.numReplies, t.numViews, ms.ID_MEMBER AS ID_FIRST_MEMBER, ml.ID_MEMBER AS ID_LAST_MEMBER,
				ml.posterTime AS lastPosterTime, IFNULL(mems.realName, ms.posterName) AS firstPosterName,
				IFNULL(meml.realName, ml.posterName) AS lastPosterName, ml.subject AS lastSubject,
				ml.icon AS lastIcon, ms.icon AS firstIcon, t.ID_POLL, t.isSticky, t.locked, ml.modifiedTime AS lastModifiedTime,
				IFNULL(lt.ID_MSG, IFNULL(lmr.ID_MSG, -1)) + 1 AS new_from, LEFT(ml.body, 384) AS lastBody, LEFT(ms.body, 384) AS firstBody,
				ml.smileysEnabled AS lastSmileys, ms.smileysEnabled AS firstSmileys, t.ID_FIRST_MSG, t.ID_LAST_MSG';
    if ($context['showing_all_topics']) {
        if (!empty($board)) {
            $request = db_query("\n\t\t\t\tSELECT MIN(ID_MSG)\n\t\t\t\tFROM {$db_prefix}log_mark_read\n\t\t\t\tWHERE ID_MEMBER = {$ID_MEMBER}\n\t\t\t\t\tAND ID_BOARD = {$board}", __FILE__, __LINE__);
            list($earliest_msg) = mysql_fetch_row($request);
            mysql_free_result($request);
        } else {
            $request = db_query("\n\t\t\t\tSELECT MIN(lmr.ID_MSG)\n\t\t\t\tFROM {$db_prefix}boards AS b\n\t\t\t\t\tLEFT JOIN {$db_prefix}log_mark_read AS lmr ON (lmr.ID_BOARD = b.ID_BOARD AND lmr.ID_MEMBER = {$ID_MEMBER})\n\t\t\t\tWHERE {$user_info['query_see_board']}", __FILE__, __LINE__);
            list($earliest_msg) = mysql_fetch_row($request);
            mysql_free_result($request);
        }
        // This is needed in case of topics marked unread.
        if (empty($earliest_msg)) {
            $earliest_msg = 0;
        } else {
            // Using caching, when possible, to ignore the below slow query.
            if (isset($_SESSION['cached_log_time']) && $_SESSION['cached_log_time'][0] + 45 > time()) {
                $earliest_msg2 = $_SESSION['cached_log_time'][1];
            } else {
                // This query is pretty slow, but it's needed to ensure nothing crucial is ignored.
                $request = db_query("\n\t\t\t\t\tSELECT MIN(ID_MSG)\n\t\t\t\t\tFROM {$db_prefix}log_topics\n\t\t\t\t\tWHERE ID_MEMBER = {$ID_MEMBER}", __FILE__, __LINE__);
                list($earliest_msg2) = mysql_fetch_row($request);
                mysql_free_result($request);
                // In theory this could be zero, if the first ever post is unread, so fudge it ;)
                if ($earliest_msg2 == 0) {
                    $earliest_msg2 = -1;
                }
                $_SESSION['cached_log_time'] = array(time(), $earliest_msg2);
            }
            $earliest_msg = min($earliest_msg2, $earliest_msg);
        }
    }
    // !!! Add modifiedTime in for logTime check?
    if ($modSettings['totalMessages'] > 100000 && $context['showing_all_topics']) {
        db_query("\n\t\t\tDROP TABLE IF EXISTS {$db_prefix}log_topics_unread", false, false);
        // Let's copy things out of the log_topics table, to reduce searching.
        $have_temp_table = db_query("\n\t\t\tCREATE TEMPORARY TABLE {$db_prefix}log_topics_unread (\n\t\t\t\tPRIMARY KEY (ID_TOPIC)\n\t\t\t)\n\t\t\tSELECT lt.ID_TOPIC, lt.ID_MSG\n\t\t\tFROM ({$db_prefix}topics AS t, {$db_prefix}log_topics AS lt)\n\t\t\tWHERE lt.ID_TOPIC = t.ID_TOPIC\n\t\t\t\tAND lt.ID_MEMBER = {$ID_MEMBER}\n\t\t\t\tAND t.{$query_this_board}" . (!empty($earliest_msg) ? "\n\t\t\t\tAND t.ID_LAST_MSG > {$earliest_msg}" : ''), false, false) !== false;
    } else {
        $have_temp_table = false;
    }
    if ($context['showing_all_topics'] && $have_temp_table) {
        $request = db_query("\n\t\t\tSELECT COUNT(*), MIN(t.ID_LAST_MSG)\n\t\t\tFROM {$db_prefix}topics AS t\n\t\t\t\tLEFT JOIN {$db_prefix}log_topics_unread AS lt ON (lt.ID_TOPIC = t.ID_TOPIC)\n\t\t\t\tLEFT JOIN {$db_prefix}log_mark_read AS lmr ON (lmr.ID_BOARD = t.ID_BOARD AND lmr.ID_MEMBER = {$ID_MEMBER})\n\t\t\tWHERE t.{$query_this_board}" . ($context['showing_all_topics'] && !empty($earliest_msg) ? "\n\t\t\t\tAND t.ID_LAST_MSG > {$earliest_msg}" : "\n\t\t\t\tAND t.ID_LAST_MSG > {$_SESSION['ID_MSG_LAST_VISIT']}") . "\n\t\t\t\tAND IFNULL(lt.ID_MSG, IFNULL(lmr.ID_MSG, 0)) < t.ID_LAST_MSG", __FILE__, __LINE__);
        list($num_topics, $min_message) = mysql_fetch_row($request);
        mysql_free_result($request);
        // Make sure the starting place makes sense and construct the page index.
        $context['page_index'] = constructPageIndex($scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . $context['querystring_board_limits'] . $context['querystring_sort_limits'], $_REQUEST['start'], $num_topics, $modSettings['defaultMaxTopics'], true);
        $context['current_page'] = (int) $_REQUEST['start'] / $modSettings['defaultMaxTopics'];
        $context['links'] = array('first' => $_REQUEST['start'] >= $modSettings['defaultMaxTopics'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits'] : '', 'prev' => $_REQUEST['start'] >= $modSettings['defaultMaxTopics'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] - $modSettings['defaultMaxTopics']) . $context['querystring_sort_limits'] : '', 'next' => $_REQUEST['start'] + $modSettings['defaultMaxTopics'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] + $modSettings['defaultMaxTopics']) . $context['querystring_sort_limits'] : '', 'last' => $_REQUEST['start'] + $modSettings['defaultMaxTopics'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], floor(($num_topics - 1) / $modSettings['defaultMaxTopics']) * $modSettings['defaultMaxTopics']) . $context['querystring_sort_limits'] : '', 'up' => $scripturl);
        $context['page_info'] = array('current_page' => $_REQUEST['start'] / $modSettings['defaultMaxTopics'] + 1, 'num_pages' => floor(($num_topics - 1) / $modSettings['defaultMaxTopics']) + 1);
        if ($num_topics == 0) {
            $context['topics'] = array();
            if ($context['querystring_board_limits'] == ';start=%d') {
                $context['querystring_board_limits'] = '';
            } else {
                $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']);
            }
            return;
        } else {
            $min_message = (int) $min_message;
        }
        $request = db_query("\n\t\t\tSELECT {$select_clause}\n\t\t\tFROM ({$db_prefix}messages AS ms, {$db_prefix}messages AS ml, {$db_prefix}topics AS t, {$db_prefix}boards AS b)\n\t\t\t\tLEFT JOIN {$db_prefix}members AS mems ON (mems.ID_MEMBER = ms.ID_MEMBER)\n\t\t\t\tLEFT JOIN {$db_prefix}members AS meml ON (meml.ID_MEMBER = ml.ID_MEMBER)\n\t\t\t\tLEFT JOIN {$db_prefix}log_topics_unread AS lt ON (lt.ID_TOPIC = t.ID_TOPIC)\n\t\t\t\tLEFT JOIN {$db_prefix}log_mark_read AS lmr ON (lmr.ID_BOARD = t.ID_BOARD AND lmr.ID_MEMBER = {$ID_MEMBER})\n\t\t\tWHERE t.ID_TOPIC = ms.ID_TOPIC\n\t\t\t\tAND b.ID_BOARD = t.ID_BOARD\n\t\t\t\tAND t.{$query_this_board}\n\t\t\t\tAND ms.ID_MSG = t.ID_FIRST_MSG\n\t\t\t\tAND ml.ID_MSG = t.ID_LAST_MSG\n\t\t\t\tAND t.ID_LAST_MSG >= {$min_message}\n\t\t\t\tAND IFNULL(lt.ID_MSG, IFNULL(lmr.ID_MSG, 0)) < t.ID_LAST_MSG\n\t\t\tORDER BY " . $_REQUEST['sort'] . ($ascending ? '' : ' DESC') . "\n\t\t\tLIMIT {$_REQUEST['start']}, {$modSettings['defaultMaxTopics']}", __FILE__, __LINE__);
    } elseif ($is_topics) {
        $request = db_query("\n\t\t\tSELECT COUNT(*), MIN(t.ID_LAST_MSG)\n\t\t\tFROM {$db_prefix}topics AS t" . ($have_temp_table ? "\n\t\t\t\tLEFT JOIN {$db_prefix}log_topics_unread AS lt ON (lt.ID_TOPIC = t.ID_TOPIC)" : "\n\t\t\t\tLEFT JOIN {$db_prefix}log_topics AS lt ON (lt.ID_TOPIC = t.ID_TOPIC AND lt.ID_MEMBER = {$ID_MEMBER})") . "\n\t\t\t\tLEFT JOIN {$db_prefix}log_mark_read AS lmr ON (lmr.ID_BOARD = t.ID_BOARD AND lmr.ID_MEMBER = {$ID_MEMBER})\n\t\t\tWHERE t.{$query_this_board}" . ($context['showing_all_topics'] && !empty($earliest_msg) ? "\n\t\t\t\tAND t.ID_LAST_MSG > {$earliest_msg}" : "\n\t\t\t\tAND t.ID_LAST_MSG > {$_SESSION['ID_MSG_LAST_VISIT']}") . "\n\t\t\t\tAND IFNULL(lt.ID_MSG, IFNULL(lmr.ID_MSG, 0)) < t.ID_LAST_MSG", __FILE__, __LINE__);
        list($num_topics, $min_message) = mysql_fetch_row($request);
        mysql_free_result($request);
        // Make sure the starting place makes sense and construct the page index.
        $context['page_index'] = constructPageIndex($scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . $context['querystring_board_limits'] . $context['querystring_sort_limits'], $_REQUEST['start'], $num_topics, $modSettings['defaultMaxTopics'], true);
        $context['current_page'] = (int) $_REQUEST['start'] / $modSettings['defaultMaxTopics'];
        $context['links'] = array('first' => $_REQUEST['start'] >= $modSettings['defaultMaxTopics'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits'] : '', 'prev' => $_REQUEST['start'] >= $modSettings['defaultMaxTopics'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] - $modSettings['defaultMaxTopics']) . $context['querystring_sort_limits'] : '', 'next' => $_REQUEST['start'] + $modSettings['defaultMaxTopics'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] + $modSettings['defaultMaxTopics']) . $context['querystring_sort_limits'] : '', 'last' => $_REQUEST['start'] + $modSettings['defaultMaxTopics'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], floor(($num_topics - 1) / $modSettings['defaultMaxTopics']) * $modSettings['defaultMaxTopics']) . $context['querystring_sort_limits'] : '', 'up' => $scripturl);
        $context['page_info'] = array('current_page' => $_REQUEST['start'] / $modSettings['defaultMaxTopics'] + 1, 'num_pages' => floor(($num_topics - 1) / $modSettings['defaultMaxTopics']) + 1);
        if ($num_topics == 0) {
            $context['topics'] = array();
            if ($context['querystring_board_limits'] == ';start=%d') {
                $context['querystring_board_limits'] = '';
            } else {
                $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']);
            }
            return;
        } else {
            $min_message = (int) $min_message;
        }
        $request = db_query("\n\t\t\tSELECT {$select_clause}\n\t\t\tFROM ({$db_prefix}messages AS ms, {$db_prefix}messages AS ml, {$db_prefix}topics AS t, {$db_prefix}boards AS b)\n\t\t\t\tLEFT JOIN {$db_prefix}members AS mems ON (mems.ID_MEMBER = ms.ID_MEMBER)\n\t\t\t\tLEFT JOIN {$db_prefix}members AS meml ON (meml.ID_MEMBER = ml.ID_MEMBER)" . ($have_temp_table ? "\n\t\t\t\tLEFT JOIN {$db_prefix}log_topics_unread AS lt ON (lt.ID_TOPIC = t.ID_TOPIC)" : "\n\t\t\t\tLEFT JOIN {$db_prefix}log_topics AS lt ON (lt.ID_TOPIC = t.ID_TOPIC AND lt.ID_MEMBER = {$ID_MEMBER})") . "\n\t\t\t\tLEFT JOIN {$db_prefix}log_mark_read AS lmr ON (lmr.ID_BOARD = t.ID_BOARD AND lmr.ID_MEMBER = {$ID_MEMBER})\n\t\t\tWHERE t.ID_TOPIC = ms.ID_TOPIC\n\t\t\t\tAND b.ID_BOARD = t.ID_BOARD\n\t\t\t\tAND t.{$query_this_board}\n\t\t\t\tAND ms.ID_MSG = t.ID_FIRST_MSG\n\t\t\t\tAND ml.ID_MSG = t.ID_LAST_MSG\n\t\t\t\tAND t.ID_LAST_MSG >= {$min_message}\n\t\t\t\tAND IFNULL(lt.ID_MSG, IFNULL(lmr.ID_MSG, 0)) < ml.ID_MSG\n\t\t\tORDER BY " . $_REQUEST['sort'] . ($ascending ? '' : ' DESC') . "\n\t\t\tLIMIT {$_REQUEST['start']}, {$modSettings['defaultMaxTopics']}", __FILE__, __LINE__);
    } else {
        if ($modSettings['totalMessages'] > 100000) {
            db_query("\n\t\t\t\tDROP TABLE IF EXISTS {$db_prefix}topics_posted_in", false, false);
            db_query("\n\t\t\t\tDROP TABLE IF EXISTS {$db_prefix}log_topics_posted_in", false, false);
            $sortKey_joins = array('ms.subject' => "\n\t\t\t\t\tINNER JOIN {$db_prefix}messages AS ms ON (ms.ID_MSG = t.ID_FIRST_MSG)", 'IFNULL(mems.realName, ms.posterName)' => "\n\t\t\t\t\tINNER JOIN {$db_prefix}messages AS ms ON (ms.ID_MSG = t.ID_FIRST_MSG)\n\t\t\t\t\tLEFT JOIN {$db_prefix}members AS mems ON (mems.ID_MEMBER = ms.ID_MEMBER)");
            // The main benefit of this temporary table is not that it's faster; it's that it avoids locks later.
            $have_temp_table = db_query("\n\t\t\t\tCREATE TEMPORARY TABLE {$db_prefix}topics_posted_in (\n\t\t\t\t\tID_TOPIC mediumint(8) unsigned NOT NULL default '0',\n\t\t\t\t\tID_BOARD smallint(5) unsigned NOT NULL default '0',\n\t\t\t\t\tID_LAST_MSG int(10) unsigned NOT NULL default '0',\n\t\t\t\t\tID_MSG int(10) unsigned NOT NULL default '0',\n\t\t\t\t\tPRIMARY KEY (ID_TOPIC)\n\t\t\t\t)\n\t\t\t\tSELECT t.ID_TOPIC, t.ID_BOARD, t.ID_LAST_MSG, IFNULL(lmr.ID_MSG, 0) AS ID_MSG" . (!in_array($_REQUEST['sort'], array('t.ID_LAST_MSG', 't.ID_TOPIC')) ? ", {$_REQUEST['sort']} AS sortKey" : '') . "\n\t\t\t\tFROM ({$db_prefix}topics AS t, {$db_prefix}messages AS m)\n\t\t\t\t\tLEFT JOIN {$db_prefix}log_mark_read AS lmr ON (lmr.ID_BOARD = t.ID_BOARD AND lmr.ID_MEMBER = {$ID_MEMBER})" . (isset($sortKey_joins[$_REQUEST['sort']]) ? $sortKey_joins[$_REQUEST['sort']] : '') . "\n\t\t\t\tWHERE m.ID_MEMBER = {$ID_MEMBER}\n\t\t\t\t\tAND t.ID_TOPIC = m.ID_TOPIC" . (!empty($board) ? "\n\t\t\t\t\tAND t.ID_BOARD = {$board}" : '') . "\n\t\t\t\tGROUP BY m.ID_TOPIC", false, false) !== false;
            // If that worked, create a sample of the log_topics table too.
            if ($have_temp_table) {
                $have_temp_table = db_query("\n\t\t\t\t\tCREATE TEMPORARY TABLE {$db_prefix}log_topics_posted_in (\n\t\t\t\t\t\tPRIMARY KEY (ID_TOPIC)\n\t\t\t\t\t)\n\t\t\t\t\tSELECT lt.ID_TOPIC, lt.ID_MSG\n\t\t\t\t\tFROM ({$db_prefix}log_topics AS lt, {$db_prefix}topics_posted_in AS pi)\n\t\t\t\t\tWHERE lt.ID_MEMBER = {$ID_MEMBER}\n\t\t\t\t\t\tAND lt.ID_TOPIC = pi.ID_TOPIC", false, false) !== false;
            }
        }
        if ($have_temp_table) {
            $request = db_query("\n\t\t\t\tSELECT COUNT(*)\n\t\t\t\tFROM ({$db_prefix}topics_posted_in AS pi)\n\t\t\t\t\tLEFT JOIN {$db_prefix}log_topics_posted_in AS lt ON (lt.ID_TOPIC = pi.ID_TOPIC)\n\t\t\t\tWHERE pi.{$query_this_board}\n\t\t\t\t\tAND IFNULL(lt.ID_MSG, pi.ID_MSG) < pi.ID_LAST_MSG", __FILE__, __LINE__);
            list($num_topics) = mysql_fetch_row($request);
            mysql_free_result($request);
        } else {
            $request = db_query("\n\t\t\t\tSELECT COUNT(DISTINCT t.ID_TOPIC), MIN(t.ID_LAST_MSG)\n\t\t\t\tFROM ({$db_prefix}topics AS t, {$db_prefix}messages AS m)\n\t\t\t\t\tLEFT JOIN {$db_prefix}log_topics AS lt ON (lt.ID_TOPIC = t.ID_TOPIC AND lt.ID_MEMBER = {$ID_MEMBER})\n\t\t\t\t\tLEFT JOIN {$db_prefix}log_mark_read AS lmr ON (lmr.ID_BOARD = t.ID_BOARD AND lmr.ID_MEMBER = {$ID_MEMBER})\n\t\t\t\tWHERE t.{$query_this_board}\n\t\t\t\t\tAND m.ID_TOPIC = t.ID_TOPIC\n\t\t\t\t\tAND m.ID_MEMBER = {$ID_MEMBER}\n\t\t\t\t\tAND IFNULL(lt.ID_MSG, IFNULL(lmr.ID_MSG, 0)) < t.ID_LAST_MSG", __FILE__, __LINE__);
            list($num_topics, $min_message) = mysql_fetch_row($request);
            mysql_free_result($request);
        }
        // Make sure the starting place makes sense and construct the page index.
        $context['page_index'] = constructPageIndex($scripturl . '?action=' . $_REQUEST['action'] . $context['querystring_board_limits'] . $context['querystring_sort_limits'], $_REQUEST['start'], $num_topics, $modSettings['defaultMaxTopics'], true);
        $context['current_page'] = (int) $_REQUEST['start'] / $modSettings['defaultMaxTopics'];
        $context['links'] = array('first' => $_REQUEST['start'] >= $modSettings['defaultMaxTopics'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits'] : '', 'prev' => $_REQUEST['start'] >= $modSettings['defaultMaxTopics'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] - $modSettings['defaultMaxTopics']) . $context['querystring_sort_limits'] : '', 'next' => $_REQUEST['start'] + $modSettings['defaultMaxTopics'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] + $modSettings['defaultMaxTopics']) . $context['querystring_sort_limits'] : '', 'last' => $_REQUEST['start'] + $modSettings['defaultMaxTopics'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], floor(($num_topics - 1) / $modSettings['defaultMaxTopics']) * $modSettings['defaultMaxTopics']) . $context['querystring_sort_limits'] : '', 'up' => $scripturl);
        $context['page_info'] = array('current_page' => $_REQUEST['start'] / $modSettings['defaultMaxTopics'] + 1, 'num_pages' => floor(($num_topics - 1) / $modSettings['defaultMaxTopics']) + 1);
        if ($num_topics == 0) {
            $context['topics'] = array();
            if ($context['querystring_board_limits'] == ';start=%d') {
                $context['querystring_board_limits'] = '';
            } else {
                $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']);
            }
            return;
        }
        if ($have_temp_table) {
            $request = db_query("\n\t\t\t\tSELECT t.ID_TOPIC\n\t\t\t\tFROM {$db_prefix}topics_posted_in AS t\n\t\t\t\t\tLEFT JOIN {$db_prefix}log_topics_posted_in AS lt ON (lt.ID_TOPIC = t.ID_TOPIC)\n\t\t\t\tWHERE t.{$query_this_board}\n\t\t\t\t\tAND IFNULL(lt.ID_MSG, t.ID_MSG) < t.ID_LAST_MSG\n\t\t\t\tORDER BY " . (in_array($_REQUEST['sort'], array('t.ID_LAST_MSG', 't.ID_TOPIC')) ? $_REQUEST['sort'] : 't.sortKey') . ($ascending ? '' : ' DESC') . "\n\t\t\t\tLIMIT {$_REQUEST['start']}, {$modSettings['defaultMaxTopics']}", __FILE__, __LINE__);
        } else {
            $request = db_query("\n\t\t\t\tSELECT DISTINCT t.ID_TOPIC\n\t\t\t\tFROM ({$db_prefix}topics AS t, {$db_prefix}messages AS m" . (strpos($_REQUEST['sort'], 'ms.') === false ? '' : ", {$db_prefix}messages AS ms") . ')' . (strpos($_REQUEST['sort'], 'mems.') === false ? '' : "\n\t\t\t\t\tLEFT JOIN {$db_prefix}members AS mems ON (mems.ID_MEMBER = ms.ID_MEMBER)") . "\n\t\t\t\t\tLEFT JOIN {$db_prefix}log_topics AS lt ON (lt.ID_TOPIC = t.ID_TOPIC AND lt.ID_MEMBER = {$ID_MEMBER})\n\t\t\t\t\tLEFT JOIN {$db_prefix}log_mark_read AS lmr ON (lmr.ID_BOARD = t.ID_BOARD AND lmr.ID_MEMBER = {$ID_MEMBER})\n\t\t\t\tWHERE m.ID_TOPIC = t.ID_TOPIC\n\t\t\t\t\tAND m.ID_MEMBER = {$ID_MEMBER}\n\t\t\t\t\tAND t.{$query_this_board}\n\t\t\t\t\tAND t.ID_LAST_MSG >= " . (int) $min_message . "\n\t\t\t\t\tAND IFNULL(lt.ID_MSG, IFNULL(lmr.ID_MSG, 0)) < t.ID_LAST_MSG" . (strpos($_REQUEST['sort'], 'ms.') !== false ? "\n\t\t\t\t\tAND ms.ID_MSG = t.ID_FIRST_MSG" : '') . "\n\t\t\t\tORDER BY " . $_REQUEST['sort'] . ($ascending ? '' : ' DESC') . "\n\t\t\t\tLIMIT {$_REQUEST['start']}, {$modSettings['defaultMaxTopics']}", __FILE__, __LINE__);
        }
        $topics = array();
        while ($row = mysql_fetch_assoc($request)) {
            $topics[] = $row['ID_TOPIC'];
        }
        mysql_free_result($request);
        // Sanity... where have you gone?
        if (empty($topics)) {
            $context['topics'] = array();
            if ($context['querystring_board_limits'] == ';start=%d') {
                $context['querystring_board_limits'] = '';
            } else {
                $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']);
            }
            return;
        }
        $request = db_query("\n\t\t\tSELECT {$select_clause}\n\t\t\tFROM ({$db_prefix}messages AS ms, {$db_prefix}messages AS ml, {$db_prefix}topics AS t, {$db_prefix}boards AS b)\n\t\t\t\tLEFT JOIN {$db_prefix}members AS mems ON (mems.ID_MEMBER = ms.ID_MEMBER)\n\t\t\t\tLEFT JOIN {$db_prefix}members AS meml ON (meml.ID_MEMBER = ml.ID_MEMBER)\n\t\t\t\tLEFT JOIN {$db_prefix}log_topics AS lt ON (lt.ID_TOPIC = t.ID_TOPIC AND lt.ID_MEMBER = {$ID_MEMBER})\n\t\t\t\tLEFT JOIN {$db_prefix}log_mark_read AS lmr ON (lmr.ID_BOARD = t.ID_BOARD AND lmr.ID_MEMBER = {$ID_MEMBER})\n\t\t\tWHERE t.ID_TOPIC IN (" . implode(', ', $topics) . ")\n\t\t\t\tAND t.ID_TOPIC = ms.ID_TOPIC\n\t\t\t\tAND b.ID_BOARD = t.ID_BOARD\n\t\t\t\tAND ms.ID_MSG = t.ID_FIRST_MSG\n\t\t\t\tAND ml.ID_MSG = t.ID_LAST_MSG\n\t\t\tORDER BY " . $_REQUEST['sort'] . ($ascending ? '' : ' DESC') . "\n\t\t\tLIMIT " . count($topics), __FILE__, __LINE__);
    }
    $context['topics'] = array();
    $topic_ids = array();
    while ($row = mysql_fetch_assoc($request)) {
        if ($row['ID_POLL'] > 0 && $modSettings['pollMode'] == '0') {
            continue;
        }
        $topic_ids[] = $row['ID_TOPIC'];
        // Clip the strings first because censoring is slow :/. (for some reason?)
        $row['firstBody'] = strip_tags(strtr(parse_bbc($row['firstBody'], $row['firstSmileys'], $row['ID_FIRST_MSG']), array('<br />' => '&#10;')));
        if ($func['strlen']($row['firstBody']) > 128) {
            $row['firstBody'] = $func['substr']($row['firstBody'], 0, 128) . '...';
        }
        $row['lastBody'] = strip_tags(strtr(parse_bbc($row['lastBody'], $row['lastSmileys'], $row['ID_LAST_MSG']), array('<br />' => '&#10;')));
        if ($func['strlen']($row['lastBody']) > 128) {
            $row['lastBody'] = $func['substr']($row['lastBody'], 0, 128) . '...';
        }
        // Do a bit of censoring...
        censorText($row['firstSubject']);
        censorText($row['firstBody']);
        // But don't do it twice, it can be a slow ordeal!
        if ($row['ID_FIRST_MSG'] == $row['ID_LAST_MSG']) {
            $row['lastSubject'] = $row['firstSubject'];
            $row['lastBody'] = $row['firstBody'];
        } else {
            censorText($row['lastSubject']);
            censorText($row['lastBody']);
        }
        // Decide how many pages the topic should have.
        $topic_length = $row['numReplies'] + 1;
        if ($topic_length > $modSettings['defaultMaxMessages']) {
            $tmppages = array();
            $tmpa = 1;
            for ($tmpb = 0; $tmpb < $topic_length; $tmpb += $modSettings['defaultMaxMessages']) {
                $tmppages[] = '<a href="' . $scripturl . '?topic=' . $row['ID_TOPIC'] . '.' . $tmpb . ';topicseen">' . $tmpa . '</a>';
                $tmpa++;
            }
            // Show links to all the pages?
            if (count($tmppages) <= 5) {
                $pages = '&#171; ' . implode(' ', $tmppages);
            } else {
                $pages = '&#171; ' . $tmppages[0] . ' ' . $tmppages[1] . ' ... ' . $tmppages[count($tmppages) - 2] . ' ' . $tmppages[count($tmppages) - 1];
            }
            if (!empty($modSettings['enableAllMessages']) && $topic_length < $modSettings['enableAllMessages']) {
                $pages .= ' &nbsp;<a href="' . $scripturl . '?topic=' . $row['ID_TOPIC'] . '.0;all">' . $txt[190] . '</a>';
            }
            $pages .= ' &#187;';
        } else {
            $pages = '';
        }
        // We need to check the topic icons exist... you can never be too sure!
        if (empty($modSettings['messageIconChecks_disable'])) {
            // First icon first... as you'd expect.
            if (!isset($context['icon_sources'][$row['firstIcon']])) {
                $context['icon_sources'][$row['firstIcon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['firstIcon'] . '.gif') ? 'images_url' : 'default_images_url';
            }
            // Last icon... last... duh.
            if (!isset($context['icon_sources'][$row['lastIcon']])) {
                $context['icon_sources'][$row['lastIcon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['lastIcon'] . '.gif') ? 'images_url' : 'default_images_url';
            }
        }
        // And build the array.
        $context['topics'][$row['ID_TOPIC']] = array('id' => $row['ID_TOPIC'], 'first_post' => array('id' => $row['ID_FIRST_MSG'], 'member' => array('name' => $row['firstPosterName'], 'id' => $row['ID_FIRST_MEMBER'], 'href' => $scripturl . '?action=profile;u=' . $row['ID_FIRST_MEMBER'], 'link' => !empty($row['ID_FIRST_MEMBER']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['ID_FIRST_MEMBER'] . '" title="' . $txt[92] . ' ' . $row['firstPosterName'] . '">' . $row['firstPosterName'] . '</a>' : $row['firstPosterName']), 'time' => timeformat($row['firstPosterTime']), 'timestamp' => forum_time(true, $row['firstPosterTime']), 'subject' => $row['firstSubject'], 'preview' => $row['firstBody'], 'icon' => $row['firstIcon'], 'icon_url' => $settings[$context['icon_sources'][$row['firstIcon']]] . '/post/' . $row['firstIcon'] . '.gif', 'href' => $scripturl . '?topic=' . $row['ID_TOPIC'] . '.0;topicseen', 'link' => '<a href="' . $scripturl . '?topic=' . $row['ID_TOPIC'] . '.0;topicseen">' . $row['firstSubject'] . '</a>'), 'last_post' => array('id' => $row['ID_LAST_MSG'], 'member' => array('name' => $row['lastPosterName'], 'id' => $row['ID_LAST_MEMBER'], 'href' => $scripturl . '?action=profile;u=' . $row['ID_LAST_MEMBER'], 'link' => !empty($row['ID_LAST_MEMBER']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['ID_LAST_MEMBER'] . '">' . $row['lastPosterName'] . '</a>' : $row['lastPosterName']), 'time' => timeformat($row['lastPosterTime']), 'timestamp' => forum_time(true, $row['lastPosterTime']), 'subject' => $row['lastSubject'], 'preview' => $row['lastBody'], 'icon' => $row['lastIcon'], 'icon_url' => $settings[$context['icon_sources'][$row['lastIcon']]] . '/post/' . $row['lastIcon'] . '.gif', 'href' => $scripturl . '?topic=' . $row['ID_TOPIC'] . ($row['numReplies'] == 0 ? '.0' : '.msg' . $row['ID_LAST_MSG']) . ';topicseen#msg' . $row['ID_LAST_MSG'], 'link' => '<a href="' . $scripturl . '?topic=' . $row['ID_TOPIC'] . ($row['numReplies'] == 0 ? '.0' : '.msg' . $row['ID_LAST_MSG']) . ';topicseen#msg' . $row['ID_LAST_MSG'] . '">' . $row['lastSubject'] . '</a>'), 'new_from' => $row['new_from'], 'new_href' => $scripturl . '?topic=' . $row['ID_TOPIC'] . '.msg' . $row['new_from'] . ';topicseen#new', 'href' => $scripturl . '?topic=' . $row['ID_TOPIC'] . ($row['numReplies'] == 0 ? '.0' : '.msg' . $row['new_from']) . ';topicseen' . ($row['numReplies'] == 0 ? '' : 'new'), 'link' => '<a href="' . $scripturl . '?topic=' . $row['ID_TOPIC'] . ($row['numReplies'] == 0 ? '.0' : '.msg' . $row['new_from']) . ';topicseen#msg' . $row['new_from'] . '">' . $row['firstSubject'] . '</a>', 'is_sticky' => !empty($modSettings['enableStickyTopics']) && !empty($row['isSticky']), 'is_locked' => !empty($row['locked']), 'is_poll' => $modSettings['pollMode'] == '1' && $row['ID_POLL'] > 0, 'is_hot' => $row['numReplies'] >= $modSettings['hotTopicPosts'], 'is_very_hot' => $row['numReplies'] >= $modSettings['hotTopicVeryPosts'], 'is_posted_in' => false, 'icon' => $row['firstIcon'], 'icon_url' => $settings[$context['icon_sources'][$row['firstIcon']]] . '/post/' . $row['firstIcon'] . '.gif', 'subject' => $row['firstSubject'], 'pages' => $pages, 'replies' => $row['numReplies'], 'views' => $row['numViews'], 'board' => array('id' => $row['ID_BOARD'], 'name' => $row['bname'], 'href' => $scripturl . '?board=' . $row['ID_BOARD'] . '.0', 'link' => '<a href="' . $scripturl . '?board=' . $row['ID_BOARD'] . '.0">' . $row['bname'] . '</a>'));
        determineTopicClass($context['topics'][$row['ID_TOPIC']]);
    }
    mysql_free_result($request);
    if ($is_topics && !empty($modSettings['enableParticipation']) && !empty($topic_ids)) {
        $result = db_query("\n\t\t\tSELECT ID_TOPIC\n\t\t\tFROM {$db_prefix}messages\n\t\t\tWHERE ID_TOPIC IN (" . implode(', ', $topic_ids) . ")\n\t\t\t\tAND ID_MEMBER = {$ID_MEMBER}", __FILE__, __LINE__);
        while ($row = mysql_fetch_assoc($result)) {
            if (empty($context['topics'][$row['ID_TOPIC']]['is_posted_in'])) {
                $context['topics'][$row['ID_TOPIC']]['is_posted_in'] = true;
                $context['topics'][$row['ID_TOPIC']]['class'] = 'my_' . $context['topics'][$row['ID_TOPIC']]['class'];
            }
        }
        mysql_free_result($result);
    }
    $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']);
    $context['topics_to_mark'] = implode('-', $topic_ids);
}
Esempio n. 5
0
    function __construct($request, $total_items, $not_profile = false)
    {
        global $context, $txt, $user_info, $scripturl, $options, $memberContext, $modSettings;
        if (!isset($context['pageindex_multiplier'])) {
            $context['pageindex_multiplier'] = commonAPI::getMessagesPerPage();
        }
        $cb_name = isset($context['cb_name']) ? $context['cb_name'] : 'topics[]';
        while ($row = mysql_fetch_assoc($request)) {
            censorText($row['subject']);
            $this->topic_ids[] = $row['id_topic'];
            $f_post_mem_href = !empty($row['id_member']) ? URL::user($row['id_member'], $row['first_member_name']) : '';
            $t_href = URL::topic($row['id_topic'], $row['subject'], 0);
            $l_post_mem_href = !empty($row['id_member_updated']) ? URL::user($row['id_member_updated'], $row['last_real_name']) : '';
            $l_post_msg_href = URL::topic($row['id_topic'], $row['last_subject'], $user_info['is_guest'] ? !empty($options['view_newest_first']) ? 0 : (int) ($row['num_replies'] / $context['pageindex_multiplier']) * $context['pageindex_multiplier'] : 0, $user_info['is_guest'] ? true : false, $user_info['is_guest'] ? '' : '.msg' . $row['id_last_msg'], $user_info['is_guest'] ? '#msg' . $row['id_last_msg'] : '#new');
            $this->topiclist[$row['id_topic']] = array('id' => $row['id_topic'], 'id_member_started' => empty($row['id_member']) ? 0 : $row['id_member'], 'first_post' => array('id' => $row['id_first_msg'], 'member' => array('username' => $row['first_member_name'], 'name' => $row['first_member_name'], 'id' => empty($row['id_member']) ? 0 : $row['id_member'], 'href' => $f_post_mem_href, 'link' => !empty($row['id_member']) ? '<a onclick="getMcard(' . $row['id_member'] . ', $(this));return(false);" href="' . $f_post_mem_href . '" title="' . $txt['profile_of'] . ' ' . $row['first_member_name'] . '">' . $row['first_member_name'] . '</a>' : $row['first_member_name']), 'time' => timeformat($row['first_poster_time']), 'timestamp' => forum_time(true, $row['first_poster_time']), 'subject' => $row['subject'], 'icon' => $row['first_icon'], 'icon_url' => getPostIcon($row['first_icon']), 'href' => $t_href, 'link' => '<a href="' . $t_href . '">' . $row['subject'] . '</a>'), 'last_post' => array('id' => $row['id_last_msg'], 'member' => array('username' => $row['last_real_name'], 'name' => $row['last_real_name'], 'id' => $row['id_member_updated'], 'href' => $l_post_mem_href, 'link' => !empty($row['id_member_updated']) ? '<a onclick="getMcard(' . $row['id_member_updated'] . ', $(this));return(false);" href="' . $l_post_mem_href . '">' . $row['last_real_name'] . '</a>' : $row['last_real_name']), 'time' => timeformat($row['last_post_time']), 'timestamp' => forum_time(true, $row['last_post_time']), 'subject' => $row['last_subject'], 'href' => $l_post_msg_href, 'link' => '<a href="' . $l_post_msg_href . ($row['num_replies'] == 0 ? '' : ' rel="nofollow"') . '>' . $row['last_subject'] . '</a>'), 'checkbox_name' => $cb_name, 'subject' => $row['subject'], 'new' => $row['new_from'] <= $row['id_msg_modified'], 'new_from' => $row['new_from'], 'newtime' => $row['new_from'], 'updated' => timeformat($row['poster_time']), 'new_href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['new_from'] . '#new', 'new_link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['new_from'] . '#new">' . $row['subject'] . '</a>', 'replies' => comma_format($row['num_replies']), 'views' => comma_format($row['num_views']), 'approved' => $row['approved'], 'unapproved_posts' => $row['unapproved_posts'], 'is_old' => !empty($modSettings['oldTopicDays']) ? $context['time_now'] - $row['last_post_time'] > $modSettings['oldTopicDays'] * 86400 : false, 'is_posted_in' => false, 'prefix' => '', 'pages' => '', 'is_sticky' => !empty($modSettings['enableStickyTopics']) && !empty($row['is_sticky']), 'is_locked' => !empty($row['locked']), 'is_poll' => false, 'is_hot' => $row['num_replies'] >= $modSettings['hotTopicPosts'], 'is_very_hot' => $row['num_replies'] >= $modSettings['hotTopicVeryPosts'], 'board' => isset($row['id_board']) && !empty($row['id_board']) ? array('name' => $row['board_name'], 'id' => $row['id_board'], 'href' => URL::board($row['id_board'], $row['board_name'])) : array('name' => '', 'id' => 0, 'href' => ''));
            determineTopicClass($this->topiclist[$row['id_topic']]);
            if (!empty($row['id_member']) && ($row['id_member'] != $user_info['id'] || $not_profile)) {
                $this->users_to_load[$row['id_member']] = $row['id_member'];
            }
        }
        loadMemberData($this->users_to_load);
        foreach ($this->topiclist as &$topic) {
            if (!isset($memberContext[$topic['id_member_started']])) {
                loadMemberContext($topic['id_member_started']);
            }
            $topic['first_post']['member']['avatar'] =& $memberContext[$topic['id_member_started']]['avatar']['image'];
        }
        // figure out whether we have posted in a topic (but only if we are not the topic starter)
        if (!empty($modSettings['enableParticipation']) && !$user_info['is_guest'] && !empty($this->topic_ids)) {
            $result = smf_db_query('
				SELECT id_topic
				FROM {db_prefix}messages
				WHERE id_topic IN ({array_int:topic_list})
					AND id_member = {int:current_member}
				GROUP BY id_topic
				LIMIT ' . count($this->topic_ids), array('current_member' => $user_info['id'], 'topic_list' => $this->topic_ids));
            while ($row = mysql_fetch_assoc($result)) {
                if ($this->topiclist[$row['id_topic']]['first_post']['member']['id'] != $user_info['id']) {
                    $this->topiclist[$row['id_topic']]['is_posted_in'] = true;
                }
            }
            mysql_free_result($result);
        }
    }
Esempio n. 6
0
function UnreadTopics()
{
    global $board, $txt, $scripturl, $sourcedir;
    global $user_info, $context, $settings, $modSettings, $smcFunc, $options;
    // Guests can't have unread things, we don't know anything about them.
    is_not_guest();
    // Prefetching + lots of MySQL work = bad mojo.
    if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') {
        ob_end_clean();
        header('HTTP/1.1 403 Forbidden');
        die;
    }
    $context['showing_all_topics'] = isset($_GET['all']);
    $context['start'] = (int) $_REQUEST['start'];
    $context['topics_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['topics_per_page']) && !WIRELESS ? $options['topics_per_page'] : $modSettings['defaultMaxTopics'];
    if ($_REQUEST['action'] == 'unread') {
        $context['page_title'] = $context['showing_all_topics'] ? $txt['unread_topics_all'] : $txt['unread_topics_visit'];
    } else {
        $context['page_title'] = $txt['unread_replies'];
    }
    if ($context['showing_all_topics'] && !empty($context['load_average']) && !empty($modSettings['loadavg_allunread']) && $context['load_average'] >= $modSettings['loadavg_allunread']) {
        fatal_lang_error('loadavg_allunread_disabled', false);
    } elseif ($_REQUEST['action'] != 'unread' && !empty($context['load_average']) && !empty($modSettings['loadavg_unreadreplies']) && $context['load_average'] >= $modSettings['loadavg_unreadreplies']) {
        fatal_lang_error('loadavg_unreadreplies_disabled', false);
    } elseif (!$context['showing_all_topics'] && $_REQUEST['action'] == 'unread' && !empty($context['load_average']) && !empty($modSettings['loadavg_unread']) && $context['load_average'] >= $modSettings['loadavg_unread']) {
        fatal_lang_error('loadavg_unread_disabled', false);
    }
    // Parameters for the main query.
    $query_parameters = array();
    // Are we specifying any specific board?
    if (isset($_REQUEST['children']) && (!empty($board) || !empty($_REQUEST['boards']))) {
        $boards = array();
        if (!empty($_REQUEST['boards'])) {
            $_REQUEST['boards'] = explode(',', $_REQUEST['boards']);
            foreach ($_REQUEST['boards'] as $b) {
                $boards[] = (int) $b;
            }
        }
        if (!empty($board)) {
            $boards[] = (int) $board;
        }
        // The easiest thing is to just get all the boards they can see, but since we've specified the top of tree we ignore some of them
        $request = $smcFunc['db_query']('', '
			SELECT b.id_board, b.id_parent
			FROM {db_prefix}boards AS b
			WHERE {query_wanna_see_board}
				AND b.child_level > {int:no_child}
				AND b.id_board NOT IN ({array_int:boards})
			ORDER BY child_level ASC
			', array('no_child' => 0, 'boards' => $boards));
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            if (in_array($row['id_parent'], $boards)) {
                $boards[] = $row['id_board'];
            }
        }
        $smcFunc['db_free_result']($request);
        if (empty($boards)) {
            fatal_lang_error('error_no_boards_selected');
        }
        $query_this_board = 'id_board IN ({array_int:boards})';
        $query_parameters['boards'] = $boards;
        $context['querystring_board_limits'] = ';boards=' . implode(',', $boards) . ';start=%d';
    } elseif (!empty($board)) {
        $query_this_board = 'id_board = {int:board}';
        $query_parameters['board'] = $board;
        $context['querystring_board_limits'] = ';board=' . $board . '.%1$d';
    } elseif (!empty($_REQUEST['boards'])) {
        $_REQUEST['boards'] = explode(',', $_REQUEST['boards']);
        foreach ($_REQUEST['boards'] as $i => $b) {
            $_REQUEST['boards'][$i] = (int) $b;
        }
        $request = $smcFunc['db_query']('', '
			SELECT b.id_board
			FROM {db_prefix}boards AS b
			WHERE {query_see_board}
				AND b.id_board IN ({array_int:board_list})', array('board_list' => $_REQUEST['boards']));
        $boards = array();
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            $boards[] = $row['id_board'];
        }
        $smcFunc['db_free_result']($request);
        if (empty($boards)) {
            fatal_lang_error('error_no_boards_selected');
        }
        $query_this_board = 'id_board IN ({array_int:boards})';
        $query_parameters['boards'] = $boards;
        $context['querystring_board_limits'] = ';boards=' . implode(',', $boards) . ';start=%1$d';
    } elseif (!empty($_REQUEST['c'])) {
        $_REQUEST['c'] = explode(',', $_REQUEST['c']);
        foreach ($_REQUEST['c'] as $i => $c) {
            $_REQUEST['c'][$i] = (int) $c;
        }
        $see_board = isset($_REQUEST['action']) && $_REQUEST['action'] == 'unreadreplies' ? 'query_see_board' : 'query_wanna_see_board';
        $request = $smcFunc['db_query']('', '
			SELECT b.id_board
			FROM {db_prefix}boards AS b
			WHERE ' . $user_info[$see_board] . '
				AND b.id_cat IN ({array_int:id_cat})', array('id_cat' => $_REQUEST['c']));
        $boards = array();
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            $boards[] = $row['id_board'];
        }
        $smcFunc['db_free_result']($request);
        if (empty($boards)) {
            fatal_lang_error('error_no_boards_selected');
        }
        $query_this_board = 'id_board IN ({array_int:boards})';
        $query_parameters['boards'] = $boards;
        $context['querystring_board_limits'] = ';c=' . implode(',', $_REQUEST['c']) . ';start=%1$d';
    } else {
        $see_board = isset($_REQUEST['action']) && $_REQUEST['action'] == 'unreadreplies' ? 'query_see_board' : 'query_wanna_see_board';
        // Don't bother to show deleted posts!
        $request = $smcFunc['db_query']('', '
			SELECT b.id_board
			FROM {db_prefix}boards AS b
			WHERE ' . $user_info[$see_board] . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
				AND b.id_board != {int:recycle_board}' : ''), array('recycle_board' => (int) $modSettings['recycle_board']));
        $boards = array();
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            $boards[] = $row['id_board'];
        }
        $smcFunc['db_free_result']($request);
        if (empty($boards)) {
            fatal_lang_error('error_no_boards_selected');
        }
        $query_this_board = 'id_board IN ({array_int:boards})';
        $query_parameters['boards'] = $boards;
        $context['querystring_board_limits'] = ';start=%1$d';
        $context['no_board_limits'] = true;
    }
    $sort_methods = array('subject' => 'ms.subject', 'starter' => 'IFNULL(mems.real_name, ms.poster_name)', 'replies' => 't.num_replies', 'views' => 't.num_views', 'first_post' => 't.id_topic', 'last_post' => 't.id_last_msg');
    // The default is the most logical: newest first.
    if (!isset($_REQUEST['sort']) || !isset($sort_methods[$_REQUEST['sort']])) {
        $context['sort_by'] = 'last_post';
        $_REQUEST['sort'] = 't.id_last_msg';
        $ascending = isset($_REQUEST['asc']);
        $context['querystring_sort_limits'] = $ascending ? ';asc' : '';
    } else {
        $context['sort_by'] = $_REQUEST['sort'];
        $_REQUEST['sort'] = $sort_methods[$_REQUEST['sort']];
        $ascending = !isset($_REQUEST['desc']);
        $context['querystring_sort_limits'] = ';sort=' . $context['sort_by'] . ($ascending ? '' : ';desc');
    }
    $context['sort_direction'] = $ascending ? 'up' : 'down';
    if (!empty($_REQUEST['c']) && is_array($_REQUEST['c']) && count($_REQUEST['c']) == 1) {
        $request = $smcFunc['db_query']('', '
			SELECT name
			FROM {db_prefix}categories
			WHERE id_cat = {int:id_cat}
			LIMIT 1', array('id_cat' => (int) $_REQUEST['c'][0]));
        list($name) = $smcFunc['db_fetch_row']($request);
        $smcFunc['db_free_result']($request);
        $context['linktree'][] = array('url' => $scripturl . '#c' . (int) $_REQUEST['c'][0], 'name' => $name);
    }
    $context['linktree'][] = array('url' => $scripturl . '?action=' . $_REQUEST['action'] . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits'], 'name' => $_REQUEST['action'] == 'unread' ? $txt['unread_topics_visit'] : $txt['unread_replies']);
    if ($context['showing_all_topics']) {
        $context['linktree'][] = array('url' => $scripturl . '?action=' . $_REQUEST['action'] . ';all' . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits'], 'name' => $txt['unread_topics_all']);
    } else {
        $txt['unread_topics_visit_none'] = strtr($txt['unread_topics_visit_none'], array('?action=unread;all' => '?action=unread;all' . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits']));
    }
    if (WIRELESS) {
        $context['sub_template'] = WIRELESS_PROTOCOL . '_recent';
    } else {
        loadTemplate('Recent');
        $context['sub_template'] = $_REQUEST['action'] == 'unread' ? 'unread' : 'replies';
    }
    // Setup the default topic icons... for checking they exist and the like ;)
    $stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'moved', 'recycled', 'wireless', 'clip');
    $context['icon_sources'] = array();
    foreach ($stable_icons as $icon) {
        $context['icon_sources'][$icon] = 'images_url';
    }
    $is_topics = $_REQUEST['action'] == 'unread';
    // This part is the same for each query.
    $select_clause = '
				ms.subject AS first_subject, ms.poster_time AS first_poster_time, ms.id_topic, t.id_board, b.name AS bname,
				t.num_replies, t.num_views, ms.id_member AS id_first_member, ml.id_member AS id_last_member,
				ml.poster_time AS last_poster_time, IFNULL(mems.real_name, ms.poster_name) AS first_poster_name,
				IFNULL(meml.real_name, ml.poster_name) AS last_poster_name, ml.subject AS last_subject,
				ml.icon AS last_icon, ms.icon AS first_icon, t.id_poll, t.is_sticky, t.locked, ml.modified_time AS last_modified_time,
				IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1 AS new_from, SUBSTRING(ml.body, 1, 385) AS last_body,
				SUBSTRING(ms.body, 1, 385) AS first_body, ml.smileys_enabled AS last_smileys, ms.smileys_enabled AS first_smileys, t.id_first_msg, t.id_last_msg';
    if ($context['showing_all_topics']) {
        if (!empty($board)) {
            $request = $smcFunc['db_query']('', '
				SELECT MIN(id_msg)
				FROM {db_prefix}log_mark_read
				WHERE id_member = {int:current_member}
					AND id_board = {int:current_board}', array('current_board' => $board, 'current_member' => $user_info['id']));
            list($earliest_msg) = $smcFunc['db_fetch_row']($request);
            $smcFunc['db_free_result']($request);
        } else {
            $request = $smcFunc['db_query']('', '
				SELECT MIN(lmr.id_msg)
				FROM {db_prefix}boards AS b
					LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = b.id_board AND lmr.id_member = {int:current_member})
				WHERE {query_see_board}', array('current_member' => $user_info['id']));
            list($earliest_msg) = $smcFunc['db_fetch_row']($request);
            $smcFunc['db_free_result']($request);
        }
        // This is needed in case of topics marked unread.
        if (empty($earliest_msg)) {
            $earliest_msg = 0;
        } else {
            // Using caching, when possible, to ignore the below slow query.
            if (isset($_SESSION['cached_log_time']) && $_SESSION['cached_log_time'][0] + 45 > time()) {
                $earliest_msg2 = $_SESSION['cached_log_time'][1];
            } else {
                // This query is pretty slow, but it's needed to ensure nothing crucial is ignored.
                $request = $smcFunc['db_query']('', '
					SELECT MIN(id_msg)
					FROM {db_prefix}log_topics
					WHERE id_member = {int:current_member}', array('current_member' => $user_info['id']));
                list($earliest_msg2) = $smcFunc['db_fetch_row']($request);
                $smcFunc['db_free_result']($request);
                // In theory this could be zero, if the first ever post is unread, so fudge it ;)
                if ($earliest_msg2 == 0) {
                    $earliest_msg2 = -1;
                }
                $_SESSION['cached_log_time'] = array(time(), $earliest_msg2);
            }
            $earliest_msg = min($earliest_msg2, $earliest_msg);
        }
    }
    // !!! Add modified_time in for log_time check?
    if ($modSettings['totalMessages'] > 100000 && $context['showing_all_topics']) {
        $smcFunc['db_query']('', '
			DROP TABLE IF EXISTS {db_prefix}log_topics_unread', array());
        // Let's copy things out of the log_topics table, to reduce searching.
        $have_temp_table = $smcFunc['db_query']('', '
			CREATE TEMPORARY TABLE {db_prefix}log_topics_unread (
				PRIMARY KEY (id_topic)
			)
			SELECT lt.id_topic, lt.id_msg
			FROM {db_prefix}topics AS t
				INNER JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic)
			WHERE lt.id_member = {int:current_member}
				AND t.' . $query_this_board . (empty($earliest_msg) ? '' : '
				AND t.id_last_msg > {int:earliest_msg}') . ($modSettings['postmod_active'] ? '
				AND t.approved = {int:is_approved}' : ''), array_merge($query_parameters, array('current_member' => $user_info['id'], 'earliest_msg' => !empty($earliest_msg) ? $earliest_msg : 0, 'is_approved' => 1, 'db_error_skip' => true))) !== false;
    } else {
        $have_temp_table = false;
    }
    if ($context['showing_all_topics'] && $have_temp_table) {
        $request = $smcFunc['db_query']('', '
			SELECT COUNT(*), MIN(t.id_last_msg)
			FROM {db_prefix}topics AS t
				LEFT JOIN {db_prefix}log_topics_unread AS lt ON (lt.id_topic = t.id_topic)
				LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})
			WHERE t.' . $query_this_board . (!empty($earliest_msg) ? '
				AND t.id_last_msg > {int:earliest_msg}' : '') . '
				AND IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0)) < t.id_last_msg' . ($modSettings['postmod_active'] ? '
				AND t.approved = {int:is_approved}' : ''), array_merge($query_parameters, array('current_member' => $user_info['id'], 'earliest_msg' => !empty($earliest_msg) ? $earliest_msg : 0, 'is_approved' => 1)));
        list($num_topics, $min_message) = $smcFunc['db_fetch_row']($request);
        $smcFunc['db_free_result']($request);
        // Make sure the starting place makes sense and construct the page index.
        $context['page_index'] = constructPageIndex($scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . $context['querystring_board_limits'] . $context['querystring_sort_limits'], $_REQUEST['start'], $num_topics, $context['topics_per_page'], true);
        $context['current_page'] = (int) $_REQUEST['start'] / $context['topics_per_page'];
        $context['links'] = array('first' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits'] : '', 'prev' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] - $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'next' => $_REQUEST['start'] + $context['topics_per_page'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] + $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'last' => $_REQUEST['start'] + $context['topics_per_page'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], floor(($num_topics - 1) / $context['topics_per_page']) * $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'up' => $scripturl);
        $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['topics_per_page'] + 1, 'num_pages' => floor(($num_topics - 1) / $context['topics_per_page']) + 1);
        if ($num_topics == 0) {
            // Mark the boards as read if there are no unread topics!
            require_once $sourcedir . '/Subs-Boards.php';
            markBoardsRead(empty($boards) ? $board : $boards);
            $context['topics'] = array();
            if ($context['querystring_board_limits'] == ';start=%1$d') {
                $context['querystring_board_limits'] = '';
            } else {
                $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']);
            }
            return;
        } else {
            $min_message = (int) $min_message;
        }
        $request = $smcFunc['db_query']('substring', '
			SELECT ' . $select_clause . '
			FROM {db_prefix}messages AS ms
				INNER JOIN {db_prefix}topics AS t ON (t.id_topic = ms.id_topic AND t.id_first_msg = ms.id_msg)
				INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
				LEFT JOIN {db_prefix}boards AS b ON (b.id_board = ms.id_board)
				LEFT JOIN {db_prefix}members AS mems ON (mems.id_member = ms.id_member)
				LEFT JOIN {db_prefix}members AS meml ON (meml.id_member = ml.id_member)
				LEFT JOIN {db_prefix}log_topics_unread AS lt ON (lt.id_topic = t.id_topic)
				LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})
			WHERE b.' . $query_this_board . '
				AND t.id_last_msg >= {int:min_message}
				AND IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0)) < t.id_last_msg' . ($modSettings['postmod_active'] ? '
				AND ms.approved = {int:is_approved}' : '') . '
			ORDER BY {raw:sort}
			LIMIT {int:offset}, {int:limit}', array_merge($query_parameters, array('current_member' => $user_info['id'], 'min_message' => $min_message, 'is_approved' => 1, 'sort' => $_REQUEST['sort'] . ($ascending ? '' : ' DESC'), 'offset' => $_REQUEST['start'], 'limit' => $context['topics_per_page'])));
    } elseif ($is_topics) {
        $request = $smcFunc['db_query']('', '
			SELECT COUNT(*), MIN(t.id_last_msg)
			FROM {db_prefix}topics AS t' . (!empty($have_temp_table) ? '
				LEFT JOIN {db_prefix}log_topics_unread AS lt ON (lt.id_topic = t.id_topic)' : '
				LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})') . '
				LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})
			WHERE t.' . $query_this_board . ($context['showing_all_topics'] && !empty($earliest_msg) ? '
				AND t.id_last_msg > {int:earliest_msg}' : (!$context['showing_all_topics'] && empty($_SESSION['first_login']) ? '
				AND t.id_last_msg > {int:id_msg_last_visit}' : '')) . '
				AND IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0)) < t.id_last_msg' . ($modSettings['postmod_active'] ? '
				AND t.approved = {int:is_approved}' : ''), array_merge($query_parameters, array('current_member' => $user_info['id'], 'earliest_msg' => !empty($earliest_msg) ? $earliest_msg : 0, 'id_msg_last_visit' => $_SESSION['id_msg_last_visit'], 'is_approved' => 1)));
        list($num_topics, $min_message) = $smcFunc['db_fetch_row']($request);
        $smcFunc['db_free_result']($request);
        // Make sure the starting place makes sense and construct the page index.
        $context['page_index'] = constructPageIndex($scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . $context['querystring_board_limits'] . $context['querystring_sort_limits'], $_REQUEST['start'], $num_topics, $context['topics_per_page'], true);
        $context['current_page'] = (int) $_REQUEST['start'] / $context['topics_per_page'];
        $context['links'] = array('first' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits'] : '', 'prev' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] - $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'next' => $_REQUEST['start'] + $context['topics_per_page'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] + $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'last' => $_REQUEST['start'] + $context['topics_per_page'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], floor(($num_topics - 1) / $context['topics_per_page']) * $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'up' => $scripturl);
        $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['topics_per_page'] + 1, 'num_pages' => floor(($num_topics - 1) / $context['topics_per_page']) + 1);
        if ($num_topics == 0) {
            // Is this an all topics query?
            if ($context['showing_all_topics']) {
                // Since there are no unread topics, mark the boards as read!
                require_once $sourcedir . '/Subs-Boards.php';
                markBoardsRead(empty($boards) ? $board : $boards);
            }
            $context['topics'] = array();
            if ($context['querystring_board_limits'] == ';start=%d') {
                $context['querystring_board_limits'] = '';
            } else {
                $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']);
            }
            return;
        } else {
            $min_message = (int) $min_message;
        }
        $request = $smcFunc['db_query']('substring', '
			SELECT ' . $select_clause . '
			FROM {db_prefix}messages AS ms
				INNER JOIN {db_prefix}topics AS t ON (t.id_topic = ms.id_topic AND t.id_first_msg = ms.id_msg)
				INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
				LEFT JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
				LEFT JOIN {db_prefix}members AS mems ON (mems.id_member = ms.id_member)
				LEFT JOIN {db_prefix}members AS meml ON (meml.id_member = ml.id_member)' . (!empty($have_temp_table) ? '
				LEFT JOIN {db_prefix}log_topics_unread AS lt ON (lt.id_topic = t.id_topic)' : '
				LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})') . '
				LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})
			WHERE t.' . $query_this_board . '
				AND t.id_last_msg >= {int:min_message}
				AND IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0)) < ml.id_msg' . ($modSettings['postmod_active'] ? '
				AND ms.approved = {int:is_approved}' : '') . '
			ORDER BY {raw:order}
			LIMIT {int:offset}, {int:limit}', array_merge($query_parameters, array('current_member' => $user_info['id'], 'min_message' => $min_message, 'is_approved' => 1, 'order' => $_REQUEST['sort'] . ($ascending ? '' : ' DESC'), 'offset' => $_REQUEST['start'], 'limit' => $context['topics_per_page'])));
    } else {
        if ($modSettings['totalMessages'] > 100000) {
            $smcFunc['db_query']('', '
				DROP TABLE IF EXISTS {db_prefix}topics_posted_in', array());
            $smcFunc['db_query']('', '
				DROP TABLE IF EXISTS {db_prefix}log_topics_posted_in', array());
            $sortKey_joins = array('ms.subject' => '
					INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg)', 'IFNULL(mems.real_name, ms.poster_name)' => '
					INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg)
					LEFT JOIN {db_prefix}members AS mems ON (mems.id_member = ms.id_member)');
            // The main benefit of this temporary table is not that it's faster; it's that it avoids locks later.
            $have_temp_table = $smcFunc['db_query']('', '
				CREATE TEMPORARY TABLE {db_prefix}topics_posted_in (
					id_topic mediumint(8) unsigned NOT NULL default {string:string_zero},
					id_board smallint(5) unsigned NOT NULL default {string:string_zero},
					id_last_msg int(10) unsigned NOT NULL default {string:string_zero},
					id_msg int(10) unsigned NOT NULL default {string:string_zero},
					PRIMARY KEY (id_topic)
				)
				SELECT t.id_topic, t.id_board, t.id_last_msg, IFNULL(lmr.id_msg, 0) AS id_msg' . (!in_array($_REQUEST['sort'], array('t.id_last_msg', 't.id_topic')) ? ', ' . $_REQUEST['sort'] . ' AS sort_key' : '') . '
				FROM {db_prefix}messages AS m
					INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)
					LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})' . (isset($sortKey_joins[$_REQUEST['sort']]) ? $sortKey_joins[$_REQUEST['sort']] : '') . '
				WHERE m.id_member = {int:current_member}' . (!empty($board) ? '
					AND t.id_board = {int:current_board}' : '') . ($modSettings['postmod_active'] ? '
					AND t.approved = {int:is_approved}' : '') . '
				GROUP BY m.id_topic', array('current_board' => $board, 'current_member' => $user_info['id'], 'is_approved' => 1, 'string_zero' => '0', 'db_error_skip' => true)) !== false;
            // If that worked, create a sample of the log_topics table too.
            if ($have_temp_table) {
                $have_temp_table = $smcFunc['db_query']('', '
					CREATE TEMPORARY TABLE {db_prefix}log_topics_posted_in (
						PRIMARY KEY (id_topic)
					)
					SELECT lt.id_topic, lt.id_msg
					FROM {db_prefix}log_topics AS lt
						INNER JOIN {db_prefix}topics_posted_in AS pi ON (pi.id_topic = lt.id_topic)
					WHERE lt.id_member = {int:current_member}', array('current_member' => $user_info['id'], 'db_error_skip' => true)) !== false;
            }
        }
        if (!empty($have_temp_table)) {
            $request = $smcFunc['db_query']('', '
				SELECT COUNT(*)
				FROM {db_prefix}topics_posted_in AS pi
					LEFT JOIN {db_prefix}log_topics_posted_in AS lt ON (lt.id_topic = pi.id_topic)
				WHERE pi.' . $query_this_board . '
					AND IFNULL(lt.id_msg, pi.id_msg) < pi.id_last_msg', array_merge($query_parameters, array()));
            list($num_topics) = $smcFunc['db_fetch_row']($request);
            $smcFunc['db_free_result']($request);
        } else {
            $request = $smcFunc['db_query']('unread_fetch_topic_count', '
				SELECT COUNT(DISTINCT t.id_topic), MIN(t.id_last_msg)
				FROM {db_prefix}topics AS t
					INNER JOIN {db_prefix}messages AS m ON (m.id_topic = t.id_topic)
					LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})
					LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})
				WHERE t.' . $query_this_board . '
					AND m.id_member = {int:current_member}
					AND IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0)) < t.id_last_msg' . ($modSettings['postmod_active'] ? '
					AND t.approved = {int:is_approved}' : ''), array_merge($query_parameters, array('current_member' => $user_info['id'], 'is_approved' => 1)));
            list($num_topics, $min_message) = $smcFunc['db_fetch_row']($request);
            $smcFunc['db_free_result']($request);
        }
        // Make sure the starting place makes sense and construct the page index.
        $context['page_index'] = constructPageIndex($scripturl . '?action=' . $_REQUEST['action'] . $context['querystring_board_limits'] . $context['querystring_sort_limits'], $_REQUEST['start'], $num_topics, $context['topics_per_page'], true);
        $context['current_page'] = (int) $_REQUEST['start'] / $context['topics_per_page'];
        $context['links'] = array('first' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits'] : '', 'prev' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] - $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'next' => $_REQUEST['start'] + $context['topics_per_page'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] + $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'last' => $_REQUEST['start'] + $context['topics_per_page'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], floor(($num_topics - 1) / $context['topics_per_page']) * $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'up' => $scripturl);
        $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['topics_per_page'] + 1, 'num_pages' => floor(($num_topics - 1) / $context['topics_per_page']) + 1);
        if ($num_topics == 0) {
            $context['topics'] = array();
            if ($context['querystring_board_limits'] == ';start=%d') {
                $context['querystring_board_limits'] = '';
            } else {
                $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']);
            }
            return;
        }
        if (!empty($have_temp_table)) {
            $request = $smcFunc['db_query']('', '
				SELECT t.id_topic
				FROM {db_prefix}topics_posted_in AS t
					LEFT JOIN {db_prefix}log_topics_posted_in AS lt ON (lt.id_topic = t.id_topic)
				WHERE t.' . $query_this_board . '
					AND IFNULL(lt.id_msg, t.id_msg) < t.id_last_msg
				ORDER BY {raw:order}
				LIMIT {int:offset}, {int:limit}', array_merge($query_parameters, array('order' => (in_array($_REQUEST['sort'], array('t.id_last_msg', 't.id_topic')) ? $_REQUEST['sort'] : 't.sort_key') . ($ascending ? '' : ' DESC'), 'offset' => $_REQUEST['start'], 'limit' => $context['topics_per_page'])));
        } else {
            $request = $smcFunc['db_query']('unread_replies', '
				SELECT DISTINCT t.id_topic
				FROM {db_prefix}topics AS t
					INNER JOIN {db_prefix}messages AS m ON (m.id_topic = t.id_topic AND m.id_member = {int:current_member})' . (strpos($_REQUEST['sort'], 'ms.') === false ? '' : '
					INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg)') . (strpos($_REQUEST['sort'], 'mems.') === false ? '' : '
					LEFT JOIN {db_prefix}members AS mems ON (mems.id_member = ms.id_member)') . '
					LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})
					LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})
				WHERE t.' . $query_this_board . '
					AND t.id_last_msg >= {int:min_message}
					AND (IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0))) < t.id_last_msg
					AND t.approved = {int:is_approved}
				ORDER BY {raw:order}
				LIMIT {int:offset}, {int:limit}', array_merge($query_parameters, array('current_member' => $user_info['id'], 'min_message' => (int) $min_message, 'is_approved' => 1, 'order' => $_REQUEST['sort'] . ($ascending ? '' : ' DESC'), 'offset' => $_REQUEST['start'], 'limit' => $context['topics_per_page'], 'sort' => $_REQUEST['sort'])));
        }
        $topics = array();
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            $topics[] = $row['id_topic'];
        }
        $smcFunc['db_free_result']($request);
        // Sanity... where have you gone?
        if (empty($topics)) {
            $context['topics'] = array();
            if ($context['querystring_board_limits'] == ';start=%d') {
                $context['querystring_board_limits'] = '';
            } else {
                $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']);
            }
            return;
        }
        $request = $smcFunc['db_query']('substring', '
			SELECT ' . $select_clause . '
			FROM {db_prefix}topics AS t
				INNER JOIN {db_prefix}messages AS ms ON (ms.id_topic = t.id_topic AND ms.id_msg = t.id_first_msg)
				INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
				INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
				LEFT JOIN {db_prefix}members AS mems ON (mems.id_member = ms.id_member)
				LEFT JOIN {db_prefix}members AS meml ON (meml.id_member = ml.id_member)
				LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})
				LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})
			WHERE t.id_topic IN ({array_int:topic_list})
			ORDER BY ' . $_REQUEST['sort'] . ($ascending ? '' : ' DESC') . '
			LIMIT ' . count($topics), array('current_member' => $user_info['id'], 'topic_list' => $topics));
    }
    $context['topics'] = array();
    $topic_ids = array();
    while ($row = $smcFunc['db_fetch_assoc']($request)) {
        if ($row['id_poll'] > 0 && $modSettings['pollMode'] == '0') {
            continue;
        }
        $topic_ids[] = $row['id_topic'];
        if (!empty($settings['message_index_preview'])) {
            // Limit them to 128 characters - do this FIRST because it's a lot of wasted censoring otherwise.
            $row['first_body'] = strip_tags(strtr(parse_bbc($row['first_body'], $row['first_smileys'], $row['id_first_msg']), array('<br />' => '&#10;')));
            if ($smcFunc['strlen']($row['first_body']) > 128) {
                $row['first_body'] = $smcFunc['substr']($row['first_body'], 0, 128) . '...';
            }
            $row['last_body'] = strip_tags(strtr(parse_bbc($row['last_body'], $row['last_smileys'], $row['id_last_msg']), array('<br />' => '&#10;')));
            if ($smcFunc['strlen']($row['last_body']) > 128) {
                $row['last_body'] = $smcFunc['substr']($row['last_body'], 0, 128) . '...';
            }
            // Censor the subject and message preview.
            censorText($row['first_subject']);
            censorText($row['first_body']);
            // Don't censor them twice!
            if ($row['id_first_msg'] == $row['id_last_msg']) {
                $row['last_subject'] = $row['first_subject'];
                $row['last_body'] = $row['first_body'];
            } else {
                censorText($row['last_subject']);
                censorText($row['last_body']);
            }
        } else {
            $row['first_body'] = '';
            $row['last_body'] = '';
            censorText($row['first_subject']);
            if ($row['id_first_msg'] == $row['id_last_msg']) {
                $row['last_subject'] = $row['first_subject'];
            } else {
                censorText($row['last_subject']);
            }
        }
        // Decide how many pages the topic should have.
        $topic_length = $row['num_replies'] + 1;
        $messages_per_page = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) && !WIRELESS ? $options['messages_per_page'] : $modSettings['defaultMaxMessages'];
        if ($topic_length > $messages_per_page) {
            $tmppages = array();
            $tmpa = 1;
            for ($tmpb = 0; $tmpb < $topic_length; $tmpb += $messages_per_page) {
                $tmppages[] = '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.' . $tmpb . ';topicseen">' . $tmpa . '</a>';
                $tmpa++;
            }
            // Show links to all the pages?
            if (count($tmppages) <= 5) {
                $pages = '&#171; ' . implode(' ', $tmppages);
            } else {
                $pages = '&#171; ' . $tmppages[0] . ' ' . $tmppages[1] . ' ... ' . $tmppages[count($tmppages) - 2] . ' ' . $tmppages[count($tmppages) - 1];
            }
            if (!empty($modSettings['enableAllMessages']) && $topic_length < $modSettings['enableAllMessages']) {
                $pages .= ' &nbsp;<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0;all">' . $txt['all'] . '</a>';
            }
            $pages .= ' &#187;';
        } else {
            $pages = '';
        }
        // We need to check the topic icons exist... you can never be too sure!
        if (empty($modSettings['messageIconChecks_disable'])) {
            // First icon first... as you'd expect.
            if (!isset($context['icon_sources'][$row['first_icon']])) {
                $context['icon_sources'][$row['first_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['first_icon'] . '.gif') ? 'images_url' : 'default_images_url';
            }
            // Last icon... last... duh.
            if (!isset($context['icon_sources'][$row['last_icon']])) {
                $context['icon_sources'][$row['last_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['last_icon'] . '.gif') ? 'images_url' : 'default_images_url';
            }
        }
        // And build the array.
        $context['topics'][$row['id_topic']] = array('id' => $row['id_topic'], 'first_post' => array('id' => $row['id_first_msg'], 'member' => array('name' => $row['first_poster_name'], 'id' => $row['id_first_member'], 'href' => $scripturl . '?action=profile;u=' . $row['id_first_member'], 'link' => !empty($row['id_first_member']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_first_member'] . '" title="' . $txt['profile_of'] . ' ' . $row['first_poster_name'] . '">' . $row['first_poster_name'] . '</a>' : $row['first_poster_name']), 'time' => timeformat($row['first_poster_time']), 'timestamp' => forum_time(true, $row['first_poster_time']), 'subject' => $row['first_subject'], 'preview' => $row['first_body'], 'icon' => $row['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['first_icon']]] . '/post/' . $row['first_icon'] . '.gif', 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.0;topicseen', 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0;topicseen">' . $row['first_subject'] . '</a>'), 'last_post' => array('id' => $row['id_last_msg'], 'member' => array('name' => $row['last_poster_name'], 'id' => $row['id_last_member'], 'href' => $scripturl . '?action=profile;u=' . $row['id_last_member'], 'link' => !empty($row['id_last_member']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_last_member'] . '">' . $row['last_poster_name'] . '</a>' : $row['last_poster_name']), 'time' => timeformat($row['last_poster_time']), 'timestamp' => forum_time(true, $row['last_poster_time']), 'subject' => $row['last_subject'], 'preview' => $row['last_body'], 'icon' => $row['last_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['last_icon']]] . '/post/' . $row['last_icon'] . '.gif', 'href' => $scripturl . '?topic=' . $row['id_topic'] . ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['id_last_msg']) . ';topicseen#msg' . $row['id_last_msg'], 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['id_last_msg']) . ';topicseen#msg' . $row['id_last_msg'] . '" rel="nofollow">' . $row['last_subject'] . '</a>'), 'new_from' => $row['new_from'], 'new_href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['new_from'] . ';topicseen#new', 'href' => $scripturl . '?topic=' . $row['id_topic'] . ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['new_from']) . ';topicseen' . ($row['num_replies'] == 0 ? '' : 'new'), 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['new_from']) . ';topicseen#msg' . $row['new_from'] . '" rel="nofollow">' . $row['first_subject'] . '</a>', 'is_sticky' => !empty($modSettings['enableStickyTopics']) && !empty($row['is_sticky']), 'is_locked' => !empty($row['locked']), 'is_poll' => $modSettings['pollMode'] == '1' && $row['id_poll'] > 0, 'is_hot' => $row['num_replies'] >= $modSettings['hotTopicPosts'], 'is_very_hot' => $row['num_replies'] >= $modSettings['hotTopicVeryPosts'], 'is_posted_in' => false, 'icon' => $row['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['first_icon']]] . '/post/' . $row['first_icon'] . '.gif', 'subject' => $row['first_subject'], 'pages' => $pages, 'replies' => comma_format($row['num_replies']), 'views' => comma_format($row['num_views']), 'board' => array('id' => $row['id_board'], 'name' => $row['bname'], 'href' => $scripturl . '?board=' . $row['id_board'] . '.0', 'link' => '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['bname'] . '</a>'));
        determineTopicClass($context['topics'][$row['id_topic']]);
    }
    $smcFunc['db_free_result']($request);
    if ($is_topics && !empty($modSettings['enableParticipation']) && !empty($topic_ids)) {
        $result = $smcFunc['db_query']('', '
			SELECT id_topic
			FROM {db_prefix}messages
			WHERE id_topic IN ({array_int:topic_list})
				AND id_member = {int:current_member}
			GROUP BY id_topic
			LIMIT {int:limit}', array('current_member' => $user_info['id'], 'topic_list' => $topic_ids, 'limit' => count($topic_ids)));
        while ($row = $smcFunc['db_fetch_assoc']($result)) {
            if (empty($context['topics'][$row['id_topic']]['is_posted_in'])) {
                $context['topics'][$row['id_topic']]['is_posted_in'] = true;
                $context['topics'][$row['id_topic']]['class'] = 'my_' . $context['topics'][$row['id_topic']]['class'];
            }
        }
        $smcFunc['db_free_result']($result);
    }
    $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']);
    $context['topics_to_mark'] = implode('-', $topic_ids);
}
Esempio n. 7
0
    /**
     * The central part of the board - topic display.
     *
     * What it does:
     * - This function loads the posts in a topic up so they can be displayed.
     * - It uses the main sub template of the Display template.
     * - It requires a topic, and can go to the previous or next topic from it.
     * - It jumps to the correct post depending on a number/time/IS_MSG passed.
     * - It depends on the messages_per_page, defaultMaxMessages and enableAllMessages settings.
     * - It is accessed by ?topic=id_topic.START.
     */
    public function action_display()
    {
        global $scripturl, $txt, $modSettings, $context, $settings;
        global $options, $user_info, $board_info, $topic, $board;
        global $attachments, $messages_request;
        // What are you gonna display if these are empty?!
        if (empty($topic)) {
            fatal_lang_error('no_board', false);
        }
        // Load the template
        loadTemplate('Display');
        $context['sub_template'] = 'messages';
        // And the topic functions
        require_once SUBSDIR . '/Topic.subs.php';
        require_once SUBSDIR . '/Messages.subs.php';
        // Not only does a prefetch make things slower for the server, but it makes it impossible to know if they read it.
        if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') {
            @ob_end_clean();
            header('HTTP/1.1 403 Prefetch Forbidden');
            die;
        }
        // How much are we sticking on each page?
        $context['messages_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) ? $options['messages_per_page'] : $modSettings['defaultMaxMessages'];
        $template_layers = Template_Layers::getInstance();
        $template_layers->addEnd('messages_informations');
        $includeUnapproved = !$modSettings['postmod_active'] || allowedTo('approve_posts');
        // Let's do some work on what to search index.
        if (count($_GET) > 2) {
            foreach ($_GET as $k => $v) {
                if (!in_array($k, array('topic', 'board', 'start', session_name()))) {
                    $context['robot_no_index'] = true;
                }
            }
        }
        if (!empty($_REQUEST['start']) && (!is_numeric($_REQUEST['start']) || $_REQUEST['start'] % $context['messages_per_page'] != 0)) {
            $context['robot_no_index'] = true;
        }
        // Find the previous or next topic.  Make a fuss if there are no more.
        if (isset($_REQUEST['prev_next']) && ($_REQUEST['prev_next'] == 'prev' || $_REQUEST['prev_next'] == 'next')) {
            // No use in calculating the next topic if there's only one.
            if ($board_info['num_topics'] > 1) {
                $includeStickies = !empty($modSettings['enableStickyTopics']);
                $topic = $_REQUEST['prev_next'] === 'prev' ? previousTopic($topic, $board, $user_info['id'], $includeUnapproved, $includeStickies) : nextTopic($topic, $board, $user_info['id'], $includeUnapproved, $includeStickies);
                $context['current_topic'] = $topic;
            }
            // Go to the newest message on this topic.
            $_REQUEST['start'] = 'new';
        }
        // Add 1 to the number of views of this topic (except for robots).
        if (!$user_info['possibly_robot'] && (empty($_SESSION['last_read_topic']) || $_SESSION['last_read_topic'] != $topic)) {
            increaseViewCounter($topic);
            $_SESSION['last_read_topic'] = $topic;
        }
        $topic_selects = array();
        $topic_tables = array();
        $topic_parameters = array('topic' => $topic, 'member' => $user_info['id'], 'board' => (int) $board);
        // Allow addons to add additional details to the topic query
        call_integration_hook('integrate_topic_query', array(&$topic_selects, &$topic_tables, &$topic_parameters));
        // Load the topic details
        $topicinfo = getTopicInfo($topic_parameters, 'all', $topic_selects, $topic_tables);
        if (empty($topicinfo)) {
            fatal_lang_error('not_a_topic', false);
        }
        // Is this a moved topic that we are redirecting to?
        if (!empty($topicinfo['id_redirect_topic']) && !isset($_GET['noredir'])) {
            markTopicsRead(array($user_info['id'], $topic, $topicinfo['id_last_msg'], 0), $topicinfo['new_from'] !== 0);
            redirectexit('topic=' . $topicinfo['id_redirect_topic'] . '.0;redirfrom=' . $topicinfo['id_topic']);
        }
        $context['real_num_replies'] = $context['num_replies'] = $topicinfo['num_replies'];
        $context['topic_first_message'] = $topicinfo['id_first_msg'];
        $context['topic_last_message'] = $topicinfo['id_last_msg'];
        $context['topic_unwatched'] = isset($topicinfo['unwatched']) ? $topicinfo['unwatched'] : 0;
        if (isset($_GET['redirfrom'])) {
            $redir_topics = topicsList(array((int) $_GET['redirfrom']));
            if (!empty($redir_topics[(int) $_GET['redirfrom']])) {
                $context['topic_redirected_from'] = $redir_topics[(int) $_GET['redirfrom']];
                $context['topic_redirected_from']['redir_href'] = $scripturl . '?topic=' . $context['topic_redirected_from']['id_topic'] . '.0;noredir';
            }
        }
        // Add up unapproved replies to get real number of replies...
        if ($modSettings['postmod_active'] && allowedTo('approve_posts')) {
            $context['real_num_replies'] += $topicinfo['unapproved_posts'] - ($topicinfo['approved'] ? 0 : 1);
        }
        // If this topic was derived from another, set the followup details
        if (!empty($topicinfo['derived_from'])) {
            require_once SUBSDIR . '/FollowUps.subs.php';
            $context['topic_derived_from'] = topicStartedHere($topic, $includeUnapproved);
        }
        // If this topic has unapproved posts, we need to work out how many posts the user can see, for page indexing.
        if (!$includeUnapproved && $topicinfo['unapproved_posts'] && !$user_info['is_guest']) {
            $myUnapprovedPosts = unapprovedPosts($topic, $user_info['id']);
            $context['total_visible_posts'] = $context['num_replies'] + $myUnapprovedPosts + ($topicinfo['approved'] ? 1 : 0);
        } elseif ($user_info['is_guest']) {
            $context['total_visible_posts'] = $context['num_replies'] + ($topicinfo['approved'] ? 1 : 0);
        } else {
            $context['total_visible_posts'] = $context['num_replies'] + $topicinfo['unapproved_posts'] + ($topicinfo['approved'] ? 1 : 0);
        }
        // When was the last time this topic was replied to?  Should we warn them about it?
        if (!empty($modSettings['oldTopicDays'])) {
            $mgsOptions = basicMessageInfo($topicinfo['id_last_msg'], true);
            $context['oldTopicError'] = $mgsOptions['poster_time'] + $modSettings['oldTopicDays'] * 86400 < time() && empty($topicinfo['is_sticky']);
        } else {
            $context['oldTopicError'] = false;
        }
        // The start isn't a number; it's information about what to do, where to go.
        if (!is_numeric($_REQUEST['start'])) {
            // Redirect to the page and post with new messages, originally by Omar Bazavilvazo.
            if ($_REQUEST['start'] == 'new') {
                // Guests automatically go to the last post.
                if ($user_info['is_guest']) {
                    $context['start_from'] = $context['total_visible_posts'] - 1;
                    $_REQUEST['start'] = $context['start_from'];
                } else {
                    // Fall through to the next if statement.
                    $_REQUEST['start'] = 'msg' . $topicinfo['new_from'];
                }
            }
            // Start from a certain time index, not a message.
            if (substr($_REQUEST['start'], 0, 4) == 'from') {
                $timestamp = (int) substr($_REQUEST['start'], 4);
                if ($timestamp === 0) {
                    $_REQUEST['start'] = 0;
                } else {
                    // Find the number of messages posted before said time...
                    $context['start_from'] = countNewPosts($topic, $topicinfo, $timestamp);
                    $_REQUEST['start'] = $context['start_from'];
                }
            } elseif (substr($_REQUEST['start'], 0, 3) == 'msg') {
                $virtual_msg = (int) substr($_REQUEST['start'], 3);
                if (!$topicinfo['unapproved_posts'] && $virtual_msg >= $topicinfo['id_last_msg']) {
                    $context['start_from'] = $context['total_visible_posts'] - 1;
                } elseif (!$topicinfo['unapproved_posts'] && $virtual_msg <= $topicinfo['id_first_msg']) {
                    $context['start_from'] = 0;
                } else {
                    $only_approved = $modSettings['postmod_active'] && $topicinfo['unapproved_posts'] && !allowedTo('approve_posts');
                    $context['start_from'] = countMessagesBefore($topic, $virtual_msg, false, $only_approved, !$user_info['is_guest']);
                }
                // We need to reverse the start as well in this case.
                $_REQUEST['start'] = $context['start_from'];
            }
        }
        // Mark the mention as read if requested
        if (isset($_REQUEST['mentionread']) && !empty($virtual_msg)) {
            require_once CONTROLLERDIR . '/Mentions.controller.php';
            $mentions = new Mentions_Controller();
            $mentions->setData(array('id_mention' => $_REQUEST['item'], 'mark' => $_REQUEST['mark']));
            $mentions->action_markread();
        }
        // Create a previous next string if the selected theme has it as a selected option.
        if ($modSettings['enablePreviousNext']) {
            $context['links'] += array('go_prev' => $scripturl . '?topic=' . $topic . '.0;prev_next=prev#new', 'go_next' => $scripturl . '?topic=' . $topic . '.0;prev_next=next#new');
        }
        // Derived from, set the link back
        if (!empty($context['topic_derived_from'])) {
            $context['links']['derived_from'] = $scripturl . '?msg=' . $context['topic_derived_from']['derived_from'];
        }
        // Check if spellchecking is both enabled and actually working. (for quick reply.)
        $context['show_spellchecking'] = !empty($modSettings['enableSpellChecking']) && function_exists('pspell_new');
        if ($context['show_spellchecking']) {
            loadJavascriptFile('spellcheck.js', array('defer' => true));
        }
        // Do we need to show the visual verification image?
        $context['require_verification'] = !$user_info['is_mod'] && !$user_info['is_admin'] && !empty($modSettings['posts_require_captcha']) && ($user_info['posts'] < $modSettings['posts_require_captcha'] || $user_info['is_guest'] && $modSettings['posts_require_captcha'] == -1);
        if ($context['require_verification']) {
            require_once SUBSDIR . '/VerificationControls.class.php';
            $verificationOptions = array('id' => 'post');
            $context['require_verification'] = create_control_verification($verificationOptions);
            $context['visual_verification_id'] = $verificationOptions['id'];
        }
        // Are we showing signatures - or disabled fields?
        $context['signature_enabled'] = substr($modSettings['signature_settings'], 0, 1) == 1;
        $context['disabled_fields'] = isset($modSettings['disabled_profile_fields']) ? array_flip(explode(',', $modSettings['disabled_profile_fields'])) : array();
        // Censor the title...
        censorText($topicinfo['subject']);
        $context['page_title'] = $topicinfo['subject'];
        // Is this topic sticky, or can it even be?
        $topicinfo['is_sticky'] = empty($modSettings['enableStickyTopics']) ? '0' : $topicinfo['is_sticky'];
        // Allow addons access to the topicinfo array
        call_integration_hook('integrate_display_topic', array($topicinfo));
        // Default this topic to not marked for notifications... of course...
        $context['is_marked_notify'] = false;
        // Did we report a post to a moderator just now?
        $context['report_sent'] = isset($_GET['reportsent']);
        if ($context['report_sent']) {
            $template_layers->add('report_sent');
        }
        // Let's get nosey, who is viewing this topic?
        if (!empty($settings['display_who_viewing'])) {
            require_once SUBSDIR . '/Who.subs.php';
            formatViewers($topic, 'topic');
        }
        // If all is set, but not allowed... just unset it.
        $can_show_all = !empty($modSettings['enableAllMessages']) && $context['total_visible_posts'] > $context['messages_per_page'] && $context['total_visible_posts'] < $modSettings['enableAllMessages'];
        if (isset($_REQUEST['all']) && !$can_show_all) {
            unset($_REQUEST['all']);
        } elseif (isset($_REQUEST['all'])) {
            $_REQUEST['start'] = -1;
        }
        // Construct the page index, allowing for the .START method...
        $context['page_index'] = constructPageIndex($scripturl . '?topic=' . $topic . '.%1$d', $_REQUEST['start'], $context['total_visible_posts'], $context['messages_per_page'], true, array('all' => $can_show_all, 'all_selected' => isset($_REQUEST['all'])));
        $context['start'] = $_REQUEST['start'];
        // This is information about which page is current, and which page we're on - in case you don't like the constructed page index. (again, wireles..)
        $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['messages_per_page'] + 1, 'num_pages' => floor(($context['total_visible_posts'] - 1) / $context['messages_per_page']) + 1);
        // Figure out all the link to the next/prev
        $context['links'] += array('prev' => $_REQUEST['start'] >= $context['messages_per_page'] ? $scripturl . '?topic=' . $topic . '.' . ($_REQUEST['start'] - $context['messages_per_page']) : '', 'next' => $_REQUEST['start'] + $context['messages_per_page'] < $context['total_visible_posts'] ? $scripturl . '?topic=' . $topic . '.' . ($_REQUEST['start'] + $context['messages_per_page']) : '');
        // If they are viewing all the posts, show all the posts, otherwise limit the number.
        if ($can_show_all && isset($_REQUEST['all'])) {
            // No limit! (actually, there is a limit, but...)
            $context['messages_per_page'] = -1;
            // Set start back to 0...
            $_REQUEST['start'] = 0;
        }
        // Build the link tree.
        $context['linktree'][] = array('url' => $scripturl . '?topic=' . $topic . '.0', 'name' => $topicinfo['subject']);
        // Build a list of this board's moderators.
        $context['moderators'] =& $board_info['moderators'];
        $context['link_moderators'] = array();
        // Information about the current topic...
        $context['is_locked'] = $topicinfo['locked'];
        $context['is_sticky'] = $topicinfo['is_sticky'];
        $context['is_very_hot'] = $topicinfo['num_replies'] >= $modSettings['hotTopicVeryPosts'];
        $context['is_hot'] = $topicinfo['num_replies'] >= $modSettings['hotTopicPosts'];
        $context['is_approved'] = $topicinfo['approved'];
        $context['is_poll'] = $topicinfo['id_poll'] > 0 && !empty($modSettings['pollMode']) && allowedTo('poll_view');
        determineTopicClass($context);
        // Did this user start the topic or not?
        $context['user']['started'] = $user_info['id'] == $topicinfo['id_member_started'] && !$user_info['is_guest'];
        $context['topic_starter_id'] = $topicinfo['id_member_started'];
        // Set the topic's information for the template.
        $context['subject'] = $topicinfo['subject'];
        $context['num_views'] = $topicinfo['num_views'];
        $context['num_views_text'] = $context['num_views'] == 1 ? $txt['read_one_time'] : sprintf($txt['read_many_times'], $context['num_views']);
        $context['mark_unread_time'] = !empty($virtual_msg) ? $virtual_msg : $topicinfo['new_from'];
        // Set a canonical URL for this page.
        $context['canonical_url'] = $scripturl . '?topic=' . $topic . '.' . $context['start'];
        // For quick reply we need a response prefix in the default forum language.
        $context['response_prefix'] = response_prefix();
        // If we want to show event information in the topic, prepare the data.
        if (allowedTo('calendar_view') && !empty($modSettings['cal_showInTopic']) && !empty($modSettings['cal_enabled'])) {
            // We need events details and all that jazz
            require_once SUBSDIR . '/Calendar.subs.php';
            // First, try create a better time format, ignoring the "time" elements.
            if (preg_match('~%[AaBbCcDdeGghjmuYy](?:[^%]*%[AaBbCcDdeGghjmuYy])*~', $user_info['time_format'], $matches) == 0 || empty($matches[0])) {
                $date_string = $user_info['time_format'];
            } else {
                $date_string = $matches[0];
            }
            // Get event information for this topic.
            $events = eventInfoForTopic($topic);
            $context['linked_calendar_events'] = array();
            foreach ($events as $event) {
                // Prepare the dates for being formatted.
                $start_date = sscanf($event['start_date'], '%04d-%02d-%02d');
                $start_date = mktime(12, 0, 0, $start_date[1], $start_date[2], $start_date[0]);
                $end_date = sscanf($event['end_date'], '%04d-%02d-%02d');
                $end_date = mktime(12, 0, 0, $end_date[1], $end_date[2], $end_date[0]);
                $context['linked_calendar_events'][] = array('id' => $event['id_event'], 'title' => $event['title'], 'can_edit' => allowedTo('calendar_edit_any') || $event['id_member'] == $user_info['id'] && allowedTo('calendar_edit_own'), 'modify_href' => $scripturl . '?action=post;msg=' . $topicinfo['id_first_msg'] . ';topic=' . $topic . '.0;calendar;eventid=' . $event['id_event'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'can_export' => allowedTo('calendar_edit_any') || $event['id_member'] == $user_info['id'] && allowedTo('calendar_edit_own'), 'export_href' => $scripturl . '?action=calendar;sa=ical;eventid=' . $event['id_event'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'start_date' => standardTime($start_date, $date_string, 'none'), 'start_timestamp' => $start_date, 'end_date' => standardTime($end_date, $date_string, 'none'), 'end_timestamp' => $end_date, 'is_last' => false);
            }
            if (!empty($context['linked_calendar_events'])) {
                $context['linked_calendar_events'][count($context['linked_calendar_events']) - 1]['is_last'] = true;
                $template_layers->add('display_calendar');
            }
        }
        // Create the poll info if it exists.
        if ($context['is_poll']) {
            $template_layers->add('display_poll');
            require_once SUBSDIR . '/Poll.subs.php';
            loadPollContext($topicinfo['id_poll']);
            // Build the poll moderation button array.
            $context['poll_buttons'] = array('vote' => array('test' => 'allow_return_vote', 'text' => 'poll_return_vote', 'image' => 'poll_options.png', 'lang' => true, 'url' => $scripturl . '?topic=' . $context['current_topic'] . '.' . $context['start']), 'results' => array('test' => 'allow_poll_view', 'text' => 'poll_results', 'image' => 'poll_results.png', 'lang' => true, 'url' => $scripturl . '?topic=' . $context['current_topic'] . '.' . $context['start'] . ';viewresults'), 'change_vote' => array('test' => 'allow_change_vote', 'text' => 'poll_change_vote', 'image' => 'poll_change_vote.png', 'lang' => true, 'url' => $scripturl . '?action=poll;sa=vote;topic=' . $context['current_topic'] . '.' . $context['start'] . ';poll=' . $context['poll']['id'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'lock' => array('test' => 'allow_lock_poll', 'text' => !$context['poll']['is_locked'] ? 'poll_lock' : 'poll_unlock', 'image' => 'poll_lock.png', 'lang' => true, 'url' => $scripturl . '?action=lockvoting;topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'edit' => array('test' => 'allow_edit_poll', 'text' => 'poll_edit', 'image' => 'poll_edit.png', 'lang' => true, 'url' => $scripturl . '?action=editpoll;topic=' . $context['current_topic'] . '.' . $context['start']), 'remove_poll' => array('test' => 'can_remove_poll', 'text' => 'poll_remove', 'image' => 'admin_remove_poll.png', 'lang' => true, 'custom' => 'onclick="return confirm(\'' . $txt['poll_remove_warn'] . '\');"', 'url' => $scripturl . '?action=poll;sa=remove;topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']));
            // Allow mods to add additional buttons here
            call_integration_hook('integrate_poll_buttons');
        }
        // Calculate the fastest way to get the messages!
        $ascending = true;
        $start = $_REQUEST['start'];
        $limit = $context['messages_per_page'];
        $firstIndex = 0;
        if ($start >= $context['total_visible_posts'] / 2 && $context['messages_per_page'] != -1) {
            $ascending = !$ascending;
            $limit = $context['total_visible_posts'] <= $start + $limit ? $context['total_visible_posts'] - $start : $limit;
            $start = $context['total_visible_posts'] <= $start + $limit ? 0 : $context['total_visible_posts'] - $start - $limit;
            $firstIndex = $limit - 1;
        }
        // Taking care of member specific settings
        $limit_settings = array('messages_per_page' => $context['messages_per_page'], 'start' => $start, 'offset' => $limit);
        // Get each post and poster in this topic.
        $topic_details = getTopicsPostsAndPoster($topic, $limit_settings, $ascending);
        $messages = $topic_details['messages'];
        $posters = array_unique($topic_details['all_posters']);
        $all_posters = $topic_details['all_posters'];
        unset($topic_details);
        call_integration_hook('integrate_display_message_list', array(&$messages, &$posters));
        // Guests can't mark topics read or for notifications, just can't sorry.
        if (!$user_info['is_guest'] && !empty($messages)) {
            $mark_at_msg = max($messages);
            if ($mark_at_msg >= $topicinfo['id_last_msg']) {
                $mark_at_msg = $modSettings['maxMsgID'];
            }
            if ($mark_at_msg >= $topicinfo['new_from']) {
                markTopicsRead(array($user_info['id'], $topic, $mark_at_msg, $topicinfo['unwatched']), $topicinfo['new_from'] !== 0);
            }
            updateReadNotificationsFor($topic, $board);
            // Have we recently cached the number of new topics in this board, and it's still a lot?
            if (isset($_REQUEST['topicseen']) && isset($_SESSION['topicseen_cache'][$board]) && $_SESSION['topicseen_cache'][$board] > 5) {
                $_SESSION['topicseen_cache'][$board]--;
            } elseif (isset($_REQUEST['topicseen'])) {
                // Use the mark read tables... and the last visit to figure out if this should be read or not.
                $numNewTopics = getUnreadCountSince($board, empty($_SESSION['id_msg_last_visit']) ? 0 : $_SESSION['id_msg_last_visit']);
                // If there're no real new topics in this board, mark the board as seen.
                if (empty($numNewTopics)) {
                    $_REQUEST['boardseen'] = true;
                } else {
                    $_SESSION['topicseen_cache'][$board] = $numNewTopics;
                }
            } elseif (isset($_SESSION['topicseen_cache'][$board])) {
                $_SESSION['topicseen_cache'][$board]--;
            }
            // Mark board as seen if we came using last post link from BoardIndex. (or other places...)
            if (isset($_REQUEST['boardseen'])) {
                require_once SUBSDIR . '/Boards.subs.php';
                markBoardsRead($board, false, false);
            }
        }
        $attachments = array();
        // If there _are_ messages here... (probably an error otherwise :!)
        if (!empty($messages)) {
            require_once SUBSDIR . '/Attachments.subs.php';
            // Fetch attachments.
            $includeUnapproved = !$modSettings['postmod_active'] || allowedTo('approve_posts');
            if (!empty($modSettings['attachmentEnable']) && allowedTo('view_attachments')) {
                $attachments = getAttachments($messages, $includeUnapproved, 'filter_accessible_attachment', $all_posters);
            }
            $msg_parameters = array('message_list' => $messages, 'new_from' => $topicinfo['new_from']);
            $msg_selects = array();
            $msg_tables = array();
            call_integration_hook('integrate_message_query', array(&$msg_selects, &$msg_tables, &$msg_parameters));
            // What?  It's not like it *couldn't* be only guests in this topic...
            if (!empty($posters)) {
                loadMemberData($posters);
            }
            // Load in the likes for this group of messages
            if (!empty($modSettings['likes_enabled'])) {
                require_once SUBSDIR . '/Likes.subs.php';
                $context['likes'] = loadLikes($messages, true);
                // ajax controller for likes
                loadJavascriptFile('like_posts.js', array('defer' => true));
                loadLanguage('Errors');
                // Initiate likes and the tooltips for likes
                addInlineJavascript('
				$(document).ready(function () {
					var likePostInstance = likePosts.prototype.init({
						oTxt: ({
							btnText : ' . JavaScriptEscape($txt['ok_uppercase']) . ',
							likeHeadingError : ' . JavaScriptEscape($txt['like_heading_error']) . ',
							error_occurred : ' . JavaScriptEscape($txt['error_occurred']) . '
						}),
					});

					$(".like_button, .unlike_button").SiteTooltip({
						hoverIntent: {
							sensitivity: 10,
							interval: 150,
							timeout: 50
						}
					});
				});', true);
            }
            $messages_request = loadMessageRequest($msg_selects, $msg_tables, $msg_parameters);
            if (!empty($modSettings['enableFollowup'])) {
                require_once SUBSDIR . '/FollowUps.subs.php';
                $context['follow_ups'] = followupTopics($messages, $includeUnapproved);
            }
            // Go to the last message if the given time is beyond the time of the last message.
            if (isset($context['start_from']) && $context['start_from'] >= $topicinfo['num_replies']) {
                $context['start_from'] = $topicinfo['num_replies'];
            }
            // Since the anchor information is needed on the top of the page we load these variables beforehand.
            $context['first_message'] = isset($messages[$firstIndex]) ? $messages[$firstIndex] : $messages[0];
            $context['first_new_message'] = isset($context['start_from']) && $_REQUEST['start'] == $context['start_from'];
        } else {
            $messages_request = false;
            $context['first_message'] = 0;
            $context['first_new_message'] = false;
        }
        $context['jump_to'] = array('label' => addslashes(un_htmlspecialchars($txt['jump_to'])), 'board_name' => htmlspecialchars(strtr(strip_tags($board_info['name']), array('&amp;' => '&')), ENT_COMPAT, 'UTF-8'), 'child_level' => $board_info['child_level']);
        // Set the callback.  (do you REALIZE how much memory all the messages would take?!?)
        // This will be called from the template.
        $context['get_message'] = array($this, 'prepareDisplayContext_callback');
        // Now set all the wonderful, wonderful permissions... like moderation ones...
        $common_permissions = array('can_approve' => 'approve_posts', 'can_ban' => 'manage_bans', 'can_sticky' => 'make_sticky', 'can_merge' => 'merge_any', 'can_split' => 'split_any', 'calendar_post' => 'calendar_post', 'can_mark_notify' => 'mark_any_notify', 'can_send_topic' => 'send_topic', 'can_send_pm' => 'pm_send', 'can_send_email' => 'send_email_to_members', 'can_report_moderator' => 'report_any', 'can_moderate_forum' => 'moderate_forum', 'can_issue_warning' => 'issue_warning', 'can_restore_topic' => 'move_any', 'can_restore_msg' => 'move_any');
        foreach ($common_permissions as $contextual => $perm) {
            $context[$contextual] = allowedTo($perm);
        }
        // Permissions with _any/_own versions.  $context[YYY] => ZZZ_any/_own.
        $anyown_permissions = array('can_move' => 'move', 'can_lock' => 'lock', 'can_delete' => 'remove', 'can_add_poll' => 'poll_add', 'can_remove_poll' => 'poll_remove', 'can_reply' => 'post_reply', 'can_reply_unapproved' => 'post_unapproved_replies');
        foreach ($anyown_permissions as $contextual => $perm) {
            $context[$contextual] = allowedTo($perm . '_any') || $context['user']['started'] && allowedTo($perm . '_own');
        }
        // Cleanup all the permissions with extra stuff...
        $context['can_mark_notify'] &= !$context['user']['is_guest'];
        $context['can_sticky'] &= !empty($modSettings['enableStickyTopics']);
        $context['calendar_post'] &= !empty($modSettings['cal_enabled']) && (allowedTo('modify_any') || $context['user']['started'] && allowedTo('modify_own'));
        $context['can_add_poll'] &= !empty($modSettings['pollMode']) && $topicinfo['id_poll'] <= 0;
        $context['can_remove_poll'] &= !empty($modSettings['pollMode']) && $topicinfo['id_poll'] > 0;
        $context['can_reply'] &= empty($topicinfo['locked']) || allowedTo('moderate_board');
        $context['can_reply_unapproved'] &= $modSettings['postmod_active'] && (empty($topicinfo['locked']) || allowedTo('moderate_board'));
        $context['can_issue_warning'] &= in_array('w', $context['admin_features']) && !empty($modSettings['warning_enable']);
        // Handle approval flags...
        $context['can_reply_approved'] = $context['can_reply'];
        $context['can_reply'] |= $context['can_reply_unapproved'];
        $context['can_quote'] = $context['can_reply'] && (empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC'])));
        $context['can_mark_unread'] = !$user_info['is_guest'] && $settings['show_mark_read'];
        $context['can_unwatch'] = !$user_info['is_guest'] && $modSettings['enable_unwatch'];
        $context['can_send_topic'] = (!$modSettings['postmod_active'] || $topicinfo['approved']) && allowedTo('send_topic');
        $context['can_print'] = empty($modSettings['disable_print_topic']);
        // Start this off for quick moderation - it will be or'd for each post.
        $context['can_remove_post'] = allowedTo('delete_any') || allowedTo('delete_replies') && $context['user']['started'];
        // Can restore topic?  That's if the topic is in the recycle board and has a previous restore state.
        $context['can_restore_topic'] &= !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board && !empty($topicinfo['id_previous_board']);
        $context['can_restore_msg'] &= !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board && !empty($topicinfo['id_previous_topic']);
        $context['can_follow_up'] = !empty($modSettings['enableFollowup']) && boardsallowedto('post_new') !== array();
        // Check if the draft functions are enabled and that they have permission to use them (for quick reply.)
        $context['drafts_save'] = !empty($modSettings['drafts_enabled']) && !empty($modSettings['drafts_post_enabled']) && allowedTo('post_draft') && $context['can_reply'];
        $context['drafts_autosave'] = !empty($context['drafts_save']) && !empty($modSettings['drafts_autosave_enabled']) && allowedTo('post_autosave_draft');
        if (!empty($context['drafts_save'])) {
            loadLanguage('Drafts');
        }
        if (!empty($context['drafts_autosave']) && empty($options['use_editor_quick_reply'])) {
            loadJavascriptFile('drafts.js');
        }
        if (!empty($modSettings['mentions_enabled'])) {
            $context['mentions_enabled'] = true;
            // Just using the plain text quick reply and not the editor
            if (empty($options['use_editor_quick_reply'])) {
                loadJavascriptFile(array('jquery.atwho.js', 'jquery.caret.min.js', 'mentioning.js'));
            }
            loadCSSFile('jquery.atwho.css');
            addInlineJavascript('
			$(document).ready(function () {
				for (var i = 0, count = all_elk_mentions.length; i < count; i++)
					all_elk_mentions[i].oMention = new elk_mentions(all_elk_mentions[i].oOptions);
			});');
        }
        // Load up the Quick ModifyTopic and Quick Reply scripts
        loadJavascriptFile('topic.js');
        // Auto video embeding enabled?
        if (!empty($modSettings['enableVideoEmbeding'])) {
            addInlineJavascript('
		$(document).ready(function() {
			$().linkifyvideo(oEmbedtext);
		});');
        }
        // Load up the "double post" sequencing magic.
        if (!empty($options['display_quick_reply'])) {
            checkSubmitOnce('register');
            $context['name'] = isset($_SESSION['guest_name']) ? $_SESSION['guest_name'] : '';
            $context['email'] = isset($_SESSION['guest_email']) ? $_SESSION['guest_email'] : '';
            if (!empty($options['use_editor_quick_reply']) && $context['can_reply']) {
                // Needed for the editor and message icons.
                require_once SUBSDIR . '/Editor.subs.php';
                // Now create the editor.
                $editorOptions = array('id' => 'message', 'value' => '', 'labels' => array('post_button' => $txt['post']), 'height' => '250px', 'width' => '100%', 'preview_type' => 0);
                create_control_richedit($editorOptions);
                $context['attached'] = '';
                $context['make_poll'] = isset($_REQUEST['poll']);
                // Message icons - customized icons are off?
                $context['icons'] = getMessageIcons($board);
                if (!empty($context['icons'])) {
                    $context['icons'][count($context['icons']) - 1]['is_last'] = true;
                }
            }
        }
        addJavascriptVar(array('notification_topic_notice' => $context['is_marked_notify'] ? $txt['notification_disable_topic'] : $txt['notification_enable_topic']), true);
        if ($context['can_send_topic']) {
            addJavascriptVar(array('sendtopic_cancel' => $txt['modify_cancel'], 'sendtopic_back' => $txt['back'], 'sendtopic_close' => $txt['find_close'], 'sendtopic_error' => $txt['send_error_occurred'], 'required_field' => $txt['require_field']), true);
        }
        // Build the normal button array.
        $context['normal_buttons'] = array('reply' => array('test' => 'can_reply', 'text' => 'reply', 'image' => 'reply.png', 'lang' => true, 'url' => $scripturl . '?action=post;topic=' . $context['current_topic'] . '.' . $context['start'] . ';last_msg=' . $context['topic_last_message'], 'active' => true), 'notify' => array('test' => 'can_mark_notify', 'text' => $context['is_marked_notify'] ? 'unnotify' : 'notify', 'image' => ($context['is_marked_notify'] ? 'un' : '') . 'notify.png', 'lang' => true, 'custom' => 'onclick="return notifyButton(this);"', 'url' => $scripturl . '?action=notify;sa=' . ($context['is_marked_notify'] ? 'off' : 'on') . ';topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'mark_unread' => array('test' => 'can_mark_unread', 'text' => 'mark_unread', 'image' => 'markunread.png', 'lang' => true, 'url' => $scripturl . '?action=markasread;sa=topic;t=' . $context['mark_unread_time'] . ';topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'unwatch' => array('test' => 'can_unwatch', 'text' => ($context['topic_unwatched'] ? '' : 'un') . 'watch', 'image' => ($context['topic_unwatched'] ? '' : 'un') . 'watched.png', 'lang' => true, 'custom' => 'onclick="return unwatchButton(this);"', 'url' => $scripturl . '?action=unwatchtopic;topic=' . $context['current_topic'] . '.' . $context['start'] . ';sa=' . ($context['topic_unwatched'] ? 'off' : 'on') . ';' . $context['session_var'] . '=' . $context['session_id']), 'send' => array('test' => 'can_send_topic', 'text' => 'send_topic', 'image' => 'sendtopic.png', 'lang' => true, 'url' => $scripturl . '?action=emailuser;sa=sendtopic;topic=' . $context['current_topic'] . '.0', 'custom' => 'onclick="return sendtopicOverlayDiv(this.href, \'' . $txt['send_topic'] . '\');"'), 'print' => array('test' => 'can_print', 'text' => 'print', 'image' => 'print.png', 'lang' => true, 'custom' => 'rel="nofollow"', 'class' => 'new_win', 'url' => $scripturl . '?action=topic;sa=printpage;topic=' . $context['current_topic'] . '.0'));
        // Build the mod button array
        $context['mod_buttons'] = array('move' => array('test' => 'can_move', 'text' => 'move_topic', 'image' => 'admin_move.png', 'lang' => true, 'url' => $scripturl . '?action=movetopic;current_board=' . $context['current_board'] . ';topic=' . $context['current_topic'] . '.0'), 'delete' => array('test' => 'can_delete', 'text' => 'remove_topic', 'image' => 'admin_rem.png', 'lang' => true, 'custom' => 'onclick="return confirm(\'' . $txt['are_sure_remove_topic'] . '\');"', 'url' => $scripturl . '?action=removetopic2;topic=' . $context['current_topic'] . '.0;' . $context['session_var'] . '=' . $context['session_id']), 'lock' => array('test' => 'can_lock', 'text' => empty($context['is_locked']) ? 'set_lock' : 'set_unlock', 'image' => 'admin_lock.png', 'lang' => true, 'url' => $scripturl . '?action=topic;sa=lock;topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'sticky' => array('test' => 'can_sticky', 'text' => empty($context['is_sticky']) ? 'set_sticky' : 'set_nonsticky', 'image' => 'admin_sticky.png', 'lang' => true, 'url' => $scripturl . '?action=topic;sa=sticky;topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'merge' => array('test' => 'can_merge', 'text' => 'merge', 'image' => 'merge.png', 'lang' => true, 'url' => $scripturl . '?action=mergetopics;board=' . $context['current_board'] . '.0;from=' . $context['current_topic']), 'calendar' => array('test' => 'calendar_post', 'text' => 'calendar_link', 'image' => 'linktocal.png', 'lang' => true, 'url' => $scripturl . '?action=post;calendar;msg=' . $context['topic_first_message'] . ';topic=' . $context['current_topic'] . '.0'));
        // Restore topic. eh?  No monkey business.
        if ($context['can_restore_topic']) {
            $context['mod_buttons'][] = array('text' => 'restore_topic', 'image' => '', 'lang' => true, 'url' => $scripturl . '?action=restoretopic;topics=' . $context['current_topic'] . ';' . $context['session_var'] . '=' . $context['session_id']);
        }
        if ($context['can_reply'] && !empty($options['display_quick_reply'])) {
            $template_layers->add('quickreply');
        }
        $template_layers->add('pages_and_buttons');
        // Allow adding new buttons easily.
        call_integration_hook('integrate_display_buttons');
        call_integration_hook('integrate_mod_buttons');
    }
Esempio n. 8
0
function Display()
{
    global $scripturl, $txt, $db_prefix, $modSettings, $context, $settings;
    global $options, $sourcedir, $user_info, $ID_MEMBER, $board_info, $topic;
    global $board, $attachments, $messages_request, $language;
    // What are you gonna display if these are empty?!
    if (empty($topic)) {
        fatal_lang_error('smf232', false);
    }
    // Load the proper template and/or sub template.
    if (WIRELESS) {
        $context['sub_template'] = WIRELESS_PROTOCOL . '_display';
    } else {
        loadTemplate('Display');
    }
    // Not only does a prefetch make things slower for the server, but it makes it impossible to know if they read it.
    if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') {
        ob_end_clean();
        header('HTTP/1.1 403 Prefetch Forbidden');
        die;
    }
    // Find the previous or next topic.  Make a fuss if there are no more.
    if (isset($_REQUEST['prev_next']) && ($_REQUEST['prev_next'] == 'prev' || $_REQUEST['prev_next'] == 'next')) {
        // No use in calculating the next topic if there's only one.
        if ($board_info['num_topics'] > 1) {
            // Just prepare some variables that are used in the query.
            $gt_lt = $_REQUEST['prev_next'] == 'prev' ? '>' : '<';
            $order = $_REQUEST['prev_next'] == 'prev' ? '' : ' DESC';
            $request = db_query("\n\t\t\t\tSELECT t2.ID_TOPIC\n\t\t\t\tFROM ({$db_prefix}topics AS t, {$db_prefix}topics AS t2)\n\t\t\t\tWHERE t.ID_TOPIC = {$topic}" . (empty($modSettings['enableStickyTopics']) ? "\n\t\t\t\t\tAND t2.ID_LAST_MSG {$gt_lt} t.ID_LAST_MSG" : "\n\t\t\t\t\tAND ((t2.ID_LAST_MSG {$gt_lt} t.ID_LAST_MSG AND t2.isSticky {$gt_lt}= t.isSticky) OR t2.isSticky {$gt_lt} t.isSticky)") . "\n\t\t\t\t\tAND t2.ID_BOARD = {$board}\n\t\t\t\tORDER BY" . (empty($modSettings['enableStickyTopics']) ? '' : " t2.isSticky{$order},") . " t2.ID_LAST_MSG{$order}\n\t\t\t\tLIMIT 1", __FILE__, __LINE__);
            // No more left.
            if (mysql_num_rows($request) == 0) {
                mysql_free_result($request);
                // Roll over - if we're going prev, get the last - otherwise the first.
                $request = db_query("\n\t\t\t\t\tSELECT ID_TOPIC\n\t\t\t\t\tFROM {$db_prefix}topics\n\t\t\t\t\tWHERE ID_BOARD = {$board}\n\t\t\t\t\tORDER BY" . (empty($modSettings['enableStickyTopics']) ? '' : " isSticky{$order},") . " ID_LAST_MSG{$order}\n\t\t\t\t\tLIMIT 1", __FILE__, __LINE__);
            }
            // Now you can be sure $topic is the ID_TOPIC to view.
            list($topic) = mysql_fetch_row($request);
            mysql_free_result($request);
            $context['current_topic'] = $topic;
        }
        // Go to the newest message on this topic.
        $_REQUEST['start'] = 'new';
        // Duplicate link!  Tell the robots not to link this.
        $context['robot_no_index'] = true;
    }
    // Add 1 to the number of views of this topic.
    if (empty($_SESSION['last_read_topic']) || $_SESSION['last_read_topic'] != $topic) {
        db_query("\n\t\t\tUPDATE {$db_prefix}topics\n\t\t\tSET numViews = numViews + 1\n\t\t\tWHERE ID_TOPIC = {$topic}\n\t\t\tLIMIT 1", __FILE__, __LINE__);
        $_SESSION['last_read_topic'] = $topic;
    }
    // Get all the important topic info.
    $request = db_query("\n\t\tSELECT\n\t\t\tt.numReplies, t.numViews, t.locked, ms.subject, t.isSticky, t.ID_POLL,\n\t\t\tt.ID_MEMBER_STARTED, t.ID_FIRST_MSG, t.ID_LAST_MSG,\n\t\t\t" . ($user_info['is_guest'] ? '0' : 'IFNULL(lt.ID_MSG, -1) + 1') . " AS new_from\n\t\tFROM ({$db_prefix}topics AS t, {$db_prefix}messages AS ms)" . ($user_info['is_guest'] ? '' : "\n\t\t\tLEFT JOIN {$db_prefix}log_topics AS lt ON (lt.ID_TOPIC = {$topic} AND lt.ID_MEMBER = {$ID_MEMBER})") . "\n\t\tWHERE t.ID_TOPIC = {$topic}\n\t\t\tAND ms.ID_MSG = t.ID_FIRST_MSG\n\t\tLIMIT 1", __FILE__, __LINE__);
    if (mysql_num_rows($request) == 0) {
        fatal_lang_error(472, false);
    }
    $topicinfo = mysql_fetch_assoc($request);
    mysql_free_result($request);
    // The start isn't a number; it's information about what to do, where to go.
    if (!is_numeric($_REQUEST['start'])) {
        // Redirect to the page and post with new messages, originally by Omar Bazavilvazo.
        if ($_REQUEST['start'] == 'new') {
            // Guests automatically go to the last topic.
            if ($user_info['is_guest']) {
                $context['start_from'] = $topicinfo['numReplies'];
                $_REQUEST['start'] = empty($options['view_newest_first']) ? $context['start_from'] : 0;
            } else {
                // Find the earliest unread message in the topic. (the use of topics here is just for both tables.)
                $request = db_query("\n\t\t\t\t\tSELECT IFNULL(lt.ID_MSG, IFNULL(lmr.ID_MSG, -1)) + 1 AS new_from\n\t\t\t\t\tFROM {$db_prefix}topics AS t\n\t\t\t\t\t\tLEFT JOIN {$db_prefix}log_topics AS lt ON (lt.ID_TOPIC = {$topic} AND lt.ID_MEMBER = {$ID_MEMBER})\n\t\t\t\t\t\tLEFT JOIN {$db_prefix}log_mark_read AS lmr ON (lmr.ID_BOARD = {$board} AND lmr.ID_MEMBER = {$ID_MEMBER})\n\t\t\t\t\tWHERE t.ID_TOPIC = {$topic}\n\t\t\t\t\tLIMIT 1", __FILE__, __LINE__);
                list($new_from) = mysql_fetch_row($request);
                mysql_free_result($request);
                // Fall through to the next if statement.
                $_REQUEST['start'] = 'msg' . $new_from;
            }
        }
        // Start from a certain time index, not a message.
        if (substr($_REQUEST['start'], 0, 4) == 'from') {
            $timestamp = (int) substr($_REQUEST['start'], 4);
            if ($timestamp === 0) {
                $_REQUEST['start'] = 0;
            } else {
                // Find the number of messages posted before said time...
                $request = db_query("\n\t\t\t\t\tSELECT COUNT(*)\n\t\t\t\t\tFROM {$db_prefix}messages\n\t\t\t\t\tWHERE posterTime < {$timestamp}\n\t\t\t\t\t\tAND ID_TOPIC = {$topic}", __FILE__, __LINE__);
                list($context['start_from']) = mysql_fetch_row($request);
                mysql_free_result($request);
                // Handle view_newest_first options, and get the correct start value.
                $_REQUEST['start'] = empty($options['view_newest_first']) ? $context['start_from'] : $topicinfo['numReplies'] - $context['start_from'];
            }
        } elseif (substr($_REQUEST['start'], 0, 3) == 'msg') {
            $virtual_msg = (int) substr($_REQUEST['start'], 3);
            if ($virtual_msg >= $topicinfo['ID_LAST_MSG']) {
                $context['start_from'] = $topicinfo['numReplies'];
            } elseif ($virtual_msg <= $topicinfo['ID_FIRST_MSG']) {
                $context['start_from'] = 0;
            } else {
                // Find the start value for that message......
                $request = db_query("\n\t\t\t\t\tSELECT COUNT(*)\n\t\t\t\t\tFROM {$db_prefix}messages\n\t\t\t\t\tWHERE ID_MSG < {$virtual_msg}\n\t\t\t\t\t\tAND ID_TOPIC = {$topic}", __FILE__, __LINE__);
                list($context['start_from']) = mysql_fetch_row($request);
                mysql_free_result($request);
            }
            // We need to reverse the start as well in this case.
            $_REQUEST['start'] = empty($options['view_newest_first']) ? $context['start_from'] : $topicinfo['numReplies'] - $context['start_from'];
            $context['robot_no_index'] = true;
        }
    }
    // Create a previous next string if the selected theme has it as a selected option.
    $context['previous_next'] = $modSettings['enablePreviousNext'] ? '<a href="' . $scripturl . '?topic=' . $topic . '.0;prev_next=prev#new">' . $txt['previous_next_back'] . '</a> <a href="' . $scripturl . '?topic=' . $topic . '.0;prev_next=next#new">' . $txt['previous_next_forward'] . '</a>' : '';
    // Check if spellchecking is both enabled and actually working. (for quick reply.)
    $context['show_spellchecking'] = !empty($modSettings['enableSpellChecking']) && function_exists('pspell_new');
    // Censor the title...
    censorText($topicinfo['subject']);
    $context['page_title'] = $topicinfo['subject'];
    $context['num_replies'] = $topicinfo['numReplies'];
    $context['topic_first_message'] = $topicinfo['ID_FIRST_MSG'];
    // Is this topic sticky, or can it even be?
    $topicinfo['isSticky'] = empty($modSettings['enableStickyTopics']) ? '0' : $topicinfo['isSticky'];
    // Default this topic to not marked for notifications... of course...
    $context['is_marked_notify'] = false;
    // Guests can't mark topics read or for notifications, just can't sorry.
    if (!$user_info['is_guest']) {
        // Mark the topic as read :)
        if (!empty($topicinfo['new_from'])) {
            db_query("\n\t\t\t\tUPDATE {$db_prefix}log_topics\n\t\t\t\tSET ID_MSG = {$modSettings['maxMsgID']}\n\t\t\t\tWHERE ID_MEMBER = {$ID_MEMBER}\n\t\t\t\t\tAND ID_TOPIC = {$topic}\n\t\t\t\tLIMIT 1", __FILE__, __LINE__);
            $flag = db_affected_rows() !== 0;
        }
        if (empty($flag)) {
            db_query("\n\t\t\t\tREPLACE INTO {$db_prefix}log_topics\n\t\t\t\t\t(ID_MSG, ID_MEMBER, ID_TOPIC)\n\t\t\t\tVALUES ({$modSettings['maxMsgID']}, {$ID_MEMBER}, {$topic})", __FILE__, __LINE__);
        }
        // Check for notifications on this topic OR board.
        $request = db_query("\n\t\t\tSELECT sent, ID_TOPIC\n\t\t\tFROM {$db_prefix}log_notify\n\t\t\tWHERE (ID_TOPIC = {$topic} OR ID_BOARD = {$board})\n\t\t\t\tAND ID_MEMBER = {$ID_MEMBER}\n\t\t\tLIMIT 2", __FILE__, __LINE__);
        $do_once = true;
        while ($row = mysql_fetch_assoc($request)) {
            // Find if this topic is marked for notification...
            if (!empty($row['ID_TOPIC'])) {
                $context['is_marked_notify'] = true;
            }
            // Only do this once, but mark the notifications as "not sent yet" for next time.
            if (!empty($row['sent']) && $do_once) {
                db_query("\n\t\t\t\t\tUPDATE {$db_prefix}log_notify\n\t\t\t\t\tSET sent = 0\n\t\t\t\t\tWHERE (ID_TOPIC = {$topic} OR ID_BOARD = {$board})\n\t\t\t\t\t\tAND ID_MEMBER = {$ID_MEMBER}\n\t\t\t\t\tLIMIT 2", __FILE__, __LINE__);
                $do_once = false;
            }
        }
        // Have we recently cached the number of new topics in this board, and it's still a lot?
        if (isset($_REQUEST['topicseen']) && isset($_SESSION['topicseen_cache'][$board]) && $_SESSION['topicseen_cache'][$board] > 5) {
            $_SESSION['topicseen_cache'][$board]--;
        } elseif (isset($_REQUEST['topicseen'])) {
            // Use the mark read tables... and the last visit to figure out if this should be read or not.
            $request = db_query("\n\t\t\t\tSELECT COUNT(*)\n\t\t\t\tFROM {$db_prefix}topics AS t\n\t\t\t\t\tLEFT JOIN {$db_prefix}log_boards AS lb ON (lb.ID_BOARD = {$board} AND lb.ID_MEMBER = {$ID_MEMBER})\n\t\t\t\t\tLEFT JOIN {$db_prefix}log_topics AS lt ON (lt.ID_TOPIC = t.ID_TOPIC AND lt.ID_MEMBER = {$ID_MEMBER})\n\t\t\t\tWHERE t.ID_BOARD = {$board}\n\t\t\t\t\tAND t.ID_LAST_MSG > IFNULL(lb.ID_MSG, 0)\n\t\t\t\t\tAND t.ID_LAST_MSG > IFNULL(lt.ID_MSG, 0)" . (empty($_SESSION['ID_MSG_LAST_VISIT']) ? '' : "\n\t\t\t\t\tAND t.ID_LAST_MSG > {$_SESSION['ID_MSG_LAST_VISIT']}"), __FILE__, __LINE__);
            list($numNewTopics) = mysql_fetch_row($request);
            mysql_free_result($request);
            // If there're no real new topics in this board, mark the board as seen.
            if (empty($numNewTopics)) {
                $_REQUEST['boardseen'] = true;
            } else {
                $_SESSION['topicseen_cache'][$board] = $numNewTopics;
            }
        } elseif (isset($_SESSION['topicseen_cache'][$board])) {
            $_SESSION['topicseen_cache'][$board]--;
        }
        // Mark board as seen if we came using last post link from BoardIndex. (or other places...)
        if (isset($_REQUEST['boardseen'])) {
            db_query("\n\t\t\t\tREPLACE INTO {$db_prefix}log_boards\n\t\t\t\t\t(ID_MSG, ID_MEMBER, ID_BOARD)\n\t\t\t\tVALUES ({$modSettings['maxMsgID']}, {$ID_MEMBER}, {$board})", __FILE__, __LINE__);
        }
    }
    // Let's get nosey, who is viewing this topic?
    if (!empty($settings['display_who_viewing'])) {
        // Start out with no one at all viewing it.
        $context['view_members'] = array();
        $context['view_members_list'] = array();
        $context['view_num_hidden'] = 0;
        // Search for members who have this topic set in their GET data.
        $request = db_query("\n\t\t\tSELECT\n\t\t\t\tlo.ID_MEMBER, lo.logTime, mem.realName, mem.memberName, mem.showOnline,\n\t\t\t\tmg.onlineColor, mg.ID_GROUP, mg.groupName\n\t\t\tFROM {$db_prefix}log_online AS lo\n\t\t\t\tLEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = lo.ID_MEMBER)\n\t\t\t\tLEFT JOIN {$db_prefix}membergroups AS mg ON (mg.ID_GROUP = IF(mem.ID_GROUP = 0, mem.ID_POST_GROUP, mem.ID_GROUP))\n\t\t\tWHERE INSTR(lo.url, 's:5:\"topic\";i:{$topic};') OR lo.session = '" . ($user_info['is_guest'] ? 'ip' . $user_info['ip'] : session_id()) . "'", __FILE__, __LINE__);
        while ($row = mysql_fetch_assoc($request)) {
            if (empty($row['ID_MEMBER'])) {
                continue;
            }
            if (!empty($row['onlineColor'])) {
                $link = '<a href="' . $scripturl . '?action=profile;u=' . $row['ID_MEMBER'] . '" style="color: ' . $row['onlineColor'] . ';">' . $row['realName'] . '</a>';
            } else {
                $link = '<a href="' . $scripturl . '?action=profile;u=' . $row['ID_MEMBER'] . '">' . $row['realName'] . '</a>';
            }
            $is_buddy = in_array($row['ID_MEMBER'], $user_info['buddies']);
            if ($is_buddy) {
                $link = '<b>' . $link . '</b>';
            }
            // Add them both to the list and to the more detailed list.
            if (!empty($row['showOnline']) || allowedTo('moderate_forum')) {
                $context['view_members_list'][$row['logTime'] . $row['memberName']] = empty($row['showOnline']) ? '<i>' . $link . '</i>' : $link;
            }
            $context['view_members'][$row['logTime'] . $row['memberName']] = array('id' => $row['ID_MEMBER'], 'username' => $row['memberName'], 'name' => $row['realName'], 'group' => $row['ID_GROUP'], 'href' => $scripturl . '?action=profile;u=' . $row['ID_MEMBER'], 'link' => $link, 'is_buddy' => $is_buddy, 'hidden' => empty($row['showOnline']));
            if (empty($row['showOnline'])) {
                $context['view_num_hidden']++;
            }
        }
        // The number of guests is equal to the rows minus the ones we actually used ;).
        $context['view_num_guests'] = mysql_num_rows($request) - count($context['view_members']);
        mysql_free_result($request);
        // Sort the list.
        krsort($context['view_members']);
        krsort($context['view_members_list']);
    }
    // If all is set, but not allowed... just unset it.
    if (isset($_REQUEST['all']) && empty($modSettings['enableAllMessages'])) {
        unset($_REQUEST['all']);
    } elseif (isset($_REQUEST['all'])) {
        $_REQUEST['start'] = -1;
    }
    // Construct the page index, allowing for the .START method...
    $context['page_index'] = constructPageIndex($scripturl . '?topic=' . $topic . '.%d', $_REQUEST['start'], $topicinfo['numReplies'] + 1, $modSettings['defaultMaxMessages'], true);
    $context['start'] = $_REQUEST['start'];
    // This is information about which page is current, and which page we're on - in case you don't like the constructed page index. (again, wireles..)
    $context['page_info'] = array('current_page' => $_REQUEST['start'] / $modSettings['defaultMaxMessages'] + 1, 'num_pages' => floor($topicinfo['numReplies'] / $modSettings['defaultMaxMessages']) + 1);
    // Figure out all the link to the next/prev/first/last/etc. for wireless mainly.
    $context['links'] = array('first' => $_REQUEST['start'] >= $modSettings['defaultMaxMessages'] ? $scripturl . '?topic=' . $topic . '.0' : '', 'prev' => $_REQUEST['start'] >= $modSettings['defaultMaxMessages'] ? $scripturl . '?topic=' . $topic . '.' . ($_REQUEST['start'] - $modSettings['defaultMaxMessages']) : '', 'next' => $_REQUEST['start'] + $modSettings['defaultMaxMessages'] < $topicinfo['numReplies'] + 1 ? $scripturl . '?topic=' . $topic . '.' . ($_REQUEST['start'] + $modSettings['defaultMaxMessages']) : '', 'last' => $_REQUEST['start'] + $modSettings['defaultMaxMessages'] < $topicinfo['numReplies'] + 1 ? $scripturl . '?topic=' . $topic . '.' . floor($topicinfo['numReplies'] / $modSettings['defaultMaxMessages']) * $modSettings['defaultMaxMessages'] : '', 'up' => $scripturl . '?board=' . $board . '.0');
    // If they are viewing all the posts, show all the posts, otherwise limit the number.
    if (!empty($modSettings['enableAllMessages']) && $topicinfo['numReplies'] + 1 > $modSettings['defaultMaxMessages'] && $topicinfo['numReplies'] + 1 < $modSettings['enableAllMessages']) {
        if (isset($_REQUEST['all'])) {
            // No limit! (actually, there is a limit, but...)
            $modSettings['defaultMaxMessages'] = -1;
            $context['page_index'] .= empty($modSettings['compactTopicPagesEnable']) ? '<b>' . $txt[190] . '</b> ' : '[<b>' . $txt[190] . '</b>] ';
            // Set start back to 0...
            $_REQUEST['start'] = 0;
        } else {
            $context['page_index'] .= '&nbsp;<a href="' . $scripturl . '?topic=' . $topic . '.0;all">' . $txt[190] . '</a> ';
        }
    }
    // Build the link tree.
    $context['linktree'][] = array('url' => $scripturl . '?topic=' . $topic . '.0', 'name' => $topicinfo['subject'], 'extra_before' => $settings['linktree_inline'] ? $txt[118] . ': ' : '');
    // Build a list of this board's moderators.
    $context['moderators'] =& $board_info['moderators'];
    $context['link_moderators'] = array();
    if (!empty($board_info['moderators'])) {
        // Add a link for each moderator...
        foreach ($board_info['moderators'] as $mod) {
            $context['link_moderators'][] = '<a href="' . $scripturl . '?action=profile;u=' . $mod['id'] . '" title="' . $txt[62] . '">' . $mod['name'] . '</a>';
        }
        // And show it after the board's name.
        $context['linktree'][count($context['linktree']) - 2]['extra_after'] = ' (' . (count($context['link_moderators']) == 1 ? $txt[298] : $txt[299]) . ': ' . implode(', ', $context['link_moderators']) . ')';
    }
    // Information about the current topic...
    $context['is_locked'] = $topicinfo['locked'];
    $context['is_sticky'] = $topicinfo['isSticky'];
    $context['is_very_hot'] = $topicinfo['numReplies'] >= $modSettings['hotTopicVeryPosts'];
    $context['is_hot'] = $topicinfo['numReplies'] >= $modSettings['hotTopicPosts'];
    // We don't want to show the poll icon in the topic class here, so pretend it's not one.
    $context['is_poll'] = false;
    determineTopicClass($context);
    $context['is_poll'] = $topicinfo['ID_POLL'] > 0 && $modSettings['pollMode'] == '1' && allowedTo('poll_view');
    // Did this user start the topic or not?
    $context['user']['started'] = $ID_MEMBER == $topicinfo['ID_MEMBER_STARTED'] && !$user_info['is_guest'];
    $context['topic_starter_id'] = $topicinfo['ID_MEMBER_STARTED'];
    // Set the topic's information for the template.
    $context['subject'] = $topicinfo['subject'];
    $context['num_views'] = $topicinfo['numViews'];
    $context['mark_unread_time'] = $topicinfo['new_from'];
    // For quick reply we need a response prefix in the default forum language.
    if (!isset($context['response_prefix']) && !($context['response_prefix'] = cache_get_data('response_prefix'))) {
        if ($language === $user_info['language']) {
            $context['response_prefix'] = $txt['response_prefix'];
        } else {
            loadLanguage('index', $language, false);
            $context['response_prefix'] = $txt['response_prefix'];
            loadLanguage('index');
        }
        cache_put_data('response_prefix', $context['response_prefix'], 600);
    }
    // If we want to show event information in the topic, prepare the data.
    if (allowedTo('calendar_view') && !empty($modSettings['cal_showInTopic']) && !empty($modSettings['cal_enabled'])) {
        // First, try create a better time format, ignoring the "time" elements.
        if (preg_match('~%[AaBbCcDdeGghjmuYy](?:[^%]*%[AaBbCcDdeGghjmuYy])*~', $user_info['time_format'], $matches) == 0 || empty($matches[0])) {
            $date_string = $user_info['time_format'];
        } else {
            $date_string = $matches[0];
        }
        // Any calendar information for this topic?
        $request = db_query("\n\t\t\tSELECT cal.ID_EVENT, cal.startDate, cal.endDate, cal.title, cal.ID_MEMBER, mem.realName\n\t\t\tFROM {$db_prefix}calendar AS cal\n\t\t\t\tLEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = cal.ID_MEMBER)\n\t\t\tWHERE cal.ID_TOPIC = {$topic}\n\t\t\tORDER BY startDate", __FILE__, __LINE__);
        $context['linked_calendar_events'] = array();
        while ($row = mysql_fetch_assoc($request)) {
            // Prepare the dates for being formatted.
            $startDate = sscanf($row['startDate'], '%04d-%02d-%02d');
            $startDate = mktime(12, 0, 0, $startDate[1], $startDate[2], $startDate[0]);
            $endDate = sscanf($row['endDate'], '%04d-%02d-%02d');
            $endDate = mktime(12, 0, 0, $endDate[1], $endDate[2], $endDate[0]);
            $context['linked_calendar_events'][] = array('id' => $row['ID_EVENT'], 'title' => $row['title'], 'can_edit' => allowedTo('calendar_edit_any') || $row['ID_MEMBER'] == $ID_MEMBER && allowedTo('calendar_edit_own'), 'modify_href' => $scripturl . '?action=post;msg=' . $topicinfo['ID_FIRST_MSG'] . ';topic=' . $topic . '.0;calendar;eventid=' . $row['ID_EVENT'] . ';sesc=' . $context['session_id'], 'start_date' => timeformat($startDate, $date_string), 'start_timestamp' => forum_time(true, $startDate), 'end_date' => timeformat($endDate, $date_string), 'end_timestamp' => forum_time(true, $startDate), 'is_last' => false);
        }
        mysql_free_result($request);
        if (!empty($context['linked_calendar_events'])) {
            $context['linked_calendar_events'][count($context['linked_calendar_events']) - 1]['is_last'] = true;
        }
    }
    // Create the poll info if it exists.
    if ($context['is_poll']) {
        // Get the question and if it's locked.
        $request = db_query("\n\t\t\tSELECT\n\t\t\t\tp.question, p.votingLocked, p.hideResults, p.expireTime, p.maxVotes, p.changeVote,\n\t\t\t\tp.ID_MEMBER, IFNULL(mem.realName, p.posterName) AS posterName,\n\t\t\t\tCOUNT(DISTINCT lp.ID_MEMBER) AS total\n\t\t\tFROM {$db_prefix}polls AS p\n\t\t\t\tLEFT JOIN {$db_prefix}log_polls AS lp ON (lp.ID_POLL = p.ID_POLL)\n\t\t\t\tLEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = p.ID_MEMBER)\n\t\t\tWHERE p.ID_POLL = {$topicinfo['ID_POLL']}\n\t\t\tGROUP BY p.ID_POLL\n\t\t\tLIMIT 1", __FILE__, __LINE__);
        $pollinfo = mysql_fetch_assoc($request);
        mysql_free_result($request);
        // Get all the options, and calculate the total votes.
        $request = db_query("\n\t\t\tSELECT pc.ID_CHOICE, pc.label, pc.votes, IFNULL(lp.ID_CHOICE, -1) AS votedThis\n\t\t\tFROM {$db_prefix}poll_choices AS pc\n\t\t\t\tLEFT JOIN {$db_prefix}log_polls AS lp ON (lp.ID_CHOICE = pc.ID_CHOICE AND lp.ID_POLL = {$topicinfo['ID_POLL']} AND lp.ID_MEMBER = {$ID_MEMBER})\n\t\t\tWHERE pc.ID_POLL = {$topicinfo['ID_POLL']}", __FILE__, __LINE__);
        $pollOptions = array();
        $realtotal = 0;
        $pollinfo['has_voted'] = false;
        while ($row = mysql_fetch_assoc($request)) {
            censorText($row['label']);
            $pollOptions[$row['ID_CHOICE']] = $row;
            $realtotal += $row['votes'];
            $pollinfo['has_voted'] |= $row['votedThis'] != -1;
        }
        mysql_free_result($request);
        // Set up the basic poll information.
        $context['poll'] = array('id' => $topicinfo['ID_POLL'], 'image' => 'normal_' . (empty($pollinfo['votingLocked']) ? 'poll' : 'locked_poll'), 'question' => parse_bbc($pollinfo['question']), 'total_votes' => $pollinfo['total'], 'change_vote' => !empty($pollinfo['changeVote']), 'is_locked' => !empty($pollinfo['votingLocked']), 'options' => array(), 'lock' => allowedTo('poll_lock_any') || $context['user']['started'] && allowedTo('poll_lock_own'), 'edit' => allowedTo('poll_edit_any') || $context['user']['started'] && allowedTo('poll_edit_own'), 'allowed_warning' => $pollinfo['maxVotes'] > 1 ? sprintf($txt['poll_options6'], $pollinfo['maxVotes']) : '', 'is_expired' => !empty($pollinfo['expireTime']) && $pollinfo['expireTime'] < time(), 'expire_time' => !empty($pollinfo['expireTime']) ? timeformat($pollinfo['expireTime']) : 0, 'has_voted' => !empty($pollinfo['has_voted']), 'starter' => array('id' => $pollinfo['ID_MEMBER'], 'name' => $row['posterName'], 'href' => $pollinfo['ID_MEMBER'] == 0 ? '' : $scripturl . '?action=profile;u=' . $pollinfo['ID_MEMBER'], 'link' => $pollinfo['ID_MEMBER'] == 0 ? $row['posterName'] : '<a href="' . $scripturl . '?action=profile;u=' . $pollinfo['ID_MEMBER'] . '">' . $row['posterName'] . '</a>'));
        // You're allowed to vote if:
        // 1. the poll did not expire, and
        // 2. you're not a guest... and
        // 3. you're not trying to view the results, and
        // 4. the poll is not locked, and
        // 5. you have the proper permissions, and
        // 6. you haven't already voted before.
        $context['allow_vote'] = !$context['poll']['is_expired'] && !$user_info['is_guest'] && empty($pollinfo['votingLocked']) && allowedTo('poll_vote') && !$context['poll']['has_voted'];
        // You're allowed to view the results if:
        // 1. you're just a super-nice-guy, or
        // 2. anyone can see them (hideResults == 0), or
        // 3. you can see them after you voted (hideResults == 1), or
        // 4. you've waited long enough for the poll to expire. (whether hideResults is 1 or 2.)
        $context['allow_poll_view'] = allowedTo('moderate_board') || $pollinfo['hideResults'] == 0 || $pollinfo['hideResults'] == 1 && $context['poll']['has_voted'] || $context['poll']['is_expired'];
        $context['poll']['show_results'] = $context['allow_poll_view'] && isset($_REQUEST['viewResults']);
        // You're allowed to change your vote if:
        // 1. the poll did not expire, and
        // 2. you're not a guest... and
        // 3. the poll is not locked, and
        // 4. you have the proper permissions, and
        // 5. you have already voted, and
        // 6. the poll creator has said you can!
        $context['allow_change_vote'] = !$context['poll']['is_expired'] && !$user_info['is_guest'] && empty($pollinfo['votingLocked']) && allowedTo('poll_vote') && $context['poll']['has_voted'] && $context['poll']['change_vote'];
        // Calculate the percentages and bar lengths...
        $divisor = $realtotal == 0 ? 1 : $realtotal;
        // Determine if a decimal point is needed in order for the options to add to 100%.
        $precision = $realtotal == 100 ? 0 : 1;
        // Now look through each option, and...
        foreach ($pollOptions as $i => $option) {
            // First calculate the percentage, and then the width of the bar...
            $bar = round($option['votes'] * 100 / $divisor, $precision);
            $barWide = $bar == 0 ? 1 : floor($bar * 8 / 3);
            // Now add it to the poll's contextual theme data.
            $context['poll']['options'][$i] = array('id' => 'options-' . $i, 'percent' => $bar, 'votes' => $option['votes'], 'voted_this' => $option['votedThis'] != -1, 'bar' => '<span style="white-space: nowrap;"><img src="' . $settings['images_url'] . '/poll_left.gif" alt="" /><img src="' . $settings['images_url'] . '/poll_middle.gif" width="' . $barWide . '" height="12" alt="-" /><img src="' . $settings['images_url'] . '/poll_right.gif" alt="" /></span>', 'bar_width' => $barWide, 'option' => parse_bbc($option['label']), 'vote_button' => '<input type="' . ($pollinfo['maxVotes'] > 1 ? 'checkbox' : 'radio') . '" name="options[]" id="options-' . $i . '" value="' . $i . '" class="check" />');
        }
    }
    // Calculate the fastest way to get the messages!
    $ascending = empty($options['view_newest_first']);
    $start = $_REQUEST['start'];
    $limit = $modSettings['defaultMaxMessages'];
    $firstIndex = 0;
    if ($start > $topicinfo['numReplies'] / 2 && $modSettings['defaultMaxMessages'] != -1) {
        $ascending = !$ascending;
        $limit = $topicinfo['numReplies'] < $start + $limit ? $topicinfo['numReplies'] - $start + 1 : $limit;
        $start = $topicinfo['numReplies'] < $start + $limit ? 0 : $topicinfo['numReplies'] - $start - $limit + 1;
        $firstIndex = $limit - 1;
    }
    // Get each post and poster in this topic.
    $request = db_query("\n\t\tSELECT ID_MSG, ID_MEMBER\n\t\tFROM {$db_prefix}messages\n\t\tWHERE ID_TOPIC = {$topic}\n\t\tORDER BY ID_MSG " . ($ascending ? '' : 'DESC') . ($modSettings['defaultMaxMessages'] == -1 ? '' : "\n\t\tLIMIT {$start}, {$limit}"), __FILE__, __LINE__);
    $messages = array();
    $posters = array();
    while ($row = mysql_fetch_assoc($request)) {
        if (!empty($row['ID_MEMBER'])) {
            $posters[] = $row['ID_MEMBER'];
        }
        $messages[] = $row['ID_MSG'];
    }
    mysql_free_result($request);
    $posters = array_unique($posters);
    $attachments = array();
    // If there _are_ messages here... (probably an error otherwise :!)
    if (!empty($messages)) {
        // Fetch attachments.
        if (!empty($modSettings['attachmentEnable']) && allowedTo('view_attachments')) {
            $request = db_query("\n\t\t\t\tSELECT\n\t\t\t\t\ta.ID_ATTACH, a.ID_MSG, a.filename, IFNULL(a.size, 0) AS filesize, a.downloads,\n\t\t\t\t\ta.width, a.height" . (empty($modSettings['attachmentShowImages']) || empty($modSettings['attachmentThumbnails']) ? '' : ",\n\t\t\t\t\tIFNULL(thumb.ID_ATTACH, 0) AS ID_THUMB, thumb.width AS thumb_width, thumb.height AS thumb_height") . "\n\t\t\t\tFROM {$db_prefix}attachments AS a" . (empty($modSettings['attachmentShowImages']) || empty($modSettings['attachmentThumbnails']) ? '' : "\n\t\t\t\t\tLEFT JOIN {$db_prefix}attachments AS thumb ON (thumb.ID_ATTACH = a.ID_THUMB)") . "\n\t\t\t\tWHERE a.ID_MSG IN (" . implode(',', $messages) . ")\n\t\t\t\t\tAND a.attachmentType = 0", __FILE__, __LINE__);
            $temp = array();
            while ($row = mysql_fetch_assoc($request)) {
                $temp[$row['ID_ATTACH']] = $row;
                if (!isset($attachments[$row['ID_MSG']])) {
                    $attachments[$row['ID_MSG']] = array();
                }
            }
            mysql_free_result($request);
            // This is better than sorting it with the query...
            ksort($temp);
            foreach ($temp as $row) {
                $attachments[$row['ID_MSG']][] = $row;
            }
        }
        // What?  It's not like it *couldn't* be only guests in this topic...
        if (!empty($posters)) {
            loadMemberData($posters);
        }
        $messages_request = db_query("\n\t\t\tSELECT\n\t\t\t\tID_MSG, icon, subject, posterTime, posterIP, ID_MEMBER, modifiedTime, modifiedName, body,\n\t\t\t\tsmileysEnabled, posterName, posterEmail,\n\t\t\t\tID_MSG_MODIFIED < {$topicinfo['new_from']} AS isRead\n\t\t\tFROM {$db_prefix}messages\n\t\t\tWHERE ID_MSG IN (" . implode(',', $messages) . ")\n\t\t\tORDER BY ID_MSG" . (empty($options['view_newest_first']) ? '' : ' DESC'), __FILE__, __LINE__);
        // Go to the last message if the given time is beyond the time of the last message.
        if (isset($context['start_from']) && $context['start_from'] >= $topicinfo['numReplies']) {
            $context['start_from'] = $topicinfo['numReplies'];
        }
        // Since the anchor information is needed on the top of the page we load these variables beforehand.
        $context['first_message'] = isset($messages[$firstIndex]) ? $messages[$firstIndex] : $messages[0];
        if (empty($options['view_newest_first'])) {
            $context['first_new_message'] = isset($context['start_from']) && $_REQUEST['start'] == $context['start_from'];
        } else {
            $context['first_new_message'] = isset($context['start_from']) && $_REQUEST['start'] == $topicinfo['numReplies'] - $context['start_from'];
        }
    } else {
        $messages_request = false;
        $context['first_message'] = 0;
        $context['first_new_message'] = false;
    }
    // Load the "Jump to" list...
    loadJumpTo();
    // Set the callback.  (do you REALIZE how much memory all the messages would take?!?)
    $context['get_message'] = 'prepareDisplayContext';
    // Basic settings.... may be converted over at some point.
    $context['allow_hide_email'] = !empty($modSettings['allow_hideEmail']) || $user_info['is_guest'] && !empty($modSettings['guest_hideContacts']);
    // Now set all the wonderful, wonderful permissions... like moderation ones...
    $common_permissions = array('can_sticky' => 'make_sticky', 'can_merge' => 'merge_any', 'can_split' => 'split_any', 'calendar_post' => 'calendar_post', 'can_mark_notify' => 'mark_any_notify', 'can_send_topic' => 'send_topic', 'can_send_pm' => 'pm_send', 'can_report_moderator' => 'report_any', 'can_moderate_forum' => 'moderate_forum');
    foreach ($common_permissions as $contextual => $perm) {
        $context[$contextual] = allowedTo($perm);
    }
    // Permissions with _any/_own versions.  $context[YYY] => ZZZ_any/_own.
    $anyown_permissions = array('can_move' => 'move', 'can_lock' => 'lock', 'can_delete' => 'remove', 'can_add_poll' => 'poll_add', 'can_remove_poll' => 'poll_remove', 'can_reply' => 'post_reply');
    foreach ($anyown_permissions as $contextual => $perm) {
        $context[$contextual] = allowedTo($perm . '_any') || $context['user']['started'] && allowedTo($perm . '_own');
    }
    // Cleanup all the permissions with extra stuff...
    $context['can_mark_notify'] &= !$context['user']['is_guest'];
    $context['can_sticky'] &= !empty($modSettings['enableStickyTopics']);
    $context['calendar_post'] &= !empty($modSettings['cal_enabled']);
    $context['can_add_poll'] &= $modSettings['pollMode'] == '1' && $topicinfo['ID_POLL'] <= 0;
    $context['can_remove_poll'] &= $modSettings['pollMode'] == '1' && $topicinfo['ID_POLL'] > 0;
    $context['can_reply'] &= empty($topicinfo['locked']) || allowedTo('moderate_board');
    $board_count = 0;
    foreach ($context['jump_to'] as $id => $cat) {
        $board_count += count($context['jump_to'][$id]['boards']);
    }
    $context['can_move'] &= $board_count > 1;
    // Start this off for quick moderation - it will be or'd for each post.
    $context['can_remove_post'] = allowedTo('delete_any') || allowedTo('delete_replies') && $context['user']['started'];
    // Load up the "double post" sequencing magic.
    if (!empty($options['display_quick_reply'])) {
        checkSubmitOnce('register');
    }
}
Esempio n. 9
0
function prepareSearchContext($reset = false)
{
    global $txt, $modSettings, $db_prefix, $scripturl, $ID_MEMBER;
    global $memberContext, $context, $settings, $options, $messages_request;
    global $boards_can, $participants, $func;
    // Remember which message this is.  (ie. reply #83)
    static $counter = null;
    if ($counter == null || $reset) {
        $counter = $_REQUEST['start'] + 1;
    }
    // If the query returned false, bail.
    if ($messages_request == false) {
        return false;
    }
    // Start from the beginning...
    if ($reset) {
        return @mysql_data_seek($messages_request, 0);
    }
    // Attempt to get the next message.
    $message = mysql_fetch_assoc($messages_request);
    if (!$message) {
        return false;
    }
    // Can't have an empty subject can we?
    $message['subject'] = $message['subject'] != '' ? $message['subject'] : $txt[24];
    $message['first_subject'] = $message['first_subject'] != '' ? $message['first_subject'] : $txt[24];
    $message['last_subject'] = $message['last_subject'] != '' ? $message['last_subject'] : $txt[24];
    // If it couldn't load, or the user was a guest.... someday may be done with a guest table.
    if (!loadMemberContext($message['ID_MEMBER'])) {
        // Notice this information isn't used anywhere else.... *cough guest table cough*.
        $memberContext[$message['ID_MEMBER']]['name'] = $message['posterName'];
        $memberContext[$message['ID_MEMBER']]['id'] = 0;
        $memberContext[$message['ID_MEMBER']]['group'] = $txt[28];
        $memberContext[$message['ID_MEMBER']]['link'] = $message['posterName'];
        $memberContext[$message['ID_MEMBER']]['email'] = $message['posterEmail'];
    }
    $memberContext[$message['ID_MEMBER']]['ip'] = $message['posterIP'];
    // Do the censor thang...
    censorText($message['body']);
    censorText($message['subject']);
    censorText($message['first_subject']);
    censorText($message['last_subject']);
    // Shorten this message if necessary.
    if ($context['compact']) {
        // Set the number of characters before and after the searched keyword.
        $charLimit = 40;
        $message['body'] = strtr($message['body'], array("\n" => ' ', '<br />' => "\n"));
        $message['body'] = parse_bbc($message['body'], $message['smileysEnabled'], $message['ID_MSG']);
        $message['body'] = strip_tags(strtr($message['body'], array('</div>' => '<br />')), '<br>');
        if (strlen($message['body']) > $charLimit) {
            if (empty($context['key_words'])) {
                $message['body'] = $func['strlen']($message['body']) > $charLimit ? $func['substr']($message['body'], 0, $charLimit) . '<b>...</b>' : $message['body'];
            } else {
                $matchString = '';
                $force_partial_word = false;
                foreach ($context['key_words'] as $keyword) {
                    $keyword = preg_replace('~(&amp;#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~e', '$GLOBALS[\'func\'][\'entity_fix\'](\'\\2\')', strtr($keyword, array('\\\'' => '\'', '&' => '&amp;')));
                    if (preg_match('~[\'\\.,/@%&;:(){}\\[\\]_\\-+\\\\]$~', $keyword) != 0 || preg_match('~^[\'\\.,/@%&;:(){}\\[\\]_\\-+\\\\]~', $keyword) != 0) {
                        $force_partial_word = true;
                    }
                    $matchString .= strtr(preg_quote($keyword, '/'), array('\\*' => '.+?')) . '|';
                }
                $matchString = substr($matchString, 0, -1);
                $message['body'] = un_htmlspecialchars(strtr($message['body'], array('&nbsp;' => ' ', '<br />' => "\n", '&#91;' => '[', '&#93;' => ']', '&#58;' => ':', '&#64;' => '@')));
                if (empty($modSettings['search_method']) || $force_partial_word) {
                    preg_match_all('/([^\\s\\W]{' . $charLimit . '}[\\s\\W]|[\\s\\W].{0,' . $charLimit . '}?|^)(' . $matchString . ')(.{0,' . $charLimit . '}[\\s\\W]|[^\\s\\W]{' . $charLimit . '})/is' . ($context['utf8'] ? 'u' : ''), $message['body'], $matches);
                } else {
                    preg_match_all('/([^\\s\\W]{' . $charLimit . '}[\\s\\W]|[\\s\\W].{0,' . $charLimit . '}?[\\s\\W]|^)(' . $matchString . ')([\\s\\W].{0,' . $charLimit . '}[\\s\\W]|[\\s\\W][^\\s\\W]{' . $charLimit . '})/is' . ($context['utf8'] ? 'u' : ''), $message['body'], $matches);
                }
                $message['body'] = '';
                foreach ($matches[0] as $index => $match) {
                    $match = strtr(htmlspecialchars($match, ENT_QUOTES), array("\n" => '<br />'));
                    $message['body'] .= '<b>...</b>&nbsp;' . $match . '&nbsp;<b>...</b><br />';
                }
            }
            // Re-fix the international characters.
            $message['body'] = preg_replace('~(&amp;#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~e', '$GLOBALS[\'func\'][\'entity_fix\'](\'\\2\')', $message['body']);
        }
    } else {
        // Run UBBC interpreter on the message.
        $message['body'] = parse_bbc($message['body'], $message['smileysEnabled'], $message['ID_MSG']);
    }
    // Sadly, we need to check the icon ain't broke.
    if (empty($modSettings['messageIconChecks_disable'])) {
        if (!isset($context['icon_sources'][$message['firstIcon']])) {
            $context['icon_sources'][$message['firstIcon']] = file_exists($settings['theme_dir'] . '/images/post/' . $message['firstIcon'] . '.gif') ? 'images_url' : 'default_images_url';
        }
        if (!isset($context['icon_sources'][$message['lastIcon']])) {
            $context['icon_sources'][$message['lastIcon']] = file_exists($settings['theme_dir'] . '/images/post/' . $message['lastIcon'] . '.gif') ? 'images_url' : 'default_images_url';
        }
        if (!isset($context['icon_sources'][$message['icon']])) {
            $context['icon_sources'][$message['icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $message['icon'] . '.gif') ? 'images_url' : 'default_images_url';
        }
    } else {
        if (!isset($context['icon_sources'][$message['firstIcon']])) {
            $context['icon_sources'][$message['firstIcon']] = 'images_url';
        }
        if (!isset($context['icon_sources'][$message['lastIcon']])) {
            $context['icon_sources'][$message['lastIcon']] = 'images_url';
        }
        if (!isset($context['icon_sources'][$message['icon']])) {
            $context['icon_sources'][$message['icon']] = 'images_url';
        }
    }
    $output = array_merge($context['topics'][$message['ID_MSG']], array('is_sticky' => !empty($modSettings['enableStickyTopics']) && !empty($message['isSticky']), 'is_locked' => !empty($message['locked']), 'is_poll' => $modSettings['pollMode'] == '1' && $message['ID_POLL'] > 0, 'is_hot' => $message['numReplies'] >= $modSettings['hotTopicPosts'], 'is_very_hot' => $message['numReplies'] >= $modSettings['hotTopicVeryPosts'], 'posted_in' => !empty($participants[$message['ID_TOPIC']]), 'views' => $message['numViews'], 'replies' => $message['numReplies'], 'can_reply' => in_array($message['ID_BOARD'], $boards_can['post_reply_any']) || in_array(0, $boards_can['post_reply_any']), 'can_mark_notify' => in_array($message['ID_BOARD'], $boards_can['mark_any_notify']) || in_array(0, $boards_can['mark_any_notify']) && !$context['user']['is_guest'], 'first_post' => array('id' => $message['first_msg'], 'time' => timeformat($message['first_posterTime']), 'timestamp' => forum_time(true, $message['first_posterTime']), 'subject' => $message['first_subject'], 'href' => $scripturl . '?topic=' . $message['ID_TOPIC'] . '.0', 'link' => '<a href="' . $scripturl . '?topic=' . $message['ID_TOPIC'] . '.0">' . $message['first_subject'] . '</a>', 'icon' => $message['firstIcon'], 'icon_url' => $settings[$context['icon_sources'][$message['firstIcon']]] . '/post/' . $message['firstIcon'] . '.gif', 'member' => array('id' => $message['first_member_id'], 'name' => $message['first_member_name'], 'href' => !empty($message['first_member_id']) ? $scripturl . '?action=profile;u=' . $message['first_member_id'] : '', 'link' => !empty($message['first_member_id']) ? '<a href="' . $scripturl . '?action=profile;u=' . $message['first_member_id'] . '" title="' . $txt[92] . ' ' . $message['first_member_name'] . '">' . $message['first_member_name'] . '</a>' : $message['first_member_name'])), 'last_post' => array('id' => $message['last_msg'], 'time' => timeformat($message['last_posterTime']), 'timestamp' => forum_time(true, $message['last_posterTime']), 'subject' => $message['last_subject'], 'href' => $scripturl . '?topic=' . $message['ID_TOPIC'] . ($message['numReplies'] == 0 ? '.0' : '.msg' . $message['last_msg']) . '#msg' . $message['last_msg'], 'link' => '<a href="' . $scripturl . '?topic=' . $message['ID_TOPIC'] . ($message['numReplies'] == 0 ? '.0' : '.msg' . $message['last_msg']) . '#msg' . $message['last_msg'] . '">' . $message['last_subject'] . '</a>', 'icon' => $message['lastIcon'], 'icon_url' => $settings[$context['icon_sources'][$message['lastIcon']]] . '/post/' . $message['lastIcon'] . '.gif', 'member' => array('id' => $message['last_member_id'], 'name' => $message['last_member_name'], 'href' => !empty($message['last_member_id']) ? $scripturl . '?action=profile;u=' . $message['last_member_id'] : '', 'link' => !empty($message['last_member_id']) ? '<a href="' . $scripturl . '?action=profile;u=' . $message['last_member_id'] . '" title="' . $txt[92] . ' ' . $message['last_member_name'] . '">' . $message['last_member_name'] . '</a>' : $message['last_member_name'])), 'board' => array('id' => $message['ID_BOARD'], 'name' => $message['bName'], 'href' => $scripturl . '?board=' . $message['ID_BOARD'] . '.0', 'link' => '<a href="' . $scripturl . '?board=' . $message['ID_BOARD'] . '.0">' . $message['bName'] . '</a>'), 'category' => array('id' => $message['ID_CAT'], 'name' => $message['cName'], 'href' => $scripturl . '#' . $message['ID_CAT'], 'link' => '<a href="' . $scripturl . '#' . $message['ID_CAT'] . '">' . $message['cName'] . '</a>')));
    determineTopicClass($output);
    if ($output['posted_in']) {
        $output['class'] = 'my_' . $output['class'];
    }
    $body_highlighted = $message['body'];
    $subject_highlighted = $message['subject'];
    if (!empty($options['display_quick_mod'])) {
        $started = $output['first_post']['member']['id'] == $ID_MEMBER;
        $output['quick_mod'] = array('lock' => in_array(0, $boards_can['lock_any']) || in_array($output['board']['id'], $boards_can['lock_any']) || $started && (in_array(0, $boards_can['lock_own']) || in_array($output['board']['id'], $boards_can['lock_own'])), 'sticky' => (in_array(0, $boards_can['make_sticky']) || in_array($output['board']['id'], $boards_can['make_sticky'])) && !empty($modSettings['enableStickyTopics']), 'move' => in_array(0, $boards_can['move_any']) || in_array($output['board']['id'], $boards_can['move_any']) || $started && (in_array(0, $boards_can['move_own']) || in_array($output['board']['id'], $boards_can['move_own'])), 'remove' => in_array(0, $boards_can['remove_any']) || in_array($output['board']['id'], $boards_can['remove_any']) || $started && (in_array(0, $boards_can['remove_own']) || in_array($output['board']['id'], $boards_can['remove_own'])));
        $context['can_lock'] |= $output['quick_mod']['lock'];
        $context['can_sticky'] |= $output['quick_mod']['sticky'];
        $context['can_move'] |= $output['quick_mod']['move'];
        $context['can_remove'] |= $output['quick_mod']['remove'];
        $context['can_merge'] |= in_array($output['board']['id'], $boards_can['merge_any']);
    }
    foreach ($context['key_words'] as $query) {
        // Fix the international characters in the keyword too.
        $query = strtr($func['htmlspecialchars']($query), array('\\\'' => '\''));
        $body_highlighted = preg_replace('/((<[^>]*)|' . preg_quote(strtr($query, array('\'' => '&#039;')), '/') . ')/ie' . ($context['utf8'] ? 'u' : ''), "'\$2' == '\$1' ? stripslashes('\$1') : '<b class=\"highlight\">\$1</b>'", $body_highlighted);
        $subject_highlighted = preg_replace('/(' . preg_quote($query, '/') . ')/i' . ($context['utf8'] ? 'u' : ''), '<b class="highlight">$1</b>', $subject_highlighted);
    }
    $output['matches'][] = array('id' => $message['ID_MSG'], 'attachment' => loadAttachmentContext($message['ID_MSG']), 'alternate' => $counter % 2, 'member' => &$memberContext[$message['ID_MEMBER']], 'icon' => $message['icon'], 'icon_url' => $settings[$context['icon_sources'][$message['icon']]] . '/post/' . $message['icon'] . '.gif', 'subject' => $message['subject'], 'subject_highlighted' => $subject_highlighted, 'time' => timeformat($message['posterTime']), 'timestamp' => forum_time(true, $message['posterTime']), 'counter' => $counter, 'modified' => array('time' => timeformat($message['modifiedTime']), 'timestamp' => forum_time(true, $message['modifiedTime']), 'name' => $message['modifiedName']), 'body' => $message['body'], 'body_highlighted' => $body_highlighted, 'start' => 'msg' . $message['ID_MSG']);
    $counter++;
    return $output;
}
Esempio n. 10
0
function Display()
{
    global $scripturl, $txt, $modSettings, $context, $settings, $memberContext, $output;
    global $options, $sourcedir, $user_info, $user_profile, $board_info, $topic, $board;
    global $attachments, $messages_request, $topicinfo, $language;
    $context['response_prefixlen'] = strlen($txt['response_prefix']);
    $context['need_synhlt'] = true;
    $context['is_display_std'] = true;
    $context['pcache_update_counter'] = !empty($modSettings['use_post_cache']) ? 0 : PCACHE_UPDATE_PER_VIEW + 1;
    $context['time_cutoff_ref'] = time();
    $context['template_hooks']['display'] = array('header' => '', 'extend_topicheader' => '', 'above_posts' => '', 'below_posts' => '', 'footer' => '');
    //EoS_Smarty::getConfigInstance()->registerHookTemplate('postbit_below', 'overrides/foo');
    if (!empty($modSettings['karmaMode'])) {
        require_once $sourcedir . '/lib/Subs-Ratings.php';
    } else {
        $context['can_see_like'] = $context['can_give_like'] = false;
    }
    // What are you gonna display if these are empty?!
    if (empty($topic)) {
        fatal_lang_error('no_board', false);
    }
    // Not only does a prefetch make things slower for the server, but it makes it impossible to know if they read it.
    if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') {
        ob_end_clean();
        header('HTTP/1.1 403 Prefetch Forbidden');
        die;
    }
    // How much are we sticking on each page?
    $context['messages_per_page'] = commonAPI::getMessagesPerPage();
    $context['page_number'] = isset($_REQUEST['start']) ? $_REQUEST['start'] / $context['messages_per_page'] : 0;
    // Let's do some work on what to search index.
    //$context['multiquote_cookiename'] = 'mq_' . $context['current_topic'];
    $context['multiquote_posts'] = array();
    if (isset($_COOKIE[$context['multiquote_cookiename']]) && strlen($_COOKIE[$context['multiquote_cookiename']]) > 1) {
        $context['multiquote_posts'] = explode(',', $_COOKIE[$context['multiquote_cookiename']]);
    }
    $context['multiquote_posts_count'] = count($context['multiquote_posts']);
    if (count($_GET) > 2) {
        foreach ($_GET as $k => $v) {
            if (!in_array($k, array('topic', 'board', 'start', session_name()))) {
                $context['robot_no_index'] = true;
            }
        }
    }
    if (!empty($_REQUEST['start']) && (!is_numeric($_REQUEST['start']) || $_REQUEST['start'] % $context['messages_per_page'] != 0)) {
        $context['robot_no_index'] = true;
    }
    // Find the previous or next topic.  Make a fuss if there are no more.
    if (isset($_REQUEST['prev_next']) && ($_REQUEST['prev_next'] == 'prev' || $_REQUEST['prev_next'] == 'next')) {
        // No use in calculating the next topic if there's only one.
        if ($board_info['num_topics'] > 1) {
            // Just prepare some variables that are used in the query.
            $gt_lt = $_REQUEST['prev_next'] == 'prev' ? '>' : '<';
            $order = $_REQUEST['prev_next'] == 'prev' ? '' : ' DESC';
            $request = smf_db_query('
				SELECT t2.id_topic
				FROM {db_prefix}topics AS t
					INNER JOIN {db_prefix}topics AS t2 ON (' . (empty($modSettings['enableStickyTopics']) ? '
					t2.id_last_msg ' . $gt_lt . ' t.id_last_msg' : '
					(t2.id_last_msg ' . $gt_lt . ' t.id_last_msg AND t2.is_sticky ' . $gt_lt . '= t.is_sticky) OR t2.is_sticky ' . $gt_lt . ' t.is_sticky') . ')
				WHERE t.id_topic = {int:current_topic}
					AND t2.id_board = {int:current_board}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
					AND (t2.approved = {int:is_approved} OR (t2.id_member_started != {int:id_member_started} AND t2.id_member_started = {int:current_member}))') . '
				ORDER BY' . (empty($modSettings['enableStickyTopics']) ? '' : ' t2.is_sticky' . $order . ',') . ' t2.id_last_msg' . $order . '
				LIMIT 1', array('current_board' => $board, 'current_member' => $user_info['id'], 'current_topic' => $topic, 'is_approved' => 1, 'id_member_started' => 0));
            // No more left.
            if (mysql_num_rows($request) == 0) {
                mysql_free_result($request);
                // Roll over - if we're going prev, get the last - otherwise the first.
                $request = smf_db_query('
					SELECT id_topic
					FROM {db_prefix}topics
					WHERE id_board = {int:current_board}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
						AND (approved = {int:is_approved} OR (id_member_started != {int:id_member_started} AND id_member_started = {int:current_member}))') . '
					ORDER BY' . (empty($modSettings['enableStickyTopics']) ? '' : ' is_sticky' . $order . ',') . ' id_last_msg' . $order . '
					LIMIT 1', array('current_board' => $board, 'current_member' => $user_info['id'], 'is_approved' => 1, 'id_member_started' => 0));
            }
            // Now you can be sure $topic is the id_topic to view.
            list($topic) = mysql_fetch_row($request);
            mysql_free_result($request);
            $context['current_topic'] = $topic;
        }
        // Go to the newest message on this topic.
        $_REQUEST['start'] = 'new';
    }
    // Add 1 to the number of views of this topic.
    if (empty($_SESSION['last_read_topic']) || $_SESSION['last_read_topic'] != $topic) {
        smf_db_query('
			UPDATE {db_prefix}topics
			SET num_views = num_views + 1
			WHERE id_topic = {int:current_topic}', array('current_topic' => $topic));
        $_SESSION['last_read_topic'] = $topic;
    }
    if ($modSettings['tags_active']) {
        $dbresult = smf_db_query('
		   SELECT t.tag,l.ID,t.ID_TAG FROM {db_prefix}tags_log as l, {db_prefix}tags as t
			WHERE t.ID_TAG = l.ID_TAG && l.ID_TOPIC = {int:topic}', array('topic' => $topic));
        $context['topic_tags'] = array();
        while ($row = mysql_fetch_assoc($dbresult)) {
            $context['topic_tags'][] = array('ID' => $row['ID'], 'ID_TAG' => $row['ID_TAG'], 'tag' => $row['tag']);
        }
        mysql_free_result($dbresult);
        $context['tags_active'] = true;
    } else {
        $context['topic_tags'] = $context['tags_active'] = 0;
    }
    // Get all the important topic info.
    $request = smf_db_query('SELECT
			t.num_replies, t.num_views, t.locked, ms.poster_name, ms.subject, ms.poster_email, ms.poster_time AS first_post_time, t.is_sticky, t.id_poll,
			t.id_member_started, t.id_first_msg, t.id_last_msg, t.approved, t.unapproved_posts, t.id_layout, 
			' . ($user_info['is_guest'] ? 't.id_last_msg + 1' : 'IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1') . ' AS new_from
			' . (!empty($modSettings['recycle_board']) && $modSettings['recycle_board'] == $board ? ', id_previous_board, id_previous_topic' : '') . ',
			p.name AS prefix_name, ms1.poster_time AS last_post_time, ms1.modified_time AS last_modified_time, IFNULL(b.automerge, 0) AS automerge
		FROM {db_prefix}topics AS t
			INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
			INNER JOIN {db_prefix}messages AS ms1 ON (ms1.id_msg = t.id_last_msg)
			INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg)' . ($user_info['is_guest'] ? '' : '
			LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = {int:current_topic} AND lt.id_member = {int:current_member})
			LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = {int:current_board} AND lmr.id_member = {int:current_member})') . '
			LEFT JOIN {db_prefix}prefixes as p ON p.id_prefix = t.id_prefix 
		WHERE t.id_topic = {int:current_topic}
		LIMIT 1', array('current_member' => $user_info['id'], 'current_topic' => $topic, 'current_board' => $board));
    if (mysql_num_rows($request) == 0) {
        fatal_lang_error('not_a_topic', false);
    }
    // Added by Related Topics
    if (isset($modSettings['have_related_topics']) && $modSettings['have_related_topics'] && !empty($modSettings['relatedTopicsEnabled'])) {
        require_once $sourcedir . '/lib/Subs-Related.php';
        loadRelated($topic);
    }
    $topicinfo = mysql_fetch_assoc($request);
    mysql_free_result($request);
    $context['topic_banned_members'] = array();
    $request = smf_db_query('SELECT id_member FROM {db_prefix}topicbans WHERE id_topic = {int:topic}', array('topic' => $topic));
    if (mysql_num_rows($request) != 0) {
        while ($row = mysql_fetch_row($request)) {
            $context['topic_banned_members'][] = $row[0];
        }
    }
    mysql_free_result($request);
    $context['topic_banned_members_count'] = count($context['topic_banned_members']);
    $context['topic_last_modified'] = max($topicinfo['last_post_time'], $topicinfo['last_modified_time']);
    // todo: considering - make post cutoff time for the cache depend on the modification time of the topic's last post
    $context['real_num_replies'] = $context['num_replies'] = $topicinfo['num_replies'];
    $context['topic_first_message'] = $topicinfo['id_first_msg'];
    $context['topic_last_message'] = $topicinfo['id_last_msg'];
    $context['first_subject'] = $topicinfo['subject'];
    $context['prefix'] = !empty($topicinfo['prefix_name']) ? html_entity_decode($topicinfo['prefix_name']) . '&nbsp;' : '';
    $context['automerge'] = $topicinfo['automerge'] > 0;
    // Add up unapproved replies to get real number of replies...
    if ($modSettings['postmod_active'] && allowedTo('approve_posts')) {
        $context['real_num_replies'] += $topicinfo['unapproved_posts'] - ($topicinfo['approved'] ? 0 : 1);
    }
    // If this topic has unapproved posts, we need to work out how many posts the user can see, for page indexing.
    if ($modSettings['postmod_active'] && $topicinfo['unapproved_posts'] && !$user_info['is_guest'] && !allowedTo('approve_posts')) {
        $request = smf_db_query('
			SELECT COUNT(id_member) AS my_unapproved_posts
			FROM {db_prefix}messages
			WHERE id_topic = {int:current_topic}
				AND id_member = {int:current_member}
				AND approved = 0', array('current_topic' => $topic, 'current_member' => $user_info['id']));
        list($myUnapprovedPosts) = mysql_fetch_row($request);
        mysql_free_result($request);
        $context['total_visible_posts'] = $context['num_replies'] + $myUnapprovedPosts + ($topicinfo['approved'] ? 1 : 0);
    } else {
        $context['total_visible_posts'] = $context['num_replies'] + $topicinfo['unapproved_posts'] + ($topicinfo['approved'] ? 1 : 0);
    }
    // When was the last time this topic was replied to?  Should we warn them about it?
    /* redundant query? last_post_time is already in $topicinfo[]
    	$request = smf_db_query( '
    		SELECT poster_time
    		FROM {db_prefix}messages
    		WHERE id_msg = {int:id_last_msg}
    		LIMIT 1',
    		array(
    			'id_last_msg' => $topicinfo['id_last_msg'],
    		)
    	);
    
    	list ($lastPostTime) = mysql_fetch_row($request);
    	mysql_free_result($request);
    	*/
    $lastPostTime = $topicinfo['last_post_time'];
    $context['oldTopicError'] = !empty($modSettings['oldTopicDays']) && $lastPostTime + $modSettings['oldTopicDays'] * 86400 < time() && empty($sticky);
    // The start isn't a number; it's information about what to do, where to go.
    if (!is_numeric($_REQUEST['start'])) {
        // Redirect to the page and post with new messages, originally by Omar Bazavilvazo.
        if ($_REQUEST['start'] == 'new') {
            // Guests automatically go to the last post.
            if ($user_info['is_guest']) {
                $context['start_from'] = $context['total_visible_posts'] - 1;
                $_REQUEST['start'] = empty($options['view_newest_first']) ? $context['start_from'] : 0;
            } else {
                // Find the earliest unread message in the topic. (the use of topics here is just for both tables.)
                $request = smf_db_query('
					SELECT IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1 AS new_from
					FROM {db_prefix}topics AS t
						LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = {int:current_topic} AND lt.id_member = {int:current_member})
						LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = {int:current_board} AND lmr.id_member = {int:current_member})
					WHERE t.id_topic = {int:current_topic}
					LIMIT 1', array('current_board' => $board, 'current_member' => $user_info['id'], 'current_topic' => $topic));
                list($new_from) = mysql_fetch_row($request);
                mysql_free_result($request);
                // Fall through to the next if statement.
                $_REQUEST['start'] = 'msg' . $new_from;
            }
        }
        // Start from a certain time index, not a message.
        if (substr($_REQUEST['start'], 0, 4) == 'from') {
            $timestamp = (int) substr($_REQUEST['start'], 4);
            if ($timestamp === 0) {
                $_REQUEST['start'] = 0;
            } else {
                // Find the number of messages posted before said time...
                $request = smf_db_query('
					SELECT COUNT(*)
					FROM {db_prefix}messages
					WHERE poster_time < {int:timestamp}
						AND id_topic = {int:current_topic}' . ($modSettings['postmod_active'] && $topicinfo['unapproved_posts'] && !allowedTo('approve_posts') ? '
						AND (approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR id_member = {int:current_member}') . ')' : ''), array('current_topic' => $topic, 'current_member' => $user_info['id'], 'is_approved' => 1, 'timestamp' => $timestamp));
                list($context['start_from']) = mysql_fetch_row($request);
                mysql_free_result($request);
                // Handle view_newest_first options, and get the correct start value.
                $_REQUEST['start'] = empty($options['view_newest_first']) ? $context['start_from'] : $context['total_visible_posts'] - $context['start_from'] - 1;
            }
        } elseif (substr($_REQUEST['start'], 0, 3) == 'msg') {
            $virtual_msg = (int) substr($_REQUEST['start'], 3);
            if (!$topicinfo['unapproved_posts'] && $virtual_msg >= $topicinfo['id_last_msg']) {
                $context['start_from'] = $context['total_visible_posts'] - 1;
            } elseif (!$topicinfo['unapproved_posts'] && $virtual_msg <= $topicinfo['id_first_msg']) {
                $context['start_from'] = 0;
            } else {
                // Find the start value for that message......
                $request = smf_db_query('
					SELECT COUNT(*)
					FROM {db_prefix}messages
					WHERE id_msg < {int:virtual_msg}
						AND id_topic = {int:current_topic}' . ($modSettings['postmod_active'] && $topicinfo['unapproved_posts'] && !allowedTo('approve_posts') ? '
						AND (approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR id_member = {int:current_member}') . ')' : ''), array('current_member' => $user_info['id'], 'current_topic' => $topic, 'virtual_msg' => $virtual_msg, 'is_approved' => 1, 'no_member' => 0));
                list($context['start_from']) = mysql_fetch_row($request);
                mysql_free_result($request);
            }
            // We need to reverse the start as well in this case.
            if (isset($_REQUEST['perma'])) {
                $_REQUEST['start'] = $virtual_msg;
            } else {
                $_REQUEST['start'] = empty($options['view_newest_first']) ? $context['start_from'] : $context['total_visible_posts'] - $context['start_from'] - 1;
            }
        }
    }
    // Create a previous next string if the selected theme has it as a selected option.
    $context['previous_next'] = $modSettings['enablePreviousNext'] ? '<a href="' . $scripturl . '?topic=' . $topic . '.0;prev_next=prev#new">' . $txt['previous_next_back'] . '</a> <a href="' . $scripturl . '?topic=' . $topic . '.0;prev_next=next#new">' . $txt['previous_next_forward'] . '</a>' : '';
    // Do we need to show the visual verification image?
    $context['require_verification'] = !$user_info['is_mod'] && !$user_info['is_admin'] && !empty($modSettings['posts_require_captcha']) && ($user_info['posts'] < $modSettings['posts_require_captcha'] || $user_info['is_guest'] && $modSettings['posts_require_captcha'] == -1);
    if ($context['require_verification']) {
        require_once $sourcedir . '/lib/Subs-Editor.php';
        $verificationOptions = array('id' => 'post', 'skip_template' => true);
        $context['require_verification'] = create_control_verification($verificationOptions);
        $context['visual_verification_id'] = $verificationOptions['id'];
    }
    // Are we showing signatures - or disabled fields?
    $context['signature_enabled'] = substr($modSettings['signature_settings'], 0, 1) == 1;
    $context['disabled_fields'] = isset($modSettings['disabled_profile_fields']) ? array_flip(explode(',', $modSettings['disabled_profile_fields'])) : array();
    // Censor the title...
    censorText($topicinfo['subject']);
    $context['page_title'] = $topicinfo['subject'] . ((int) $context['page_number'] > 0 ? ' - ' . $txt['page'] . ' ' . ($context['page_number'] + 1) : '');
    // Is this topic sticky, or can it even be?
    $topicinfo['is_sticky'] = empty($modSettings['enableStickyTopics']) ? '0' : $topicinfo['is_sticky'];
    // Default this topic to not marked for notifications... of course...
    $context['is_marked_notify'] = false;
    // Did we report a post to a moderator just now?
    $context['report_sent'] = isset($_GET['reportsent']);
    // Let's get nosey, who is viewing this topic?
    if (!empty($settings['display_who_viewing'])) {
        // Start out with no one at all viewing it.
        $context['view_members'] = array();
        $context['view_members_list'] = array();
        $context['view_num_hidden'] = 0;
        // Search for members who have this topic set in their GET data.
        $request = smf_db_query('
			SELECT
				lo.id_member, lo.log_time, mem.real_name, mem.member_name, mem.show_online, mem.id_group, mem.id_post_group
			FROM {db_prefix}log_online AS lo
				LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lo.id_member)
			WHERE INSTR(lo.url, {string:in_url_string}) > 0 OR lo.session = {string:session}', array('in_url_string' => 's:5:"topic";i:' . $topic . ';', 'session' => $user_info['is_guest'] ? 'ip' . $user_info['ip'] : session_id()));
        while ($row = mysql_fetch_assoc($request)) {
            if (empty($row['id_member'])) {
                continue;
            }
            $class = 'member group_' . (empty($row['id_group']) ? $row['id_post_group'] : $row['id_group']) . (in_array($row['id_member'], $user_info['buddies']) ? ' buddy' : '');
            $href = URL::user($row['id_member'], $row['real_name']);
            if ($row['id_member'] == $user_info['id']) {
                $link = '<strong>' . $txt['you'] . '</strong>';
            } else {
                $link = '<a onclick="getMcard(' . $row['id_member'] . ');return(false);" class="' . $class . '" href="' . $href . '">' . $row['real_name'] . '</a>';
            }
            // Add them both to the list and to the more detailed list.
            if (!empty($row['show_online']) || allowedTo('moderate_forum')) {
                $context['view_members_list'][$row['log_time'] . $row['member_name']] = empty($row['show_online']) ? '<em>' . $link . '</em>' : $link;
            }
            $context['view_members'][$row['log_time'] . $row['member_name']] = array('id' => $row['id_member'], 'username' => $row['member_name'], 'name' => $row['real_name'], 'group' => $row['id_group'], 'href' => $href, 'link' => $link, 'hidden' => empty($row['show_online']));
            if (empty($row['show_online'])) {
                $context['view_num_hidden']++;
            }
        }
        // The number of guests is equal to the rows minus the ones we actually used ;).
        $context['view_num_guests'] = mysql_num_rows($request) - count($context['view_members']);
        mysql_free_result($request);
        // Sort the list.
        krsort($context['view_members']);
        krsort($context['view_members_list']);
    }
    // If all is set, but not allowed... just unset it.
    $can_show_all = !empty($modSettings['enableAllMessages']) && $context['total_visible_posts'] > $context['messages_per_page'] && $context['total_visible_posts'] < $modSettings['enableAllMessages'];
    if (isset($_REQUEST['all']) && !$can_show_all) {
        unset($_REQUEST['all']);
    } elseif (isset($_REQUEST['all'])) {
        $_REQUEST['start'] = -1;
    }
    // Construct the page index, allowing for the .START method...
    if (!isset($_REQUEST['perma'])) {
        $context['page_index'] = constructPageIndex(URL::topic($topic, $topicinfo['subject'], '%1$d'), $_REQUEST['start'], $context['total_visible_posts'], $context['messages_per_page'], true);
    }
    $context['start'] = $_REQUEST['start'];
    // This is information about which page is current, and which page we're on - in case you don't like the constructed page index. (again, wireles..)
    $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['messages_per_page'] + 1, 'num_pages' => floor(($context['total_visible_posts'] - 1) / $context['messages_per_page']) + 1);
    $context['links'] = array('first' => $_REQUEST['start'] >= $context['messages_per_page'] ? $scripturl . '?topic=' . $topic . '.0' : '', 'prev' => $_REQUEST['start'] >= $context['messages_per_page'] ? $scripturl . '?topic=' . $topic . '.' . ($_REQUEST['start'] - $context['messages_per_page']) : '', 'next' => $_REQUEST['start'] + $context['messages_per_page'] < $context['total_visible_posts'] ? $scripturl . '?topic=' . $topic . '.' . ($_REQUEST['start'] + $context['messages_per_page']) : '', 'last' => $_REQUEST['start'] + $context['messages_per_page'] < $context['total_visible_posts'] ? $scripturl . '?topic=' . $topic . '.' . floor($context['total_visible_posts'] / $context['messages_per_page']) * $context['messages_per_page'] : '', 'up' => $scripturl . '?board=' . $board . '.0');
    // If they are viewing all the posts, show all the posts, otherwise limit the number.
    if ($can_show_all) {
        if (isset($_REQUEST['all'])) {
            // No limit! (actually, there is a limit, but...)
            $context['messages_per_page'] = -1;
            $context['page_index'] .= '[<strong>' . $txt['all'] . '</strong>] ';
            // Set start back to 0...
            $_REQUEST['start'] = 0;
        } else {
            if (!isset($context['page_index'])) {
                $context['page_index'] = '';
            }
            $context['page_index'] .= '&nbsp;<a href="' . $scripturl . '?topic=' . $topic . '.0;all">' . $txt['all'] . '</a> ';
        }
    }
    // Build the link tree.
    $context['linktree'][] = array('url' => URL::topic($topic, $topicinfo['subject'], 0), 'name' => $topicinfo['subject'], 'extra_before' => $settings['linktree_inline'] ? $txt['topic'] . ': ' : '');
    // Build a list of this board's moderators.
    $context['moderators'] =& $board_info['moderators'];
    $context['link_moderators'] = array();
    if (!empty($board_info['moderators'])) {
        // Add a link for each moderator...
        foreach ($board_info['moderators'] as $mod) {
            $context['link_moderators'][] = '<a href="' . $scripturl . '?action=profile;u=' . $mod['id'] . '" title="' . $txt['board_moderator'] . '">' . $mod['name'] . '</a>';
        }
        // And show it after the board's name.
        //$context['linktree'][count($context['linktree']) - 2]['extra_after'] = ' (' . (count($context['link_moderators']) == 1 ? $txt['moderator'] : $txt['moderators']) . ': ' . implode(', ', $context['link_moderators']) . ')';
    }
    // Information about the current topic...
    $context['is_locked'] = $topicinfo['locked'];
    $context['is_sticky'] = $topicinfo['is_sticky'];
    $context['is_very_hot'] = $topicinfo['num_replies'] >= $modSettings['hotTopicVeryPosts'];
    $context['is_hot'] = $topicinfo['num_replies'] >= $modSettings['hotTopicPosts'];
    $context['is_approved'] = $topicinfo['approved'];
    // We don't want to show the poll icon in the topic class here, so pretend it's not one.
    $context['is_poll'] = false;
    determineTopicClass($context);
    $context['is_poll'] = $topicinfo['id_poll'] > 0 && $modSettings['pollMode'] == '1' && allowedTo('poll_view');
    // Did this user start the topic or not?
    $context['user']['started'] = $user_info['id'] == $topicinfo['id_member_started'] && !$user_info['is_guest'];
    $context['topic_starter_id'] = $topicinfo['id_member_started'];
    // Set the topic's information for the template.
    $context['subject'] = $topicinfo['subject'];
    $context['num_views'] = $topicinfo['num_views'];
    $context['mark_unread_time'] = $topicinfo['new_from'];
    // Set a canonical URL for this page.
    $context['canonical_url'] = URL::topic($topic, $topicinfo['subject'], $context['start']);
    $context['share_url'] = $scripturl . '?topic=' . $topic;
    // For quick reply we need a response prefix in the default forum language.
    if (!isset($context['response_prefix']) && !($context['response_prefix'] = CacheAPI::getCache('response_prefix', 600))) {
        if ($language === $user_info['language']) {
            $context['response_prefix'] = $txt['response_prefix'];
        } else {
            loadLanguage('index', $language, false);
            $context['response_prefix'] = $txt['response_prefix'];
            loadLanguage('index');
        }
        CacheAPI::putCache('response_prefix', $context['response_prefix'], 600);
    }
    // If we want to show event information in the topic, prepare the data.
    if (allowedTo('calendar_view') && !empty($modSettings['cal_showInTopic']) && !empty($modSettings['cal_enabled'])) {
        // First, try create a better time format, ignoring the "time" elements.
        if (preg_match('~%[AaBbCcDdeGghjmuYy](?:[^%]*%[AaBbCcDdeGghjmuYy])*~', $user_info['time_format'], $matches) == 0 || empty($matches[0])) {
            $date_string = $user_info['time_format'];
        } else {
            $date_string = $matches[0];
        }
        // Any calendar information for this topic?
        $request = smf_db_query('
			SELECT cal.id_event, cal.start_date, cal.end_date, cal.title, cal.id_member, mem.real_name
			FROM {db_prefix}calendar AS cal
				LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = cal.id_member)
			WHERE cal.id_topic = {int:current_topic}
			ORDER BY start_date', array('current_topic' => $topic));
        $context['linked_calendar_events'] = array();
        while ($row = mysql_fetch_assoc($request)) {
            // Prepare the dates for being formatted.
            $start_date = sscanf($row['start_date'], '%04d-%02d-%02d');
            $start_date = mktime(12, 0, 0, $start_date[1], $start_date[2], $start_date[0]);
            $end_date = sscanf($row['end_date'], '%04d-%02d-%02d');
            $end_date = mktime(12, 0, 0, $end_date[1], $end_date[2], $end_date[0]);
            $context['linked_calendar_events'][] = array('id' => $row['id_event'], 'title' => $row['title'], 'can_edit' => allowedTo('calendar_edit_any') || $row['id_member'] == $user_info['id'] && allowedTo('calendar_edit_own'), 'modify_href' => $scripturl . '?action=post;msg=' . $topicinfo['id_first_msg'] . ';topic=' . $topic . '.0;calendar;eventid=' . $row['id_event'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'start_date' => timeformat_static($start_date, $date_string, 'none'), 'start_timestamp' => $start_date, 'end_date' => timeformat_static($end_date, $date_string, 'none'), 'end_timestamp' => $end_date, 'is_last' => false);
        }
        mysql_free_result($request);
        if (!empty($context['linked_calendar_events'])) {
            $context['linked_calendar_events'][count($context['linked_calendar_events']) - 1]['is_last'] = true;
        }
    }
    // Create the poll info if it exists.
    if ($context['is_poll']) {
        // Get the question and if it's locked.
        $request = smf_db_query('
			SELECT
				p.question, p.voting_locked, p.hide_results, p.expire_time, p.max_votes, p.change_vote,
				p.guest_vote, p.id_member, IFNULL(mem.real_name, p.poster_name) AS poster_name, p.num_guest_voters, p.reset_poll
			FROM {db_prefix}polls AS p
				LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = p.id_member)
			WHERE p.id_poll = {int:id_poll}
			LIMIT 1', array('id_poll' => $topicinfo['id_poll']));
        $pollinfo = mysql_fetch_assoc($request);
        mysql_free_result($request);
        $request = smf_db_query('
			SELECT COUNT(DISTINCT id_member) AS total
			FROM {db_prefix}log_polls
			WHERE id_poll = {int:id_poll}
				AND id_member != {int:not_guest}', array('id_poll' => $topicinfo['id_poll'], 'not_guest' => 0));
        list($pollinfo['total']) = mysql_fetch_row($request);
        mysql_free_result($request);
        // Total voters needs to include guest voters
        $pollinfo['total'] += $pollinfo['num_guest_voters'];
        // Get all the options, and calculate the total votes.
        $request = smf_db_query('
			SELECT pc.id_choice, pc.label, pc.votes, IFNULL(lp.id_choice, -1) AS voted_this
			FROM {db_prefix}poll_choices AS pc
				LEFT JOIN {db_prefix}log_polls AS lp ON (lp.id_choice = pc.id_choice AND lp.id_poll = {int:id_poll} AND lp.id_member = {int:current_member} AND lp.id_member != {int:not_guest})
			WHERE pc.id_poll = {int:id_poll}', array('current_member' => $user_info['id'], 'id_poll' => $topicinfo['id_poll'], 'not_guest' => 0));
        $pollOptions = array();
        $realtotal = 0;
        $pollinfo['has_voted'] = false;
        while ($row = mysql_fetch_assoc($request)) {
            censorText($row['label']);
            $pollOptions[$row['id_choice']] = $row;
            $realtotal += $row['votes'];
            $pollinfo['has_voted'] |= $row['voted_this'] != -1;
        }
        mysql_free_result($request);
        // If this is a guest we need to do our best to work out if they have voted, and what they voted for.
        if ($user_info['is_guest'] && $pollinfo['guest_vote'] && allowedTo('poll_vote')) {
            if (!empty($_COOKIE['guest_poll_vote']) && preg_match('~^[0-9,;]+$~', $_COOKIE['guest_poll_vote']) && strpos($_COOKIE['guest_poll_vote'], ';' . $topicinfo['id_poll'] . ',') !== false) {
                // ;id,timestamp,[vote,vote...]; etc
                $guestinfo = explode(';', $_COOKIE['guest_poll_vote']);
                // Find the poll we're after.
                foreach ($guestinfo as $i => $guestvoted) {
                    $guestvoted = explode(',', $guestvoted);
                    if ($guestvoted[0] == $topicinfo['id_poll']) {
                        break;
                    }
                }
                // Has the poll been reset since guest voted?
                if ($pollinfo['reset_poll'] > $guestvoted[1]) {
                    // Remove the poll info from the cookie to allow guest to vote again
                    unset($guestinfo[$i]);
                    if (!empty($guestinfo)) {
                        $_COOKIE['guest_poll_vote'] = ';' . implode(';', $guestinfo);
                    } else {
                        unset($_COOKIE['guest_poll_vote']);
                    }
                } else {
                    // What did they vote for?
                    unset($guestvoted[0], $guestvoted[1]);
                    foreach ($pollOptions as $choice => $details) {
                        $pollOptions[$choice]['voted_this'] = in_array($choice, $guestvoted) ? 1 : -1;
                        $pollinfo['has_voted'] |= $pollOptions[$choice]['voted_this'] != -1;
                    }
                    unset($choice, $details, $guestvoted);
                }
                unset($guestinfo, $guestvoted, $i);
            }
        }
        // Set up the basic poll information.
        $context['poll'] = array('id' => $topicinfo['id_poll'], 'image' => 'normal_' . (empty($pollinfo['voting_locked']) ? 'poll' : 'locked_poll'), 'question' => parse_bbc($pollinfo['question']), 'total_votes' => $pollinfo['total'], 'change_vote' => !empty($pollinfo['change_vote']), 'is_locked' => !empty($pollinfo['voting_locked']), 'options' => array(), 'lock' => allowedTo('poll_lock_any') || $context['user']['started'] && allowedTo('poll_lock_own'), 'edit' => allowedTo('poll_edit_any') || $context['user']['started'] && allowedTo('poll_edit_own'), 'allowed_warning' => $pollinfo['max_votes'] > 1 ? sprintf($txt['poll_options6'], min(count($pollOptions), $pollinfo['max_votes'])) : '', 'is_expired' => !empty($pollinfo['expire_time']) && $pollinfo['expire_time'] < time(), 'expire_time' => !empty($pollinfo['expire_time']) ? timeformat($pollinfo['expire_time']) : 0, 'has_voted' => !empty($pollinfo['has_voted']), 'starter' => array('id' => $pollinfo['id_member'], 'name' => $row['poster_name'], 'href' => $pollinfo['id_member'] == 0 ? '' : $scripturl . '?action=profile;u=' . $pollinfo['id_member'], 'link' => $pollinfo['id_member'] == 0 ? $row['poster_name'] : '<a href="' . $scripturl . '?action=profile;u=' . $pollinfo['id_member'] . '">' . $row['poster_name'] . '</a>'));
        // Make the lock and edit permissions defined above more directly accessible.
        $context['allow_lock_poll'] = $context['poll']['lock'];
        $context['allow_edit_poll'] = $context['poll']['edit'];
        // You're allowed to vote if:
        // 1. the poll did not expire, and
        // 2. you're either not a guest OR guest voting is enabled... and
        // 3. you're not trying to view the results, and
        // 4. the poll is not locked, and
        // 5. you have the proper permissions, and
        // 6. you haven't already voted before.
        $context['allow_vote'] = !$context['poll']['is_expired'] && (!$user_info['is_guest'] || $pollinfo['guest_vote'] && allowedTo('poll_vote')) && empty($pollinfo['voting_locked']) && allowedTo('poll_vote') && !$context['poll']['has_voted'];
        // You're allowed to view the results if:
        // 1. you're just a super-nice-guy, or
        // 2. anyone can see them (hide_results == 0), or
        // 3. you can see them after you voted (hide_results == 1), or
        // 4. you've waited long enough for the poll to expire. (whether hide_results is 1 or 2.)
        $context['allow_poll_view'] = allowedTo('moderate_board') || $pollinfo['hide_results'] == 0 || $pollinfo['hide_results'] == 1 && $context['poll']['has_voted'] || $context['poll']['is_expired'];
        $context['poll']['show_results'] = $context['allow_poll_view'] && (isset($_REQUEST['viewresults']) || isset($_REQUEST['viewResults']));
        $context['show_view_results_button'] = $context['allow_vote'] && (!$context['allow_poll_view'] || !$context['poll']['show_results'] || !$context['poll']['has_voted']);
        // You're allowed to change your vote if:
        // 1. the poll did not expire, and
        // 2. you're not a guest... and
        // 3. the poll is not locked, and
        // 4. you have the proper permissions, and
        // 5. you have already voted, and
        // 6. the poll creator has said you can!
        $context['allow_change_vote'] = !$context['poll']['is_expired'] && !$user_info['is_guest'] && empty($pollinfo['voting_locked']) && allowedTo('poll_vote') && $context['poll']['has_voted'] && $context['poll']['change_vote'];
        // You're allowed to return to voting options if:
        // 1. you are (still) allowed to vote.
        // 2. you are currently seeing the results.
        $context['allow_return_vote'] = $context['allow_vote'] && $context['poll']['show_results'];
        // Calculate the percentages and bar lengths...
        $divisor = $realtotal == 0 ? 1 : $realtotal;
        // Determine if a decimal point is needed in order for the options to add to 100%.
        $precision = $realtotal == 100 ? 0 : 1;
        // Now look through each option, and...
        foreach ($pollOptions as $i => $option) {
            // First calculate the percentage, and then the width of the bar...
            $bar = round($option['votes'] * 100 / $divisor, $precision);
            $barWide = $bar == 0 ? 1 : floor($bar * 8 / 3);
            // Now add it to the poll's contextual theme data.
            $context['poll']['options'][$i] = array('id' => 'options-' . $i, 'percent' => $bar, 'votes' => $option['votes'], 'voted_this' => $option['voted_this'] != -1, 'bar' => '<span style="white-space: nowrap;"><img src="' . $settings['images_url'] . '/poll_' . ($context['right_to_left'] ? 'right' : 'left') . '.gif" alt="" /><img src="' . $settings['images_url'] . '/poll_middle.gif" width="' . $barWide . '" height="12" alt="-" /><img src="' . $settings['images_url'] . '/poll_' . ($context['right_to_left'] ? 'left' : 'right') . '.gif" alt="" /></span>', 'bar_ndt' => $bar > 0 ? '<div class="bar" style="width: ' . ($bar * 3.5 + 4) . 'px;"></div>' : '', 'bar_width' => $barWide, 'option' => parse_bbc($option['label']), 'vote_button' => '<input type="' . ($pollinfo['max_votes'] > 1 ? 'checkbox' : 'radio') . '" name="options[]" id="options-' . $i . '" value="' . $i . '" class="input_' . ($pollinfo['max_votes'] > 1 ? 'check' : 'radio') . '" />');
        }
    }
    // Calculate the fastest way to get the messages!
    $ascending = empty($options['view_newest_first']);
    $start = $_REQUEST['start'];
    $limit = $context['messages_per_page'];
    $firstIndex = 0;
    if ($start >= $context['total_visible_posts'] / 2 && $context['messages_per_page'] != -1) {
        $ascending = !$ascending;
        $limit = $context['total_visible_posts'] <= $start + $limit ? $context['total_visible_posts'] - $start : $limit;
        $start = $context['total_visible_posts'] <= $start + $limit ? 0 : $context['total_visible_posts'] - $start - $limit;
        $firstIndex = $limit - 1;
    }
    if (!isset($_REQUEST['perma'])) {
        // Get each post and poster in this topic.
        $request = smf_db_query('
			SELECT id_msg, id_member, approved
			FROM {db_prefix}messages
			WHERE id_topic = {int:current_topic}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : (!empty($modSettings['db_mysql_group_by_fix']) ? '' : '
			GROUP BY id_msg') . '
			HAVING (approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR id_member = {int:current_member}') . ')') . '
			ORDER BY id_msg ' . ($ascending ? '' : 'DESC') . ($context['messages_per_page'] == -1 ? '' : '
			LIMIT ' . $start . ', ' . $limit), array('current_member' => $user_info['id'], 'current_topic' => $topic, 'is_approved' => 1, 'blank_id_member' => 0));
        $messages = array();
        $all_posters = array();
        while ($row = mysql_fetch_assoc($request)) {
            if (!empty($row['id_member'])) {
                $all_posters[$row['id_msg']] = $row['id_member'];
            }
            $messages[] = $row['id_msg'];
        }
        mysql_free_result($request);
        $posters[$context['topic_first_message']] = $context['topic_starter_id'];
        $posters = array_unique($all_posters);
    } else {
        $request = smf_db_query('
			SELECT id_member, approved
			FROM {db_prefix}messages
			WHERE id_msg = {int:id_msg}', array('id_msg' => $virtual_msg));
        list($id_member, $approved) = mysql_fetch_row($request);
        mysql_free_result($request);
        EoS_Smarty::loadTemplate('topic/topic_singlepost');
        //loadTemplate('DisplaySingle');
        $context['sub_template'] = isset($_REQUEST['xml']) ? 'single_post_xml' : 'single_post';
        if (isset($_REQUEST['xml'])) {
            $context['template_layers'] = array();
            header('Content-Type: text/xml; charset=UTF-8');
        }
        $messages = array($virtual_msg);
        $posters[$virtual_msg] = $id_member;
    }
    // Guests can't mark topics read or for notifications, just can't sorry.
    if (!$user_info['is_guest']) {
        $mark_at_msg = max($messages);
        if ($mark_at_msg >= $topicinfo['id_last_msg']) {
            $mark_at_msg = $modSettings['maxMsgID'];
        }
        if ($mark_at_msg >= $topicinfo['new_from']) {
            smf_db_insert($topicinfo['new_from'] == 0 ? 'ignore' : 'replace', '{db_prefix}log_topics', array('id_member' => 'int', 'id_topic' => 'int', 'id_msg' => 'int'), array($user_info['id'], $topic, $mark_at_msg), array('id_member', 'id_topic'));
        }
        // Check for notifications on this topic OR board.
        $request = smf_db_query('
			SELECT sent, id_topic
			FROM {db_prefix}log_notify
			WHERE (id_topic = {int:current_topic} OR id_board = {int:current_board})
				AND id_member = {int:current_member}
			LIMIT 2', array('current_board' => $board, 'current_member' => $user_info['id'], 'current_topic' => $topic));
        $do_once = true;
        while ($row = mysql_fetch_assoc($request)) {
            // Find if this topic is marked for notification...
            if (!empty($row['id_topic'])) {
                $context['is_marked_notify'] = true;
            }
            // Only do this once, but mark the notifications as "not sent yet" for next time.
            if (!empty($row['sent']) && $do_once) {
                smf_db_query('
					UPDATE {db_prefix}log_notify
					SET sent = {int:is_not_sent}
					WHERE (id_topic = {int:current_topic} OR id_board = {int:current_board})
						AND id_member = {int:current_member}', array('current_board' => $board, 'current_member' => $user_info['id'], 'current_topic' => $topic, 'is_not_sent' => 0));
                $do_once = false;
            }
        }
        // Have we recently cached the number of new topics in this board, and it's still a lot?
        if (isset($_REQUEST['topicseen']) && isset($_SESSION['topicseen_cache'][$board]) && $_SESSION['topicseen_cache'][$board] > 5) {
            $_SESSION['topicseen_cache'][$board]--;
        } elseif (isset($_REQUEST['topicseen'])) {
            // Use the mark read tables... and the last visit to figure out if this should be read or not.
            $request = smf_db_query('
				SELECT COUNT(*)
				FROM {db_prefix}topics AS t
					LEFT JOIN {db_prefix}log_boards AS lb ON (lb.id_board = {int:current_board} AND lb.id_member = {int:current_member})
					LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})
				WHERE t.id_board = {int:current_board}
					AND t.id_last_msg > IFNULL(lb.id_msg, 0)
					AND t.id_last_msg > IFNULL(lt.id_msg, 0)' . (empty($_SESSION['id_msg_last_visit']) ? '' : '
					AND t.id_last_msg > {int:id_msg_last_visit}'), array('current_board' => $board, 'current_member' => $user_info['id'], 'id_msg_last_visit' => (int) $_SESSION['id_msg_last_visit']));
            list($numNewTopics) = mysql_fetch_row($request);
            mysql_free_result($request);
            // If there're no real new topics in this board, mark the board as seen.
            if (empty($numNewTopics)) {
                $_REQUEST['boardseen'] = true;
            } else {
                $_SESSION['topicseen_cache'][$board] = $numNewTopics;
            }
        } elseif (isset($_SESSION['topicseen_cache'][$board])) {
            $_SESSION['topicseen_cache'][$board]--;
        }
        // Mark board as seen if we came using last post link from BoardIndex. (or other places...)
        if (isset($_REQUEST['boardseen'])) {
            smf_db_insert('replace', '{db_prefix}log_boards', array('id_msg' => 'int', 'id_member' => 'int', 'id_board' => 'int'), array($modSettings['maxMsgID'], $user_info['id'], $board), array('id_member', 'id_board'));
        }
    }
    $attachments = array();
    // deal with possible sticky posts and different postbit layouts for
    // the first post
    // topic.id_layout meanings: bit 0-6 > layout id, bit 7 > first post sticky on every page.
    // don't blame me for using bit magic here. I'm a C guy and a 8bits can store more than just one bool :P
    $layout = (int) ($topicinfo['id_layout'] & 0x7f);
    $postbit_classes =& EoS_Smarty::getConfigInstance()->getPostbitClasses();
    // set defaults...
    $context['postbit_callbacks'] = array('firstpost' => 'template_postbit_normal', 'post' => 'template_postbit_normal');
    $context['postbit_template_class'] = array('firstpost' => $postbit_classes['normal'], 'post' => $postbit_classes['normal']);
    if ($topicinfo['id_layout']) {
        $this_start = isset($_REQUEST['perma']) ? 0 : (int) $_REQUEST['start'];
        if ((int) $topicinfo['id_layout'] & 0x80) {
            if ($this_start > 0) {
                array_unshift($messages, intval($topicinfo['id_first_msg']));
            }
            $context['postbit_callbacks']['firstpost'] = $layout == 0 ? 'template_postbit_normal' : ($layout == 2 ? 'template_postbit_clean' : 'template_postbit_lean');
            $context['postbit_callbacks']['post'] = $layout == 2 ? 'template_postbit_comment' : 'template_postbit_normal';
            $context['postbit_template_class']['firstpost'] = $layout == 0 ? $postbit_classes['normal'] : ($layout == 2 ? $postbit_classes['article'] : $postbit_classes['lean']);
            $context['postbit_template_class']['post'] = $layout == 2 ? $postbit_classes['commentstyle'] : $postbit_classes['normal'];
        } elseif ($layout) {
            $context['postbit_callbacks']['firstpost'] = $layout == 0 || $this_start != 0 ? 'template_postbit_normal' : ($layout == 2 ? 'template_postbit_clean' : 'template_postbit_lean');
            $context['postbit_callbacks']['post'] = $layout == 2 ? 'template_postbit_comment' : 'template_postbit_normal';
            $context['postbit_template_class']['firstpost'] = $layout == 0 || $this_start != 0 ? $postbit_classes['normal'] : ($layout == 2 ? $postbit_classes['article'] : $postbit_classes['lean']);
            $context['postbit_template_class']['post'] = $layout == 2 ? $postbit_classes['commentstyle'] : $postbit_classes['normal'];
        }
    }
    // now we know which display template we need
    if (!isset($_REQUEST['perma'])) {
        EoS_Smarty::loadTemplate($layout > 1 ? 'topic/topic_page' : 'topic/topic');
    }
    /*
    if($user_info['is_admin']) {
    	EoS_Smarty::init();
    	if(!isset($_REQUEST['perma']))
    		EoS_Smarty::loadTemplate($layout > 1 ? 'topic_page' : 'topic');
    }
    else {
    	if(!isset($_REQUEST['perma']))
    		loadTemplate($layout > 1 ? 'DisplayPage' : 'Display');
    	loadTemplate('Postbit');
    }
    */
    // If there _are_ messages here... (probably an error otherwise :!)
    if (!empty($messages)) {
        // Fetch attachments.
        if (!empty($modSettings['attachmentEnable']) && allowedTo('view_attachments')) {
            $request = smf_db_query('
				SELECT
					a.id_attach, a.id_folder, a.id_msg, a.filename, a.file_hash, IFNULL(a.size, 0) AS filesize, a.downloads, a.approved,
					a.width, a.height' . (empty($modSettings['attachmentShowImages']) || empty($modSettings['attachmentThumbnails']) ? '' : ',
					IFNULL(thumb.id_attach, 0) AS id_thumb, thumb.width AS thumb_width, thumb.height AS thumb_height') . '
				FROM {db_prefix}attachments AS a' . (empty($modSettings['attachmentShowImages']) || empty($modSettings['attachmentThumbnails']) ? '' : '
					LEFT JOIN {db_prefix}attachments AS thumb ON (thumb.id_attach = a.id_thumb)') . '
				WHERE a.id_msg IN ({array_int:message_list})
					AND a.attachment_type = {int:attachment_type}', array('message_list' => $messages, 'attachment_type' => 0, 'is_approved' => 1));
            $temp = array();
            while ($row = mysql_fetch_assoc($request)) {
                if (!$row['approved'] && $modSettings['postmod_active'] && !allowedTo('approve_posts') && (!isset($all_posters[$row['id_msg']]) || $all_posters[$row['id_msg']] != $user_info['id'])) {
                    continue;
                }
                $temp[$row['id_attach']] = $row;
                if (!isset($attachments[$row['id_msg']])) {
                    $attachments[$row['id_msg']] = array();
                }
            }
            mysql_free_result($request);
            // This is better than sorting it with the query...
            ksort($temp);
            foreach ($temp as $row) {
                $attachments[$row['id_msg']][] = $row;
            }
        }
        // What?  It's not like it *couldn't* be only guests in this topic...
        if (!isset($posters[$context['topic_starter_id']])) {
            $posters[] = $context['topic_starter_id'];
        }
        if (!empty($posters)) {
            loadMemberData($posters);
        }
        if (!isset($user_profile[$context['topic_starter_id']])) {
            $context['topicstarter']['name'] = $topicinfo['poster_name'];
            $context['topicstarter']['id'] = 0;
            $context['topicstarter']['group'] = $txt['guest_title'];
            $context['topicstarter']['link'] = $topicinfo['poster_name'];
            $context['topicstarter']['email'] = $topicinfo['poster_email'];
            $context['topicstarter']['show_email'] = showEmailAddress(true, 0);
            $context['topicstarter']['is_guest'] = true;
            $context['topicstarter']['avatar'] = array();
        } else {
            loadMemberContext($context['topic_starter_id'], true);
            $context['topicstarter'] =& $memberContext[$context['topic_starter_id']];
        }
        $context['topicstarter']['start_time'] = timeformat($topicinfo['first_post_time']);
        $sql_what = '
			m.id_msg, m.icon, m.subject, m.poster_time, m.poster_ip, m.id_member, m.modified_time, m.modified_name, m.body, mc.body AS cached_body,
			m.smileys_enabled, m.poster_name, m.poster_email, m.approved, m.locked,' . (!empty($modSettings['karmaMode']) ? 'c.likes_count, c.like_status, c.updated AS like_updated, l.rtype AS liked,' : '0 AS likes_count, 0 AS like_status, 0 AS like_updated, 0 AS liked,') . '
			m.id_msg_modified < {int:new_from} AS is_read';
        $sql_from_tables = '
			FROM {db_prefix}messages AS m';
        $sql_from_joins = (!empty($modSettings['karmaMode']) ? '
			LEFT JOIN {db_prefix}likes AS l ON (l.id_msg = m.id_msg AND l.ctype = 1 AND l.id_user = {int:id_user})
			LEFT JOIN {db_prefix}like_cache AS c ON (c.id_msg = m.id_msg AND c.ctype = 1)' : '') . '
			LEFT JOIN {db_prefix}messages_cache AS mc on mc.id_msg = m.id_msg AND mc.style = {int:style} AND mc.lang = {int:lang}';
        $sql_array = array('message_list' => $messages, 'new_from' => $topicinfo['new_from'], 'style' => $user_info['smiley_set_id'], 'lang' => $user_info['language_id'], 'id_user' => $user_info['id']);
        HookAPI::callHook('display_messagerequest', array(&$sql_what, &$sql_from_tables, &$sql_from_joins, &$sql_array));
        $messages_request = smf_db_query('
			SELECT ' . $sql_what . ' ' . $sql_from_tables . $sql_from_joins . '
			WHERE m.id_msg IN ({array_int:message_list})
			ORDER BY m.id_msg' . (empty($options['view_newest_first']) ? '' : ' DESC'), $sql_array);
        // Go to the last message if the given time is beyond the time of the last message.
        if (isset($context['start_from']) && $context['start_from'] >= $topicinfo['num_replies']) {
            $context['start_from'] = $topicinfo['num_replies'];
        }
        // Since the anchor information is needed on the top of the page we load these variables beforehand.
        $context['first_message'] = isset($messages[$firstIndex]) ? $messages[$firstIndex] : $messages[0];
        if (empty($options['view_newest_first'])) {
            $context['first_new_message'] = isset($context['start_from']) && $_REQUEST['start'] == $context['start_from'];
        } else {
            $context['first_new_message'] = isset($context['start_from']) && $_REQUEST['start'] == $topicinfo['num_replies'] - $context['start_from'];
        }
    } else {
        $messages_request = false;
        $context['first_message'] = 0;
        $context['first_new_message'] = false;
    }
    $context['jump_to'] = array('label' => addslashes(un_htmlspecialchars($txt['jump_to'])), 'board_name' => htmlspecialchars(strtr(strip_tags($board_info['name']), array('&amp;' => '&'))), 'child_level' => $board_info['child_level']);
    // Set the callback.  (do you REALIZE how much memory all the messages would take?!?)
    $context['get_message'] = 'prepareDisplayContext';
    // Now set all the wonderful, wonderful permissions... like moderation ones...
    $common_permissions = array('can_approve' => 'approve_posts', 'can_ban' => 'manage_bans', 'can_sticky' => 'make_sticky', 'can_merge' => 'merge_any', 'can_split' => 'split_any', 'calendar_post' => 'calendar_post', 'can_mark_notify' => 'mark_any_notify', 'can_send_topic' => 'send_topic', 'can_send_pm' => 'pm_send', 'can_report_moderator' => 'report_any', 'can_moderate_forum' => 'moderate_forum', 'can_issue_warning' => 'issue_warning', 'can_restore_topic' => 'move_any', 'can_restore_msg' => 'move_any');
    foreach ($common_permissions as $contextual => $perm) {
        $context[$contextual] = allowedTo($perm);
    }
    // Permissions with _any/_own versions.  $context[YYY] => ZZZ_any/_own.
    $anyown_permissions = array('can_move' => 'move', 'can_lock' => 'lock', 'can_delete' => 'remove', 'can_add_poll' => 'poll_add', 'can_remove_poll' => 'poll_remove', 'can_reply' => 'post_reply', 'can_reply_unapproved' => 'post_unapproved_replies');
    foreach ($anyown_permissions as $contextual => $perm) {
        $context[$contextual] = allowedTo($perm . '_any') || $context['user']['started'] && allowedTo($perm . '_own');
    }
    $context['can_add_tags'] = $context['user']['started'] && allowedTo('smftags_add') || allowedTo('smftags_manage');
    $context['can_delete_tags'] = $context['user']['started'] && allowedTo('smftags_del') || allowedTo('smftags_manage');
    $context['can_moderate_board'] = allowedTo('moderate_board');
    $context['can_modify_any'] = allowedTo('modify_any');
    $context['can_modify_replies'] = allowedTo('modify_replies');
    $context['can_modify_own'] = allowedTo('modify_own');
    $context['can_delete_any'] = allowedTo('delete_any');
    $context['can_delete_replies'] = allowedTo('delete_replies');
    $context['can_delete_own'] = allowedTo('delete_own');
    $context['use_share'] = !$user_info['possibly_robot'] && allowedTo('use_share') && ($context['user']['is_guest'] || (empty($options['use_share_bar']) ? 1 : !$options['use_share_bar']));
    $context['can_unapprove'] = $context['can_approve'] && !empty($modSettings['postmod_active']);
    $context['can_profile_view_any'] = allowedTo('profile_view_any');
    $context['can_profile_view_own'] = allowedTo('profile_view_own');
    $context['is_banned_from_topic'] = !$user_info['is_admin'] && !$context['can_moderate_forum'] && !$context['can_moderate_board'] && (!empty($context['topic_banned_members']) ? in_array($user_info['id'], $context['topic_banned_members']) : false);
    $context['banned_notice'] = $context['is_banned_from_topic'] ? $txt['topic_banned_notice'] : '';
    // Cleanup all the permissions with extra stuff...
    $context['can_mark_notify'] &= !$context['user']['is_guest'];
    $context['can_sticky'] &= !empty($modSettings['enableStickyTopics']);
    $context['calendar_post'] &= !empty($modSettings['cal_enabled']);
    $context['can_add_poll'] &= $modSettings['pollMode'] == '1' && $topicinfo['id_poll'] <= 0;
    $context['can_remove_poll'] &= $modSettings['pollMode'] == '1' && $topicinfo['id_poll'] > 0;
    $context['can_reply'] &= empty($topicinfo['locked']) || allowedTo('moderate_board');
    $context['can_reply_unapproved'] &= $modSettings['postmod_active'] && (empty($topicinfo['locked']) || allowedTo('moderate_board'));
    $context['can_issue_warning'] &= in_array('w', $context['admin_features']) && $modSettings['warning_settings'][0] == 1;
    // Handle approval flags...
    $context['can_reply_approved'] = $context['can_reply'];
    $context['can_reply'] |= $context['can_reply_unapproved'];
    $context['can_quote'] = $context['can_reply'] && (empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC'])));
    $context['can_mark_unread'] = !$user_info['is_guest'] && $settings['show_mark_read'];
    $context['can_send_topic'] = (!$modSettings['postmod_active'] || $topicinfo['approved']) && allowedTo('send_topic');
    // Start this off for quick moderation - it will be or'd for each post.
    $context['can_remove_post'] = allowedTo('delete_any') || allowedTo('delete_replies') && $context['user']['started'];
    // Can restore topic?  That's if the topic is in the recycle board and has a previous restore state.
    $context['can_restore_topic'] &= !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board && !empty($topicinfo['id_previous_board']);
    $context['can_restore_msg'] &= !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board && !empty($topicinfo['id_previous_topic']);
    if ($context['is_banned_from_topic']) {
        $context['can_add_tags'] = $context['can_delete_tags'] = $context['can_modify_any'] = $context['can_modify_replies'] = $context['can_modify_own'] = $context['can_delete_any'] = $context['can_delete_replies'] = $context['can_delete_own'] = $context['can_lock'] = $context['can_sticky'] = $context['calendar_post'] = $context['can_add_poll'] = $context['can_remove_poll'] = $context['can_reply'] = $context['can_reply_unapproved'] = $context['can_quote'] = $context['can_remove_post'] = false;
    }
    // Load up the "double post" sequencing magic.
    if (!empty($options['display_quick_reply'])) {
        checkSubmitOnce('register');
        $context['name'] = isset($_SESSION['guest_name']) ? $_SESSION['guest_name'] : '';
        $context['email'] = isset($_SESSION['guest_email']) ? $_SESSION['guest_email'] : '';
    }
    // todo: drafts -> plugin
    $context['can_save_draft'] = false;
    //$context['can_reply'] && !$context['user']['is_guest'] && in_array('dr', $context['admin_features']) && !empty($options['use_drafts']) && allowedTo('drafts_allow');
    $context['can_autosave_draft'] = false;
    //$context['can_save_draft'] && !empty($modSettings['enableAutoSaveDrafts']) && allowedTo('drafts_autosave_allow');
    enqueueThemeScript('topic', 'scripts/topic.js', true);
    if ($context['can_autosave_draft']) {
        enqueueThemeScript('drafts', 'scripts/drafts.js', true);
    }
    $context['can_moderate_member'] = $context['can_issue_warning'] || $context['can_moderate_board'];
    $context['topic_has_banned_members_msg'] = $context['topic_banned_members_count'] > 0 && $context['can_moderate_board'] ? sprintf($txt['topic_has_bans_msg'], URL::parse('?action=moderate;area=topicbans;sa=bytopic;t=' . $topic)) : '';
    if (EoS_Smarty::isActive()) {
        if (isset($context['poll'])) {
            $context['poll_buttons'] = array('vote' => array('test' => 'allow_return_vote', 'text' => 'poll_return_vote', 'image' => 'poll_options.gif', 'lang' => true, 'url' => $scripturl . '?topic=' . $context['current_topic'] . '.' . $context['start']), 'results' => array('test' => 'show_view_results_button', 'text' => 'poll_results', 'image' => 'poll_results.gif', 'lang' => true, 'url' => $scripturl . '?topic=' . $context['current_topic'] . '.' . $context['start'] . ';viewresults'), 'change_vote' => array('test' => 'allow_change_vote', 'text' => 'poll_change_vote', 'image' => 'poll_change_vote.gif', 'lang' => true, 'url' => $scripturl . '?action=vote;topic=' . $context['current_topic'] . '.' . $context['start'] . ';poll=' . $context['poll']['id'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'lock' => array('test' => 'allow_lock_poll', 'text' => !$context['poll']['is_locked'] ? 'poll_lock' : 'poll_unlock', 'image' => 'poll_lock.gif', 'lang' => true, 'url' => $scripturl . '?action=lockvoting;topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'edit' => array('test' => 'allow_edit_poll', 'text' => 'poll_edit', 'image' => 'poll_edit.gif', 'lang' => true, 'url' => $scripturl . '?action=editpoll;topic=' . $context['current_topic'] . '.' . $context['start']), 'remove_poll' => array('test' => 'can_remove_poll', 'text' => 'poll_remove', 'image' => 'admin_remove_poll.gif', 'lang' => true, 'custom' => 'onclick="return Eos_Confirm(\'\', \'' . $txt['poll_remove_warn'] . '\', $(this).attr(\'href\'));"', 'url' => $scripturl . '?action=removepoll;topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']));
        }
        $context['normal_buttons'] = array('reply' => array('test' => 'can_reply', 'text' => 'reply', 'custom' => 'onclick="return oQuickReply.quote(0);" ', 'image' => 'reply.gif', 'lang' => true, 'url' => $scripturl . '?action=post;topic=' . $context['current_topic'] . '.' . $context['start'] . ';last_msg=' . $context['topic_last_message'], 'active' => true), 'add_poll' => array('test' => 'can_add_poll', 'text' => 'add_poll', 'image' => 'add_poll.gif', 'lang' => true, 'url' => $scripturl . '?action=editpoll;add;topic=' . $context['current_topic'] . '.' . $context['start']), 'mark_unread' => array('test' => 'can_mark_unread', 'text' => 'mark_unread', 'image' => 'markunread.gif', 'lang' => true, 'url' => $scripturl . '?action=markasread;sa=topic;t=' . $context['mark_unread_time'] . ';topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']));
        HookAPI::callHook('integrate_display_buttons', array(&$context['normal_buttons']));
        $remove_url = $scripturl . '?action=removetopic2;topic=' . $context['current_topic'] . '.0;' . $context['session_var'] . '=' . $context['session_id'];
        $context['mod_buttons'] = array('move' => array('test' => 'can_move', 'text' => 'move_topic', 'image' => 'admin_move.gif', 'lang' => true, 'url' => $scripturl . '?action=movetopic;topic=' . $context['current_topic'] . '.0'), 'delete' => array('test' => 'can_delete', 'text' => 'remove_topic', 'image' => 'admin_rem.gif', 'lang' => true, 'custom' => 'onclick="return Eos_Confirm(\'\',\'' . $txt['are_sure_remove_topic'] . '\',\'' . $remove_url . '\');"', 'url' => $remove_url), 'lock' => array('test' => 'can_lock', 'text' => empty($context['is_locked']) ? 'set_lock' : 'set_unlock', 'image' => 'admin_lock.gif', 'lang' => true, 'url' => $scripturl . '?action=lock;topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'sticky' => array('test' => 'can_sticky', 'text' => empty($context['is_sticky']) ? 'set_sticky' : 'set_nonsticky', 'image' => 'admin_sticky.gif', 'lang' => true, 'url' => $scripturl . '?action=sticky;topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'merge' => array('test' => 'can_merge', 'text' => 'merge', 'image' => 'merge.gif', 'lang' => true, 'url' => $scripturl . '?action=mergetopics;board=' . $context['current_board'] . '.0;from=' . $context['current_topic']), 'calendar' => array('test' => 'calendar_post', 'text' => 'calendar_link', 'image' => 'linktocal.gif', 'lang' => true, 'url' => $scripturl . '?action=post;calendar;msg=' . $context['topic_first_message'] . ';topic=' . $context['current_topic'] . '.0'));
        // Restore topic. eh?  No monkey business.
        if ($context['can_restore_topic']) {
            $context['mod_buttons'][] = array('text' => 'restore_topic', 'image' => '', 'lang' => true, 'url' => $scripturl . '?action=restoretopic;topics=' . $context['current_topic'] . ';' . $context['session_var'] . '=' . $context['session_id']);
        }
        // Allow adding new mod buttons easily.
        HookAPI::callHook('integrate_mod_buttons', array(&$context['mod_buttons']));
        $context['message_ids'] = $messages;
        $context['perma_request'] = isset($_REQUEST['perma']) ? true : false;
        $context['mod_buttons_style'] = array('id' => 'moderationbuttons_strip', 'class' => 'buttonlist');
        $context['full_members_viewing_list'] = empty($context['view_members_list']) ? '0 ' . $txt['members'] : implode(', ', $context['view_members_list']) . (empty($context['view_num_hidden']) || $context['can_moderate_forum'] ? '' : ' (+ ' . $context['view_num_hidden'] . ' ' . $txt['hidden'] . ')');
    }
    fetchNewsItems($board, $topic);
    HookAPI::callHook('display_general', array());
    /*
     * $message is always available in templates as global variable
     * prepareDisplayContext() just repopulates it and is called from
     * the topic display template via $SUPPORT object callback.
     */
    EoS_Smarty::getSmartyInstance()->assignByRef('message', $output);
}
Esempio n. 11
0
function prepareSearchContext($reset = false)
{
    global $txt, $modSettings, $scripturl, $user_info, $sourcedir;
    global $memberContext, $context, $settings, $options, $messages_request;
    global $boards_can, $participants, $smcFunc;
    // Remember which message this is.  (ie. reply #83)
    static $counter = null;
    if ($counter == null || $reset) {
        $counter = $_REQUEST['start'] + 1;
    }
    // If the query returned false, bail.
    if ($messages_request == false) {
        return false;
    }
    // Start from the beginning...
    if ($reset) {
        return @$smcFunc['db_data_seek']($messages_request, 0);
    }
    // Attempt to get the next message.
    $message = $smcFunc['db_fetch_assoc']($messages_request);
    if (!$message) {
        return false;
    }
    // Can't have an empty subject can we?
    $message['subject'] = $message['subject'] != '' ? $message['subject'] : $txt['no_subject'];
    $message['first_subject'] = $message['first_subject'] != '' ? $message['first_subject'] : $txt['no_subject'];
    $message['last_subject'] = $message['last_subject'] != '' ? $message['last_subject'] : $txt['no_subject'];
    // If it couldn't load, or the user was a guest.... someday may be done with a guest table.
    if (!loadMemberContext($message['id_member'])) {
        // Notice this information isn't used anywhere else.... *cough guest table cough*.
        $memberContext[$message['id_member']]['name'] = $message['poster_name'];
        $memberContext[$message['id_member']]['id'] = 0;
        $memberContext[$message['id_member']]['group'] = $txt['guest_title'];
        $memberContext[$message['id_member']]['link'] = $message['poster_name'];
        $memberContext[$message['id_member']]['email'] = $message['poster_email'];
    }
    $memberContext[$message['id_member']]['ip'] = $message['poster_ip'];
    // Do the censor thang...
    censorText($message['body']);
    censorText($message['subject']);
    censorText($message['first_subject']);
    censorText($message['last_subject']);
    // Shorten this message if necessary.
    if ($context['compact']) {
        // Set the number of characters before and after the searched keyword.
        $charLimit = 50;
        $message['body'] = strtr($message['body'], array("\n" => ' ', '<br />' => "\n"));
        $message['body'] = parse_bbc($message['body'], $message['smileys_enabled'], $message['id_msg']);
        $message['body'] = strip_tags(strtr($message['body'], array('</div>' => '<br />', '</li>' => '<br />')), '<br>');
        if ($smcFunc['strlen']($message['body']) > $charLimit) {
            if (empty($context['key_words'])) {
                $message['body'] = $smcFunc['substr']($message['body'], 0, $charLimit) . '<strong>...</strong>';
            } else {
                $matchString = '';
                $force_partial_word = false;
                foreach ($context['key_words'] as $keyword) {
                    $keyword = preg_replace_callback('~(&amp;#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~', 'entity_fix__callback', strtr($keyword, array('\\\'' => '\'', '&' => '&amp;')));
                    if (preg_match('~[\'\\.,/@%&;:(){}\\[\\]_\\-+\\\\]$~', $keyword) != 0 || preg_match('~^[\'\\.,/@%&;:(){}\\[\\]_\\-+\\\\]~', $keyword) != 0) {
                        $force_partial_word = true;
                    }
                    $matchString .= strtr(preg_quote($keyword, '/'), array('\\*' => '.+?')) . '|';
                }
                $matchString = substr($matchString, 0, -1);
                $message['body'] = un_htmlspecialchars(strtr($message['body'], array('&nbsp;' => ' ', '<br />' => "\n", '&#91;' => '[', '&#93;' => ']', '&#58;' => ':', '&#64;' => '@')));
                if (empty($modSettings['search_method']) || $force_partial_word) {
                    preg_match_all('/([^\\s\\W]{' . $charLimit . '}[\\s\\W]|[\\s\\W].{0,' . $charLimit . '}?|^)(' . $matchString . ')(.{0,' . $charLimit . '}[\\s\\W]|[^\\s\\W]{' . $charLimit . '})/is' . ($context['utf8'] ? 'u' : ''), $message['body'], $matches);
                } else {
                    preg_match_all('/([^\\s\\W]{' . $charLimit . '}[\\s\\W]|[\\s\\W].{0,' . $charLimit . '}?[\\s\\W]|^)(' . $matchString . ')([\\s\\W].{0,' . $charLimit . '}[\\s\\W]|[\\s\\W][^\\s\\W]{' . $charLimit . '})/is' . ($context['utf8'] ? 'u' : ''), $message['body'], $matches);
                }
                $message['body'] = '';
                foreach ($matches[0] as $index => $match) {
                    $match = strtr($smcFunc['htmlspecialchars']($match, ENT_QUOTES), array("\n" => '&nbsp;'));
                    $message['body'] .= '<strong>......</strong>&nbsp;' . $match . '&nbsp;<strong>......</strong>';
                }
            }
            // Re-fix the international characters.
            $message['body'] = preg_replace_callback('~(&amp;#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~', 'entity_fix__callback', $message['body']);
        }
    } else {
        // Run BBC interpreter on the message.
        $message['body'] = parse_bbc($message['body'], $message['smileys_enabled'], $message['id_msg']);
    }
    // Make sure we don't end up with a practically empty message body.
    $message['body'] = preg_replace('~^(?:&nbsp;)+$~', '', $message['body']);
    // Sadly, we need to check the icon ain't broke.
    if (empty($modSettings['messageIconChecks_disable'])) {
        if (!isset($context['icon_sources'][$message['first_icon']])) {
            $context['icon_sources'][$message['first_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $message['first_icon'] . '.gif') ? 'images_url' : 'default_images_url';
        }
        if (!isset($context['icon_sources'][$message['last_icon']])) {
            $context['icon_sources'][$message['last_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $message['last_icon'] . '.gif') ? 'images_url' : 'default_images_url';
        }
        if (!isset($context['icon_sources'][$message['icon']])) {
            $context['icon_sources'][$message['icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $message['icon'] . '.gif') ? 'images_url' : 'default_images_url';
        }
    } else {
        if (!isset($context['icon_sources'][$message['first_icon']])) {
            $context['icon_sources'][$message['first_icon']] = 'images_url';
        }
        if (!isset($context['icon_sources'][$message['last_icon']])) {
            $context['icon_sources'][$message['last_icon']] = 'images_url';
        }
        if (!isset($context['icon_sources'][$message['icon']])) {
            $context['icon_sources'][$message['icon']] = 'images_url';
        }
    }
    // Do we have quote tag enabled?
    $quote_enabled = empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC']));
    $output = array_merge($context['topics'][$message['id_msg']], array('id' => $message['id_topic'], 'is_sticky' => !empty($modSettings['enableStickyTopics']) && !empty($message['is_sticky']), 'is_locked' => !empty($message['locked']), 'is_poll' => $modSettings['pollMode'] == '1' && $message['id_poll'] > 0, 'is_hot' => $message['num_replies'] >= $modSettings['hotTopicPosts'], 'is_very_hot' => $message['num_replies'] >= $modSettings['hotTopicVeryPosts'], 'posted_in' => !empty($participants[$message['id_topic']]), 'views' => $message['num_views'], 'replies' => $message['num_replies'], 'can_reply' => in_array($message['id_board'], $boards_can['post_reply_any']) || in_array(0, $boards_can['post_reply_any']), 'can_quote' => (in_array($message['id_board'], $boards_can['post_reply_any']) || in_array(0, $boards_can['post_reply_any'])) && $quote_enabled, 'can_mark_notify' => in_array($message['id_board'], $boards_can['mark_any_notify']) || in_array(0, $boards_can['mark_any_notify']) && !$context['user']['is_guest'], 'first_post' => array('id' => $message['first_msg'], 'time' => timeformat($message['first_poster_time']), 'timestamp' => forum_time(true, $message['first_poster_time']), 'subject' => $message['first_subject'], 'href' => $scripturl . '?topic=' . $message['id_topic'] . '.0', 'link' => '<a href="' . $scripturl . '?topic=' . $message['id_topic'] . '.0">' . $message['first_subject'] . '</a>', 'icon' => $message['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$message['first_icon']]] . '/post/' . $message['first_icon'] . '.gif', 'member' => array('id' => $message['first_member_id'], 'name' => $message['first_member_name'], 'href' => !empty($message['first_member_id']) ? $scripturl . '?action=profile;u=' . $message['first_member_id'] : '', 'link' => !empty($message['first_member_id']) ? '<a href="' . $scripturl . '?action=profile;u=' . $message['first_member_id'] . '" title="' . $txt['profile_of'] . ' ' . $message['first_member_name'] . '">' . $message['first_member_name'] . '</a>' : $message['first_member_name'])), 'last_post' => array('id' => $message['last_msg'], 'time' => timeformat($message['last_poster_time']), 'timestamp' => forum_time(true, $message['last_poster_time']), 'subject' => $message['last_subject'], 'href' => $scripturl . '?topic=' . $message['id_topic'] . ($message['num_replies'] == 0 ? '.0' : '.msg' . $message['last_msg']) . '#msg' . $message['last_msg'], 'link' => '<a href="' . $scripturl . '?topic=' . $message['id_topic'] . ($message['num_replies'] == 0 ? '.0' : '.msg' . $message['last_msg']) . '#msg' . $message['last_msg'] . '">' . $message['last_subject'] . '</a>', 'icon' => $message['last_icon'], 'icon_url' => $settings[$context['icon_sources'][$message['last_icon']]] . '/post/' . $message['last_icon'] . '.gif', 'member' => array('id' => $message['last_member_id'], 'name' => $message['last_member_name'], 'href' => !empty($message['last_member_id']) ? $scripturl . '?action=profile;u=' . $message['last_member_id'] : '', 'link' => !empty($message['last_member_id']) ? '<a href="' . $scripturl . '?action=profile;u=' . $message['last_member_id'] . '" title="' . $txt['profile_of'] . ' ' . $message['last_member_name'] . '">' . $message['last_member_name'] . '</a>' : $message['last_member_name'])), 'board' => array('id' => $message['id_board'], 'name' => $message['board_name'], 'href' => $scripturl . '?board=' . $message['id_board'] . '.0', 'link' => '<a href="' . $scripturl . '?board=' . $message['id_board'] . '.0">' . $message['board_name'] . '</a>'), 'category' => array('id' => $message['id_cat'], 'name' => $message['cat_name'], 'href' => $scripturl . '#c' . $message['id_cat'], 'link' => '<a href="' . $scripturl . '#c' . $message['id_cat'] . '">' . $message['cat_name'] . '</a>')));
    determineTopicClass($output);
    if ($output['posted_in']) {
        $output['class'] = 'my_' . $output['class'];
    }
    $body_highlighted = $message['body'];
    $subject_highlighted = $message['subject'];
    if (!empty($options['display_quick_mod'])) {
        $started = $output['first_post']['member']['id'] == $user_info['id'];
        $output['quick_mod'] = array('lock' => in_array(0, $boards_can['lock_any']) || in_array($output['board']['id'], $boards_can['lock_any']) || $started && (in_array(0, $boards_can['lock_own']) || in_array($output['board']['id'], $boards_can['lock_own'])), 'sticky' => (in_array(0, $boards_can['make_sticky']) || in_array($output['board']['id'], $boards_can['make_sticky'])) && !empty($modSettings['enableStickyTopics']), 'move' => in_array(0, $boards_can['move_any']) || in_array($output['board']['id'], $boards_can['move_any']) || $started && (in_array(0, $boards_can['move_own']) || in_array($output['board']['id'], $boards_can['move_own'])), 'remove' => in_array(0, $boards_can['remove_any']) || in_array($output['board']['id'], $boards_can['remove_any']) || $started && (in_array(0, $boards_can['remove_own']) || in_array($output['board']['id'], $boards_can['remove_own'])));
        $context['can_lock'] |= $output['quick_mod']['lock'];
        $context['can_sticky'] |= $output['quick_mod']['sticky'];
        $context['can_move'] |= $output['quick_mod']['move'];
        $context['can_remove'] |= $output['quick_mod']['remove'];
        $context['can_merge'] |= in_array($output['board']['id'], $boards_can['merge_any']);
        // If we've found a message we can move, and we don't already have it, load the destinations.
        if ($options['display_quick_mod'] == 1 && !isset($context['move_to_boards']) && $context['can_move']) {
            require_once $sourcedir . '/Subs-MessageIndex.php';
            $boardListOptions = array('use_permissions' => true, 'not_redirection' => true, 'selected_board' => empty($_SESSION['move_to_topic']) ? null : $_SESSION['move_to_topic']);
            $context['move_to_boards'] = getBoardList($boardListOptions);
        }
    }
    foreach ($context['key_words'] as $query) {
        // Fix the international characters in the keyword too.
        $query = strtr($smcFunc['htmlspecialchars']($query), array('\\\'' => '\''));
        $body_highlighted = preg_replace_callback('/((<[^>]*)|' . preg_quote(strtr($query, array('\'' => '&#039;')), '/') . ')/i' . ($context['utf8'] ? 'u' : ''), 'search_highlight__preg_callback', $body_highlighted);
        $subject_highlighted = preg_replace('/(' . preg_quote($query, '/') . ')/i' . ($context['utf8'] ? 'u' : ''), '<strong class="highlight">$1</strong>', $subject_highlighted);
    }
    $output['matches'][] = array('id' => $message['id_msg'], 'attachment' => loadAttachmentContext($message['id_msg']), 'alternate' => $counter % 2, 'member' => &$memberContext[$message['id_member']], 'icon' => $message['icon'], 'icon_url' => $settings[$context['icon_sources'][$message['icon']]] . '/post/' . $message['icon'] . '.gif', 'subject' => $message['subject'], 'subject_highlighted' => $subject_highlighted, 'time' => timeformat($message['poster_time']), 'timestamp' => forum_time(true, $message['poster_time']), 'counter' => $counter, 'modified' => array('time' => timeformat($message['modified_time']), 'timestamp' => forum_time(true, $message['modified_time']), 'name' => $message['modified_name']), 'body' => $message['body'], 'body_highlighted' => $body_highlighted, 'start' => 'msg' . $message['id_msg']);
    $counter++;
    return $output;
}
Esempio n. 12
0
function prepareTopicArray($topic_ids)
{
    global $scripturl, $txt, $db_prefix, $modSettings, $options, $context;
    global $user_info, $board_info, $settings, $smcFunc;
    // Setup the default topic icons...
    $stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'moved', 'recycled', 'wireless');
    $context['icon_sources'] = array();
    foreach ($stable_icons as $icon) {
        $context['icon_sources'][$icon] = 'images_url';
    }
    if (empty($topic_ids)) {
        return false;
    }
    $context['messages_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) && !WIRELESS ? $options['messages_per_page'] : $modSettings['defaultMaxMessages'];
    $result = $smcFunc['db_query']('substring', '
		SELECT
			t.id_topic, t.num_replies, t.locked, t.num_views, t.is_sticky, t.id_poll, t.id_previous_board,
			' . ($user_info['is_guest'] ? '0' : 'IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1') . ' AS new_from,
			t.id_last_msg, t.approved, t.unapproved_posts, ml.poster_time AS last_poster_time,
			ml.id_msg_modified, ml.subject AS last_subject, ml.icon AS last_icon,
			ml.poster_name AS last_member_name, ml.id_member AS last_id_member,
			IFNULL(meml.real_name, ml.poster_name) AS last_display_name, t.id_first_msg,
			mf.poster_time AS first_poster_time, mf.subject AS first_subject, mf.icon AS first_icon,
			mf.poster_name AS first_member_name, mf.id_member AS first_id_member,
			IFNULL(memf.real_name, mf.poster_name) AS first_display_name, SUBSTRING(ml.body, 1, 385) AS last_body,
			SUBSTRING(mf.body, 1, 385) AS first_body, ml.smileys_enabled AS last_smileys,
			mf.smileys_enabled AS first_smileys, b.id_board, b.name As board_name
		FROM {db_prefix}topics AS t
			INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
			INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
			INNER JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg)
			LEFT JOIN {db_prefix}members AS meml ON (meml.id_member = ml.id_member)
			LEFT JOIN {db_prefix}members AS memf ON (memf.id_member = mf.id_member)' . ($user_info['is_guest'] ? '' : '
			LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})
			LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})') . '
		WHERE t.id_topic IN ({array_int:topic_list})
			AND (t.approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR t.id_member_started = {int:current_member}') . ')
		ORDER BY ml.poster_time DESC', array('current_member' => $user_info['id'], 'topic_list' => $topic_ids, 'is_approved' => 1));
    // Stolen from SMF
    while ($row = $smcFunc['db_fetch_assoc']($result)) {
        if ($row['id_poll'] > 0 && $modSettings['pollMode'] == '0') {
            continue;
        }
        if (!empty($settings['message_index_preview'])) {
            // Limit them to 128 characters - do this FIRST because it's a lot of wasted censoring otherwise.
            $row['first_body'] = strip_tags(strtr(parse_bbc($row['first_body'], $row['first_smileys'], $row['id_first_msg']), array('<br />' => '&#10;')));
            if ($smcFunc['strlen']($row['first_body']) > 128) {
                $row['first_body'] = $smcFunc['substr']($row['first_body'], 0, 128) . '...';
            }
            $row['last_body'] = strip_tags(strtr(parse_bbc($row['last_body'], $row['last_smileys'], $row['id_last_msg']), array('<br />' => '&#10;')));
            if ($smcFunc['strlen']($row['last_body']) > 128) {
                $row['last_body'] = $smcFunc['substr']($row['last_body'], 0, 128) . '...';
            }
            // Censor the subject and message preview.
            censorText($row['first_subject']);
            censorText($row['first_body']);
            // Don't censor them twice!
            if ($row['id_first_msg'] == $row['id_last_msg']) {
                $row['last_subject'] = $row['first_subject'];
                $row['last_body'] = $row['first_body'];
            } else {
                censorText($row['last_subject']);
                censorText($row['last_body']);
            }
        } else {
            $row['first_body'] = '';
            $row['last_body'] = '';
            censorText($row['first_subject']);
            if ($row['id_first_msg'] == $row['id_last_msg']) {
                $row['last_subject'] = $row['first_subject'];
            } else {
                censorText($row['last_subject']);
            }
        }
        // Decide how many pages the topic should have.
        $topic_length = $row['num_replies'] + 1;
        if ($topic_length > $context['messages_per_page']) {
            $tmppages = array();
            $tmpa = 1;
            for ($tmpb = 0; $tmpb < $topic_length; $tmpb += $context['messages_per_page']) {
                $tmppages[] = '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.' . $tmpb . '">' . $tmpa . '</a>';
                $tmpa++;
            }
            // Show links to all the pages?
            if (count($tmppages) <= 5) {
                $pages = '&#171; ' . implode(' ', $tmppages);
            } else {
                $pages = '&#171; ' . $tmppages[0] . ' ' . $tmppages[1] . ' ... ' . $tmppages[count($tmppages) - 2] . ' ' . $tmppages[count($tmppages) - 1];
            }
            if (!empty($modSettings['enableAllMessages']) && $topic_length < $modSettings['enableAllMessages']) {
                $pages .= ' &nbsp;<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0;all">' . $txt['all'] . '</a>';
            }
            $pages .= ' &#187;';
        } else {
            $pages = '';
        }
        // We need to check the topic icons exist...
        if (empty($modSettings['messageIconChecks_disable'])) {
            if (!isset($context['icon_sources'][$row['first_icon']])) {
                $context['icon_sources'][$row['first_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['first_icon'] . '.gif') ? 'images_url' : 'default_images_url';
            }
            if (!isset($context['icon_sources'][$row['last_icon']])) {
                $context['icon_sources'][$row['last_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['last_icon'] . '.gif') ? 'images_url' : 'default_images_url';
            }
        } else {
            if (!isset($context['icon_sources'][$row['first_icon']])) {
                $context['icon_sources'][$row['first_icon']] = 'images_url';
            }
            if (!isset($context['icon_sources'][$row['last_icon']])) {
                $context['icon_sources'][$row['last_icon']] = 'images_url';
            }
        }
        $context['related_topics'][$row['id_topic']] = array('id' => $row['id_topic'], 'board' => array('id' => $row['id_board'], 'name' => $row['board_name'], 'link' => '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['board_name'] . '</a>', 'can_approve_posts' => in_array(0, $context['can_approve_posts_boards']) || in_array($row['id_board'], $context['can_approve_posts_boards'])), 'first_post' => array('id' => $row['id_first_msg'], 'member' => array('username' => $row['first_member_name'], 'name' => $row['first_display_name'], 'id' => $row['first_id_member'], 'href' => !empty($row['first_id_member']) ? $scripturl . '?action=profile;u=' . $row['first_id_member'] : '', 'link' => !empty($row['first_id_member']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['first_id_member'] . '" title="' . $txt['profile_of'] . ' ' . $row['first_display_name'] . '">' . $row['first_display_name'] . '</a>' : $row['first_display_name']), 'time' => timeformat($row['first_poster_time']), 'timestamp' => forum_time(true, $row['first_poster_time']), 'subject' => $row['first_subject'], 'preview' => $row['first_body'], 'icon' => $row['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['first_icon']]] . '/post/' . $row['first_icon'] . '.gif', 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.0', 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0">' . $row['first_subject'] . '</a>'), 'last_post' => array('id' => $row['id_last_msg'], 'member' => array('username' => $row['last_member_name'], 'name' => $row['last_display_name'], 'id' => $row['last_id_member'], 'href' => !empty($row['last_id_member']) ? $scripturl . '?action=profile;u=' . $row['last_id_member'] : '', 'link' => !empty($row['last_id_member']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['last_id_member'] . '">' . $row['last_display_name'] . '</a>' : $row['last_display_name']), 'time' => timeformat($row['last_poster_time']), 'timestamp' => forum_time(true, $row['last_poster_time']), 'subject' => $row['last_subject'], 'preview' => $row['last_body'], 'icon' => $row['last_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['last_icon']]] . '/post/' . $row['last_icon'] . '.gif', 'href' => $scripturl . '?topic=' . $row['id_topic'] . ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['id_last_msg']) . '#new', 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['id_last_msg']) . '#new" ' . ($row['num_replies'] == 0 ? '' : 'rel="nofollow"') . '>' . $row['last_subject'] . '</a>'), 'is_sticky' => !empty($modSettings['enableStickyTopics']) && !empty($row['is_sticky']), 'is_locked' => !empty($row['locked']), 'is_poll' => $modSettings['pollMode'] == '1' && $row['id_poll'] > 0, 'is_hot' => $row['num_replies'] >= $modSettings['hotTopicPosts'], 'is_very_hot' => $row['num_replies'] >= $modSettings['hotTopicVeryPosts'], 'is_posted_in' => false, 'icon' => $row['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['first_icon']]] . '/post/' . $row['first_icon'] . '.gif', 'subject' => $row['first_subject'], 'new' => $row['new_from'] <= $row['id_msg_modified'], 'new_from' => $row['new_from'], 'newtime' => $row['new_from'], 'new_href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['new_from'] . '#new', 'pages' => $pages, 'replies' => $row['num_replies'], 'views' => $row['num_views'], 'approved' => $row['approved'], 'unapproved_posts' => $row['unapproved_posts']);
        determineTopicClass($context['related_topics'][$row['id_topic']]);
    }
    $smcFunc['db_free_result']($result);
}
Esempio n. 13
0
 /**
  * Show the list of topics in this board, along with any sub-boards.
  * @uses MessageIndex template topic_listing sub template
  */
 public function action_messageindex()
 {
     global $txt, $scripturl, $board, $modSettings, $context;
     global $options, $settings, $board_info, $user_info;
     // Fairly often, we'll work with boards. Current board, sub-boards.
     require_once SUBSDIR . '/Boards.subs.php';
     // If this is a redirection board head off.
     if ($board_info['redirect']) {
         incrementBoard($board, 'num_posts');
         redirectexit($board_info['redirect']);
     }
     loadTemplate('MessageIndex');
     loadJavascriptFile('topic.js');
     $context['name'] = $board_info['name'];
     $context['sub_template'] = 'topic_listing';
     $context['description'] = $board_info['description'];
     $template_layers = Template_Layers::getInstance();
     // How many topics do we have in total?
     $board_info['total_topics'] = allowedTo('approve_posts') ? $board_info['num_topics'] + $board_info['unapproved_topics'] : $board_info['num_topics'] + $board_info['unapproved_user_topics'];
     // View all the topics, or just a few?
     $context['topics_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['topics_per_page']) ? $options['topics_per_page'] : $modSettings['defaultMaxTopics'];
     $context['messages_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) ? $options['messages_per_page'] : $modSettings['defaultMaxMessages'];
     $maxindex = isset($_REQUEST['all']) && !empty($modSettings['enableAllMessages']) ? $board_info['total_topics'] : $context['topics_per_page'];
     // Right, let's only index normal stuff!
     if (count($_GET) > 1) {
         $session_name = session_name();
         foreach ($_GET as $k => $v) {
             if (!in_array($k, array('board', 'start', $session_name))) {
                 $context['robot_no_index'] = true;
             }
         }
     }
     if (!empty($_REQUEST['start']) && (!is_numeric($_REQUEST['start']) || $_REQUEST['start'] % $context['messages_per_page'] != 0)) {
         $context['robot_no_index'] = true;
     }
     // If we can view unapproved messages and there are some build up a list.
     if (allowedTo('approve_posts') && ($board_info['unapproved_topics'] || $board_info['unapproved_posts'])) {
         $untopics = $board_info['unapproved_topics'] ? '<a href="' . $scripturl . '?action=moderate;area=postmod;sa=topics;brd=' . $board . '">' . $board_info['unapproved_topics'] . '</a>' : 0;
         $unposts = $board_info['unapproved_posts'] ? '<a href="' . $scripturl . '?action=moderate;area=postmod;sa=posts;brd=' . $board . '">' . ($board_info['unapproved_posts'] - $board_info['unapproved_topics']) . '</a>' : 0;
         $context['unapproved_posts_message'] = sprintf($txt['there_are_unapproved_topics'], $untopics, $unposts, $scripturl . '?action=moderate;area=postmod;sa=' . ($board_info['unapproved_topics'] ? 'topics' : 'posts') . ';brd=' . $board);
     }
     // We only know these.
     if (isset($_REQUEST['sort']) && !in_array($_REQUEST['sort'], array('subject', 'starter', 'last_poster', 'replies', 'views', 'likes', 'first_post', 'last_post'))) {
         $_REQUEST['sort'] = 'last_post';
     }
     // Make sure the starting place makes sense and construct the page index.
     if (isset($_REQUEST['sort'])) {
         $sort_string = ';sort=' . $_REQUEST['sort'] . (isset($_REQUEST['desc']) ? ';desc' : '');
     } else {
         $sort_string = '';
     }
     $context['page_index'] = constructPageIndex($scripturl . '?board=' . $board . '.%1$d' . $sort_string, $_REQUEST['start'], $board_info['total_topics'], $maxindex, true);
     $context['start'] =& $_REQUEST['start'];
     // Set a canonical URL for this page.
     $context['canonical_url'] = $scripturl . '?board=' . $board . '.' . $context['start'];
     $context['links'] += array('prev' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?board=' . $board . '.' . ($_REQUEST['start'] - $context['topics_per_page']) : '', 'next' => $_REQUEST['start'] + $context['topics_per_page'] < $board_info['total_topics'] ? $scripturl . '?board=' . $board . '.' . ($_REQUEST['start'] + $context['topics_per_page']) : '');
     $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['topics_per_page'] + 1, 'num_pages' => floor(($board_info['total_topics'] - 1) / $context['topics_per_page']) + 1);
     if (isset($_REQUEST['all']) && !empty($modSettings['enableAllMessages']) && $maxindex > $modSettings['enableAllMessages']) {
         $maxindex = $modSettings['enableAllMessages'];
         $_REQUEST['start'] = 0;
     }
     // Build a list of the board's moderators.
     $context['moderators'] =& $board_info['moderators'];
     $context['link_moderators'] = array();
     if (!empty($board_info['moderators'])) {
         foreach ($board_info['moderators'] as $mod) {
             $context['link_moderators'][] = '<a href="' . $scripturl . '?action=profile;u=' . $mod['id'] . '" title="' . $txt['board_moderator'] . '">' . $mod['name'] . '</a>';
         }
     }
     // Mark current and parent boards as seen.
     if (!$user_info['is_guest']) {
         // We can't know they read it if we allow prefetches.
         if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') {
             @ob_end_clean();
             header('HTTP/1.1 403 Prefetch Forbidden');
             die;
         }
         // Mark the board as read, and its parents.
         if (!empty($board_info['parent_boards'])) {
             $board_list = array_keys($board_info['parent_boards']);
             $board_list[] = $board;
         } else {
             $board_list = array($board);
         }
         // Mark boards as read. Boards alone, no need for topics.
         markBoardsRead($board_list, false, false);
         // Clear topicseen cache
         if (!empty($board_info['parent_boards'])) {
             // We've seen all these boards now!
             foreach ($board_info['parent_boards'] as $k => $dummy) {
                 if (isset($_SESSION['topicseen_cache'][$k])) {
                     unset($_SESSION['topicseen_cache'][$k]);
                 }
             }
         }
         if (isset($_SESSION['topicseen_cache'][$board])) {
             unset($_SESSION['topicseen_cache'][$board]);
         }
         // From now on, they've seen it. So we reset notifications.
         $context['is_marked_notify'] = resetSentBoardNotification($user_info['id'], $board);
     } else {
         $context['is_marked_notify'] = false;
     }
     // 'Print' the header and board info.
     $context['page_title'] = strip_tags($board_info['name']);
     // Set the variables up for the template.
     $context['can_mark_notify'] = allowedTo('mark_notify') && !$user_info['is_guest'];
     $context['can_post_new'] = allowedTo('post_new') || $modSettings['postmod_active'] && allowedTo('post_unapproved_topics');
     $context['can_post_poll'] = !empty($modSettings['pollMode']) && allowedTo('poll_post') && $context['can_post_new'];
     $context['can_moderate_forum'] = allowedTo('moderate_forum');
     $context['can_approve_posts'] = allowedTo('approve_posts');
     // Prepare sub-boards for display.
     require_once SUBSDIR . '/BoardsList.class.php';
     $boardIndexOptions = array('include_categories' => false, 'base_level' => $board_info['child_level'] + 1, 'parent_id' => $board_info['id'], 'set_latest_post' => false, 'countChildPosts' => !empty($modSettings['countChildPosts']));
     $boardlist = new Boards_List($boardIndexOptions);
     $context['boards'] = $boardlist->getBoards();
     // Nosey, nosey - who's viewing this board?
     if (!empty($settings['display_who_viewing'])) {
         require_once SUBSDIR . '/Who.subs.php';
         formatViewers($board, 'board');
     }
     // And now, what we're here for: topics!
     require_once SUBSDIR . '/MessageIndex.subs.php';
     // Known sort methods.
     $sort_methods = messageIndexSort();
     // They didn't pick one, default to by last post descending.
     if (!isset($_REQUEST['sort']) || !isset($sort_methods[$_REQUEST['sort']])) {
         $context['sort_by'] = 'last_post';
         $ascending = isset($_REQUEST['asc']);
     } else {
         $context['sort_by'] = $_REQUEST['sort'];
         $ascending = !isset($_REQUEST['desc']);
     }
     $sort_column = $sort_methods[$context['sort_by']];
     $context['sort_direction'] = $ascending ? 'up' : 'down';
     $context['sort_title'] = $ascending ? $txt['sort_desc'] : $txt['sort_asc'];
     // Trick
     $txt['starter'] = $txt['started_by'];
     foreach ($sort_methods as $key => $val) {
         $context['topics_headers'][$key] = array('url' => $scripturl . '?board=' . $context['current_board'] . '.' . $context['start'] . ';sort=' . $key . ($context['sort_by'] == $key && $context['sort_direction'] == 'up' ? ';desc' : ''), 'sort_dir_img' => $context['sort_by'] == $key ? '<img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" title="' . $context['sort_title'] . '" />' : '');
     }
     // Calculate the fastest way to get the topics.
     $start = (int) $_REQUEST['start'];
     if ($start > ($board_info['total_topics'] - 1) / 2) {
         $ascending = !$ascending;
         $fake_ascending = true;
         $maxindex = $board_info['total_topics'] < $start + $maxindex + 1 ? $board_info['total_topics'] - $start : $maxindex;
         $start = $board_info['total_topics'] < $start + $maxindex + 1 ? 0 : $board_info['total_topics'] - $start - $maxindex;
     } else {
         $fake_ascending = false;
     }
     // Setup the default topic icons...
     $context['icon_sources'] = MessageTopicIcons();
     $topic_ids = array();
     $context['topics'] = array();
     // Set up the query options
     $indexOptions = array('include_sticky' => !empty($modSettings['enableStickyTopics']), 'only_approved' => $modSettings['postmod_active'] && !allowedTo('approve_posts'), 'previews' => !empty($modSettings['message_index_preview']) ? empty($modSettings['preview_characters']) ? -1 : $modSettings['preview_characters'] : 0, 'include_avatars' => !empty($settings['avatars_on_indexes']), 'ascending' => $ascending, 'fake_ascending' => $fake_ascending);
     // Allow integration to modify / add to the $indexOptions
     call_integration_hook('integrate_messageindex_topics', array(&$sort_column, &$indexOptions));
     $topics_info = messageIndexTopics($board, $user_info['id'], $start, $maxindex, $context['sort_by'], $sort_column, $indexOptions);
     // Prepare for links to guests (for search engines)
     $context['pageindex_multiplier'] = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) ? $options['messages_per_page'] : $modSettings['defaultMaxMessages'];
     // Begin 'printing' the message index for current board.
     foreach ($topics_info as $row) {
         $topic_ids[] = $row['id_topic'];
         // Do they want message previews?
         if (!empty($modSettings['message_index_preview'])) {
             // Limit them to $modSettings['preview_characters'] characters
             $row['first_body'] = strip_tags(strtr(parse_bbc($row['first_body'], false, $row['id_first_msg']), array('<br />' => "\n", '&nbsp;' => ' ')));
             $row['first_body'] = Util::shorten_text($row['first_body'], !empty($modSettings['preview_characters']) ? $modSettings['preview_characters'] : 128, true);
             // No reply then they are the same, no need to process it again
             if ($row['num_replies'] == 0) {
                 $row['last_body'] == $row['first_body'];
             } else {
                 $row['last_body'] = strip_tags(strtr(parse_bbc($row['last_body'], false, $row['id_last_msg']), array('<br />' => "\n", '&nbsp;' => ' ')));
                 $row['last_body'] = Util::shorten_text($row['last_body'], !empty($modSettings['preview_characters']) ? $modSettings['preview_characters'] : 128, true);
             }
             // Censor the subject and message preview.
             censorText($row['first_subject']);
             censorText($row['first_body']);
             // Don't censor them twice!
             if ($row['id_first_msg'] == $row['id_last_msg']) {
                 $row['last_subject'] = $row['first_subject'];
                 $row['last_body'] = $row['first_body'];
             } else {
                 censorText($row['last_subject']);
                 censorText($row['last_body']);
             }
         } else {
             $row['first_body'] = '';
             $row['last_body'] = '';
             censorText($row['first_subject']);
             if ($row['id_first_msg'] == $row['id_last_msg']) {
                 $row['last_subject'] = $row['first_subject'];
             } else {
                 censorText($row['last_subject']);
             }
         }
         // Decide how many pages the topic should have.
         if ($row['num_replies'] + 1 > $context['messages_per_page']) {
             // We can't pass start by reference.
             $start = -1;
             $pages = constructPageIndex($scripturl . '?topic=' . $row['id_topic'] . '.%1$d', $start, $row['num_replies'] + 1, $context['messages_per_page'], true, array('prev_next' => false, 'all' => !empty($modSettings['enableAllMessages']) && $row['num_replies'] + 1 < $modSettings['enableAllMessages']));
         } else {
             $pages = '';
         }
         // We need to check the topic icons exist...
         if (!empty($modSettings['messageIconChecks_enable'])) {
             if (!isset($context['icon_sources'][$row['first_icon']])) {
                 $context['icon_sources'][$row['first_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['first_icon'] . '.png') ? 'images_url' : 'default_images_url';
             }
             if (!isset($context['icon_sources'][$row['last_icon']])) {
                 $context['icon_sources'][$row['last_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['last_icon'] . '.png') ? 'images_url' : 'default_images_url';
             }
         } else {
             if (!isset($context['icon_sources'][$row['first_icon']])) {
                 $context['icon_sources'][$row['first_icon']] = 'images_url';
             }
             if (!isset($context['icon_sources'][$row['last_icon']])) {
                 $context['icon_sources'][$row['last_icon']] = 'images_url';
             }
         }
         // 'Print' the topic info.
         $context['topics'][$row['id_topic']] = array('id' => $row['id_topic'], 'first_post' => array('id' => $row['id_first_msg'], 'member' => array('username' => $row['first_member_name'], 'name' => $row['first_display_name'], 'id' => $row['first_id_member'], 'href' => !empty($row['first_id_member']) ? $scripturl . '?action=profile;u=' . $row['first_id_member'] : '', 'link' => !empty($row['first_id_member']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['first_id_member'] . '" title="' . $txt['profile_of'] . ' ' . $row['first_display_name'] . '" class="preview">' . $row['first_display_name'] . '</a>' : $row['first_display_name']), 'time' => standardTime($row['first_poster_time']), 'html_time' => htmlTime($row['first_poster_time']), 'timestamp' => forum_time(true, $row['first_poster_time']), 'subject' => $row['first_subject'], 'preview' => trim($row['first_body']), 'icon' => $row['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['first_icon']]] . '/post/' . $row['first_icon'] . '.png', 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.0', 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0">' . $row['first_subject'] . '</a>'), 'last_post' => array('id' => $row['id_last_msg'], 'member' => array('username' => $row['last_member_name'], 'name' => $row['last_display_name'], 'id' => $row['last_id_member'], 'href' => !empty($row['last_id_member']) ? $scripturl . '?action=profile;u=' . $row['last_id_member'] : '', 'link' => !empty($row['last_id_member']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['last_id_member'] . '">' . $row['last_display_name'] . '</a>' : $row['last_display_name']), 'time' => standardTime($row['last_poster_time']), 'html_time' => htmlTime($row['last_poster_time']), 'timestamp' => forum_time(true, $row['last_poster_time']), 'subject' => $row['last_subject'], 'preview' => trim($row['last_body']), 'icon' => $row['last_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['last_icon']]] . '/post/' . $row['last_icon'] . '.png', 'href' => $scripturl . '?topic=' . $row['id_topic'] . ($user_info['is_guest'] ? '.' . (int) ($row['num_replies'] / $context['pageindex_multiplier']) * $context['pageindex_multiplier'] . '#msg' . $row['id_last_msg'] : ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['id_last_msg']) . '#new'), 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . ($user_info['is_guest'] ? '.' . (int) ($row['num_replies'] / $context['pageindex_multiplier']) * $context['pageindex_multiplier'] . '#msg' . $row['id_last_msg'] : ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['id_last_msg']) . '#new') . '" ' . ($row['num_replies'] == 0 ? '' : 'rel="nofollow"') . '>' . $row['last_subject'] . '</a>'), 'default_preview' => trim($row[!empty($modSettings['message_index_preview']) && $modSettings['message_index_preview'] == 2 ? 'last_body' : 'first_body']), 'is_sticky' => !empty($modSettings['enableStickyTopics']) && !empty($row['is_sticky']), 'is_locked' => !empty($row['locked']), 'is_poll' => !empty($modSettings['pollMode']) && $row['id_poll'] > 0, 'is_hot' => !empty($modSettings['useLikesNotViews']) ? $row['num_likes'] >= $modSettings['hotTopicPosts'] : $row['num_replies'] >= $modSettings['hotTopicPosts'], 'is_very_hot' => !empty($modSettings['useLikesNotViews']) ? $row['num_likes'] >= $modSettings['hotTopicVeryPosts'] : $row['num_replies'] >= $modSettings['hotTopicVeryPosts'], 'is_posted_in' => false, 'icon' => $row['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['first_icon']]] . '/post/' . $row['first_icon'] . '.png', 'subject' => $row['first_subject'], 'new' => $row['new_from'] <= $row['id_msg_modified'], 'new_from' => $row['new_from'], 'newtime' => $row['new_from'], 'new_href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['new_from'] . '#new', 'redir_href' => !empty($row['id_redirect_topic']) ? $scripturl . '?topic=' . $row['id_topic'] . '.0;noredir' : '', 'pages' => $pages, 'replies' => comma_format($row['num_replies']), 'views' => comma_format($row['num_views']), 'likes' => comma_format($row['num_likes']), 'approved' => $row['approved'], 'unapproved_posts' => $row['unapproved_posts']);
         if (!empty($settings['avatars_on_indexes'])) {
             $context['topics'][$row['id_topic']]['last_post']['member']['avatar'] = determineAvatar($row);
         }
         determineTopicClass($context['topics'][$row['id_topic']]);
     }
     // Allow addons to add to the $context['topics']
     call_integration_hook('integrate_messageindex_listing', array($topics_info));
     // Fix the sequence of topics if they were retrieved in the wrong order. (for speed reasons...)
     if ($fake_ascending) {
         $context['topics'] = array_reverse($context['topics'], true);
     }
     if (!empty($modSettings['enableParticipation']) && !$user_info['is_guest'] && !empty($topic_ids)) {
         $topics_participated_in = topicsParticipation($user_info['id'], $topic_ids);
         foreach ($topics_participated_in as $participated) {
             $context['topics'][$participated['id_topic']]['is_posted_in'] = true;
             $context['topics'][$participated['id_topic']]['class'] = 'my_' . $context['topics'][$participated['id_topic']]['class'];
         }
     }
     $context['jump_to'] = array('label' => addslashes(un_htmlspecialchars($txt['jump_to'])), 'board_name' => htmlspecialchars(strtr(strip_tags($board_info['name']), array('&amp;' => '&')), ENT_COMPAT, 'UTF-8'), 'child_level' => $board_info['child_level']);
     // Is Quick Moderation active/needed?
     if (!empty($options['display_quick_mod']) && !empty($context['topics'])) {
         $context['can_markread'] = $context['user']['is_logged'];
         $context['can_lock'] = allowedTo('lock_any');
         $context['can_sticky'] = allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']);
         $context['can_move'] = allowedTo('move_any');
         $context['can_remove'] = allowedTo('remove_any');
         $context['can_merge'] = allowedTo('merge_any');
         // Ignore approving own topics as it's unlikely to come up...
         $context['can_approve'] = $modSettings['postmod_active'] && allowedTo('approve_posts') && !empty($board_info['unapproved_topics']);
         // Can we restore topics?
         $context['can_restore'] = allowedTo('move_any') && !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board;
         // Set permissions for all the topics.
         foreach ($context['topics'] as $t => $topic) {
             $started = $topic['first_post']['member']['id'] == $user_info['id'];
             $context['topics'][$t]['quick_mod'] = array('lock' => allowedTo('lock_any') || $started && allowedTo('lock_own'), 'sticky' => allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']), 'move' => allowedTo('move_any') || $started && allowedTo('move_own'), 'modify' => allowedTo('modify_any') || $started && allowedTo('modify_own'), 'remove' => allowedTo('remove_any') || $started && allowedTo('remove_own'), 'approve' => $context['can_approve'] && $topic['unapproved_posts']);
             $context['can_lock'] |= $started && allowedTo('lock_own');
             $context['can_move'] |= $started && allowedTo('move_own');
             $context['can_remove'] |= $started && allowedTo('remove_own');
         }
         // Can we use quick moderation checkboxes?
         if ($options['display_quick_mod'] == 1) {
             $context['can_quick_mod'] = $context['user']['is_logged'] || $context['can_approve'] || $context['can_remove'] || $context['can_lock'] || $context['can_sticky'] || $context['can_move'] || $context['can_merge'] || $context['can_restore'];
         } else {
             $context['can_quick_mod'] = $context['can_remove'] || $context['can_lock'] || $context['can_sticky'] || $context['can_move'];
         }
     }
     if (!empty($context['can_quick_mod']) && $options['display_quick_mod'] == 1) {
         $context['qmod_actions'] = array('approve', 'remove', 'lock', 'sticky', 'move', 'merge', 'restore', 'markread');
         call_integration_hook('integrate_quick_mod_actions');
     }
     if (!empty($context['boards']) && $context['start'] == 0) {
         $template_layers->add('display_child_boards');
     }
     // If there are children, but no topics and no ability to post topics...
     $context['no_topic_listing'] = !empty($context['boards']) && empty($context['topics']) && !$context['can_post_new'];
     $template_layers->add('topic_listing');
     addJavascriptVar(array('notification_board_notice' => $context['is_marked_notify'] ? $txt['notification_disable_board'] : $txt['notification_enable_board']), true);
     // Build the message index button array.
     $context['normal_buttons'] = array('new_topic' => array('test' => 'can_post_new', 'text' => 'new_topic', 'image' => 'new_topic.png', 'lang' => true, 'url' => $scripturl . '?action=post;board=' . $context['current_board'] . '.0', 'active' => true), 'notify' => array('test' => 'can_mark_notify', 'text' => $context['is_marked_notify'] ? 'unnotify' : 'notify', 'image' => ($context['is_marked_notify'] ? 'un' : '') . 'notify.png', 'lang' => true, 'custom' => 'onclick="return notifyboardButton(this);"', 'url' => $scripturl . '?action=notifyboard;sa=' . ($context['is_marked_notify'] ? 'off' : 'on') . ';board=' . $context['current_board'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']));
     // They can only mark read if they are logged in and it's enabled!
     if (!$user_info['is_guest'] && $settings['show_mark_read']) {
         $context['normal_buttons']['markread'] = array('text' => 'mark_read_short', 'image' => 'markread.png', 'lang' => true, 'url' => $scripturl . '?action=markasread;sa=board;board=' . $context['current_board'] . '.0;' . $context['session_var'] . '=' . $context['session_id'], 'custom' => 'onclick="return markboardreadButton(this);"');
     }
     // Allow adding new buttons easily.
     call_integration_hook('integrate_messageindex_buttons');
 }
Esempio n. 14
0
    /**
     * Find unread topics and replies.
     * Accessed by action=unread and action=unreadreplies
     */
    public function action_unread()
    {
        global $board, $txt, $scripturl;
        global $user_info, $context, $settings, $modSettings, $options;
        $db = database();
        // Guests can't have unread things, we don't know anything about them.
        is_not_guest();
        // Prefetching + lots of MySQL work = bad mojo.
        if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') {
            @ob_end_clean();
            header('HTTP/1.1 403 Forbidden');
            die;
        }
        // We need... we need... I know!
        require_once SUBSDIR . '/Recent.subs.php';
        require_once SUBSDIR . '/Boards.subs.php';
        $context['showCheckboxes'] = !empty($options['display_quick_mod']) && $options['display_quick_mod'] == 1 && $settings['show_mark_read'];
        $context['showing_all_topics'] = isset($_GET['all']);
        $context['start'] = (int) $_REQUEST['start'];
        $context['topics_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['topics_per_page']) ? $options['topics_per_page'] : $modSettings['defaultMaxTopics'];
        if ($_REQUEST['action'] == 'unread') {
            $context['page_title'] = $context['showing_all_topics'] ? $txt['unread_topics_all'] : $txt['unread_topics_visit'];
        } else {
            $context['page_title'] = $txt['unread_replies'];
        }
        if ($context['showing_all_topics'] && !empty($modSettings['loadavg_allunread']) && $modSettings['current_load'] >= $modSettings['loadavg_allunread']) {
            fatal_lang_error('loadavg_allunread_disabled', false);
        } elseif ($_REQUEST['action'] != 'unread' && !empty($modSettings['loadavg_unreadreplies']) && $modSettings['current_load'] >= $modSettings['loadavg_unreadreplies']) {
            fatal_lang_error('loadavg_unreadreplies_disabled', false);
        } elseif (!$context['showing_all_topics'] && $_REQUEST['action'] == 'unread' && !empty($modSettings['loadavg_unread']) && $modSettings['current_load'] >= $modSettings['loadavg_unread']) {
            fatal_lang_error('loadavg_unread_disabled', false);
        }
        // Parameters for the main query.
        $query_parameters = array();
        // Are we specifying any specific board?
        if (isset($_REQUEST['children']) && (!empty($board) || !empty($_REQUEST['boards']))) {
            $boards = array();
            if (!empty($_REQUEST['boards'])) {
                $_REQUEST['boards'] = explode(',', $_REQUEST['boards']);
                foreach ($_REQUEST['boards'] as $b) {
                    $boards[] = (int) $b;
                }
            }
            if (!empty($board)) {
                $boards[] = (int) $board;
            }
            // The easiest thing is to just get all the boards they can see,
            // but since we've specified the top of tree we ignore some of them
            addChildBoards($boards);
            if (empty($boards)) {
                fatal_lang_error('error_no_boards_selected');
            }
            $query_this_board = 'id_board IN ({array_int:boards})';
            $query_parameters['boards'] = $boards;
            $context['querystring_board_limits'] = ';boards=' . implode(',', $boards) . ';start=%d';
        } elseif (!empty($board)) {
            $query_this_board = 'id_board = {int:board}';
            $query_parameters['board'] = $board;
            $context['querystring_board_limits'] = ';board=' . $board . '.%1$d';
        } elseif (!empty($_REQUEST['boards'])) {
            $selected_boards = array_map('intval', explode(',', $_REQUEST['boards']));
            $boards = accessibleBoards($selected_boards);
            if (empty($boards)) {
                fatal_lang_error('error_no_boards_selected');
            }
            $query_this_board = 'id_board IN ({array_int:boards})';
            $query_parameters['boards'] = $boards;
            $context['querystring_board_limits'] = ';boards=' . implode(',', $boards) . ';start=%1$d';
        } elseif (!empty($_REQUEST['c'])) {
            $categories = array_map('intval', explode(',', $_REQUEST['c']));
            $boards = array_keys(boardsPosts(array(), $categories, isset($_REQUEST['action']) && $_REQUEST['action'] != 'unreadreplies'));
            if (empty($boards)) {
                fatal_lang_error('error_no_boards_selected');
            }
            $query_this_board = 'id_board IN ({array_int:boards})';
            $query_parameters['boards'] = $boards;
            $context['querystring_board_limits'] = ';c=' . $_REQUEST['c'] . ';start=%1$d';
        } else {
            $see_board = isset($_REQUEST['action']) && $_REQUEST['action'] == 'unreadreplies' ? 'query_see_board' : 'query_wanna_see_board';
            // Don't bother to show deleted posts!
            $boards = wantedBoards($see_board);
            if (empty($boards)) {
                fatal_lang_error('error_no_boards_selected');
            }
            $query_this_board = 'id_board IN ({array_int:boards})';
            $query_parameters['boards'] = $boards;
            $context['querystring_board_limits'] = ';start=%1$d';
            $context['no_board_limits'] = true;
        }
        $sort_methods = array('subject' => 'ms.subject', 'starter' => 'IFNULL(mems.real_name, ms.poster_name)', 'replies' => 't.num_replies', 'views' => 't.num_views', 'first_post' => 't.id_topic', 'last_post' => 't.id_last_msg');
        // The default is the most logical: newest first.
        if (!isset($_REQUEST['sort']) || !isset($sort_methods[$_REQUEST['sort']])) {
            $context['sort_by'] = 'last_post';
            $ascending = isset($_REQUEST['asc']);
            $context['querystring_sort_limits'] = $ascending ? ';asc' : '';
        } else {
            $context['sort_by'] = $_REQUEST['sort'];
            $ascending = !isset($_REQUEST['desc']);
            $context['querystring_sort_limits'] = ';sort=' . $context['sort_by'] . ($ascending ? '' : ';desc');
        }
        $_REQUEST['sort'] = $sort_methods[$context['sort_by']];
        $context['sort_direction'] = $ascending ? 'up' : 'down';
        $context['sort_title'] = $ascending ? $txt['sort_desc'] : $txt['sort_asc'];
        // Trick
        $txt['starter'] = $txt['started_by'];
        foreach ($sort_methods as $key => $val) {
            $context['topics_headers'][$key] = array('url' => $scripturl . '?action=unread' . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start']) . ';sort=subject' . ($context['sort_by'] == 'subject' && $context['sort_direction'] == 'up' ? ';desc' : ''), 'sort_dir_img' => $context['sort_by'] == $key ? '<img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" title="' . $context['sort_title'] . '" />' : '');
        }
        if (!empty($_REQUEST['c']) && is_array($_REQUEST['c']) && count($_REQUEST['c']) == 1) {
            $name = categoryName((int) $_REQUEST['c'][0]);
            $context['linktree'][] = array('url' => $scripturl . '#c' . (int) $_REQUEST['c'][0], 'name' => $name);
        }
        $context['linktree'][] = array('url' => $scripturl . '?action=' . $_REQUEST['action'] . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits'], 'name' => $_REQUEST['action'] == 'unread' ? $txt['unread_topics_visit'] : $txt['unread_replies']);
        if ($context['showing_all_topics']) {
            $context['linktree'][] = array('url' => $scripturl . '?action=' . $_REQUEST['action'] . ';all' . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits'], 'name' => $txt['unread_topics_all']);
            $txt['unread_topics_visit_none'] = str_replace('{unread_all_url}', $scripturl . '?action=unread;all', $txt['unread_topics_visit_none']);
        } else {
            $txt['unread_topics_visit_none'] = str_replace('{unread_all_url}', $scripturl . '?action=unread;all' . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits'], $txt['unread_topics_visit_none']);
        }
        loadTemplate('Recent');
        $context['sub_template'] = $_REQUEST['action'] == 'unread' ? 'unread' : 'replies';
        // Setup the default topic icons... for checking they exist and the like ;)
        require_once SUBSDIR . '/MessageIndex.subs.php';
        $context['icon_sources'] = MessageTopicIcons();
        $is_topics = $_REQUEST['action'] == 'unread';
        // If empty, no preview at all
        if (empty($modSettings['message_index_preview'])) {
            $preview_bodies = '';
        } elseif (empty($modSettings['preview_characters'])) {
            $preview_bodies = 'ml.body AS last_body, ms.body AS first_body,';
        } else {
            $preview_bodies = 'SUBSTRING(ml.body, 1, ' . ($modSettings['preview_characters'] + 256) . ') AS last_body, SUBSTRING(ms.body, 1, ' . ($modSettings['preview_characters'] + 256) . ') AS first_body,';
        }
        // This part is the same for each query.
        $select_clause = '
					ms.subject AS first_subject, ms.poster_time AS first_poster_time, ms.id_topic, t.id_board, b.name AS bname,
					t.num_replies, t.num_views, t.num_likes, ms.id_member AS id_first_member, ml.id_member AS id_last_member,
					ml.poster_time AS last_poster_time, IFNULL(mems.real_name, ms.poster_name) AS first_poster_name,
					IFNULL(meml.real_name, ml.poster_name) AS last_poster_name, ml.subject AS last_subject,
					ml.icon AS last_icon, ms.icon AS first_icon, t.id_poll, t.is_sticky, t.locked, ml.modified_time AS last_modified_time,
					IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1 AS new_from,
					' . $preview_bodies . '
					ml.smileys_enabled AS last_smileys, ms.smileys_enabled AS first_smileys, t.id_first_msg, t.id_last_msg';
        if ($context['showing_all_topics']) {
            $earliest_msg = earliest_msg();
        }
        // @todo Add modified_time in for log_time check?
        if ($modSettings['totalMessages'] > 100000 && $context['showing_all_topics']) {
            $db->query('', '
				DROP TABLE IF EXISTS {db_prefix}log_topics_unread', array());
            // Let's copy things out of the log_topics table, to reduce searching.
            $have_temp_table = $db->query('', '
				CREATE TEMPORARY TABLE {db_prefix}log_topics_unread (
					PRIMARY KEY (id_topic)
				)
				SELECT lt.id_topic, lt.id_msg, lt.unwatched
				FROM {db_prefix}topics AS t
					INNER JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic)
				WHERE lt.id_member = {int:current_member}
					AND t.' . $query_this_board . (empty($earliest_msg) ? '' : '
					AND t.id_last_msg > {int:earliest_msg}') . ($modSettings['postmod_active'] ? '
					AND t.approved = {int:is_approved}' : '') . ($modSettings['enable_unwatch'] ? '
					AND lt.unwatched != 1' : ''), array_merge($query_parameters, array('current_member' => $user_info['id'], 'earliest_msg' => !empty($earliest_msg) ? $earliest_msg : 0, 'is_approved' => 1, 'db_error_skip' => true))) !== false;
        } else {
            $have_temp_table = false;
        }
        if ($context['showing_all_topics'] && $have_temp_table) {
            $request = $db->query('', '
				SELECT COUNT(*), MIN(t.id_last_msg)
				FROM {db_prefix}topics AS t
					LEFT JOIN {db_prefix}log_topics_unread AS lt ON (lt.id_topic = t.id_topic)
					LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})
				WHERE t.' . $query_this_board . (!empty($earliest_msg) ? '
					AND t.id_last_msg > {int:earliest_msg}' : '') . '
					AND IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0)) < t.id_last_msg' . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved}' : '') . ($modSettings['enable_unwatch'] ? ' AND IFNULL(lt.unwatched, 0) != 1' : ''), array_merge($query_parameters, array('current_member' => $user_info['id'], 'earliest_msg' => !empty($earliest_msg) ? $earliest_msg : 0, 'is_approved' => 1)));
            list($num_topics, $min_message) = $db->fetch_row($request);
            $db->free_result($request);
            // Make sure the starting place makes sense and construct the page index.
            $context['page_index'] = constructPageIndex($scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . $context['querystring_board_limits'] . $context['querystring_sort_limits'], $_REQUEST['start'], $num_topics, $context['topics_per_page'], true);
            $context['current_page'] = (int) $_REQUEST['start'] / $context['topics_per_page'];
            $context['links'] += array('prev' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] - $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'next' => $_REQUEST['start'] + $context['topics_per_page'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] + $context['topics_per_page']) . $context['querystring_sort_limits'] : '');
            $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['topics_per_page'] + 1, 'num_pages' => floor(($num_topics - 1) / $context['topics_per_page']) + 1);
            if ($num_topics == 0) {
                // Mark the boards as read if there are no unread topics!
                // @todo look at this... there are no more unread topics already.
                // If clearing of log_topics is still needed, perhaps do it separately.
                markBoardsRead(empty($boards) ? $board : $boards, false, true);
                $context['topics'] = array();
                if ($context['querystring_board_limits'] == ';start=%1$d') {
                    $context['querystring_board_limits'] = '';
                } else {
                    $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']);
                }
                return;
            } else {
                $min_message = (int) $min_message;
            }
            $request = $db->query('substring', '
				SELECT ' . $select_clause . '
				FROM {db_prefix}messages AS ms
					INNER JOIN {db_prefix}topics AS t ON (t.id_topic = ms.id_topic AND t.id_first_msg = ms.id_msg)
					INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
					LEFT JOIN {db_prefix}boards AS b ON (b.id_board = ms.id_board)
					LEFT JOIN {db_prefix}members AS mems ON (mems.id_member = ms.id_member)
					LEFT JOIN {db_prefix}members AS meml ON (meml.id_member = ml.id_member)
					LEFT JOIN {db_prefix}log_topics_unread AS lt ON (lt.id_topic = t.id_topic)
					LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})
				WHERE b.' . $query_this_board . '
					AND t.id_last_msg >= {int:min_message}
					AND IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0)) < t.id_last_msg' . ($modSettings['postmod_active'] ? ' AND ms.approved = {int:is_approved}' : '') . ($modSettings['enable_unwatch'] ? ' AND IFNULL(lt.unwatched, 0) != 1' : '') . '
				ORDER BY {raw:sort}
				LIMIT {int:offset}, {int:limit}', array_merge($query_parameters, array('current_member' => $user_info['id'], 'min_message' => $min_message, 'is_approved' => 1, 'sort' => $_REQUEST['sort'] . ($ascending ? '' : ' DESC'), 'offset' => $_REQUEST['start'], 'limit' => $context['topics_per_page'])));
        } elseif ($is_topics) {
            $request = $db->query('', '
				SELECT COUNT(*), MIN(t.id_last_msg)
				FROM {db_prefix}topics AS t' . (!empty($have_temp_table) ? '
					LEFT JOIN {db_prefix}log_topics_unread AS lt ON (lt.id_topic = t.id_topic)' : '
					LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})') . '
					LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})
				WHERE t.' . $query_this_board . ($context['showing_all_topics'] && !empty($earliest_msg) ? '
					AND t.id_last_msg > {int:earliest_msg}' : (!$context['showing_all_topics'] && empty($_SESSION['first_login']) ? '
					AND t.id_last_msg > {int:id_msg_last_visit}' : '')) . '
					AND IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0)) < t.id_last_msg' . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved}' : '') . ($modSettings['enable_unwatch'] ? ' AND IFNULL(lt.unwatched, 0) != 1' : ''), array_merge($query_parameters, array('current_member' => $user_info['id'], 'earliest_msg' => !empty($earliest_msg) ? $earliest_msg : 0, 'id_msg_last_visit' => $_SESSION['id_msg_last_visit'], 'is_approved' => 1)));
            list($num_topics, $min_message) = $db->fetch_row($request);
            $db->free_result($request);
            // Make sure the starting place makes sense and construct the page index.
            $context['page_index'] = constructPageIndex($scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . $context['querystring_board_limits'] . $context['querystring_sort_limits'], $_REQUEST['start'], $num_topics, $context['topics_per_page'], true);
            $context['current_page'] = (int) $_REQUEST['start'] / $context['topics_per_page'];
            $context['links'] += array('prev' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] - $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'next' => $_REQUEST['start'] + $context['topics_per_page'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] + $context['topics_per_page']) . $context['querystring_sort_limits'] : '');
            $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['topics_per_page'] + 1, 'num_pages' => floor(($num_topics - 1) / $context['topics_per_page']) + 1);
            if ($num_topics == 0) {
                // Is this an all topics query?
                if ($context['showing_all_topics']) {
                    // Since there are no unread topics, mark the boards as read!
                    // @todo look at this... there are no more unread topics already.
                    // If clearing of log_topics is still needed, perhaps do it separately.
                    markBoardsRead(empty($boards) ? $board : $boards, false, true);
                }
                $context['topics'] = array();
                if ($context['querystring_board_limits'] == ';start=%d') {
                    $context['querystring_board_limits'] = '';
                } else {
                    $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']);
                }
                return;
            } else {
                $min_message = (int) $min_message;
            }
            $request = $db->query('substring', '
				SELECT ' . $select_clause . '
				FROM {db_prefix}messages AS ms
					INNER JOIN {db_prefix}topics AS t ON (t.id_topic = ms.id_topic AND t.id_first_msg = ms.id_msg)
					INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
					LEFT JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
					LEFT JOIN {db_prefix}members AS mems ON (mems.id_member = ms.id_member)
					LEFT JOIN {db_prefix}members AS meml ON (meml.id_member = ml.id_member)' . (!empty($have_temp_table) ? '
					LEFT JOIN {db_prefix}log_topics_unread AS lt ON (lt.id_topic = t.id_topic)' : '
					LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})') . '
					LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})
				WHERE t.' . $query_this_board . '
					AND t.id_last_msg >= {int:min_message}
					AND IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0)) < ml.id_msg' . ($modSettings['postmod_active'] ? ' AND ms.approved = {int:is_approved}' : '') . ($modSettings['enable_unwatch'] ? ' AND IFNULL(lt.unwatched, 0) != 1' : '') . '
				ORDER BY {raw:order}
				LIMIT {int:offset}, {int:limit}', array_merge($query_parameters, array('current_member' => $user_info['id'], 'min_message' => $min_message, 'is_approved' => 1, 'order' => $_REQUEST['sort'] . ($ascending ? '' : ' DESC'), 'offset' => $_REQUEST['start'], 'limit' => $context['topics_per_page'])));
        } else {
            if ($modSettings['totalMessages'] > 100000) {
                $db->query('', '
					DROP TABLE IF EXISTS {db_prefix}topics_posted_in', array());
                $db->query('', '
					DROP TABLE IF EXISTS {db_prefix}log_topics_posted_in', array());
                $sortKey_joins = array('ms.subject' => '
						INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg)', 'IFNULL(mems.real_name, ms.poster_name)' => '
						INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg)
						LEFT JOIN {db_prefix}members AS mems ON (mems.id_member = ms.id_member)');
                // The main benefit of this temporary table is not that it's faster; it's that it avoids locks later.
                $have_temp_table = $db->query('', '
					CREATE TEMPORARY TABLE {db_prefix}topics_posted_in (
						id_topic mediumint(8) unsigned NOT NULL default {string:string_zero},
						id_board smallint(5) unsigned NOT NULL default {string:string_zero},
						id_last_msg int(10) unsigned NOT NULL default {string:string_zero},
						id_msg int(10) unsigned NOT NULL default {string:string_zero},
						PRIMARY KEY (id_topic)
					)
					SELECT t.id_topic, t.id_board, t.id_last_msg, IFNULL(lmr.id_msg, 0) AS id_msg' . (!in_array($_REQUEST['sort'], array('t.id_last_msg', 't.id_topic')) ? ', ' . $_REQUEST['sort'] . ' AS sort_key' : '') . '
					FROM {db_prefix}messages AS m
						INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)' . ($modSettings['enable_unwatch'] ? '
						LEFT JOIN {db_prefix}log_topics AS lt ON (t.id_topic = lt.id_topic AND lt.id_member = {int:current_member})' : '') . '
						LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})' . (isset($sortKey_joins[$_REQUEST['sort']]) ? $sortKey_joins[$_REQUEST['sort']] : '') . '
					WHERE m.id_member = {int:current_member}' . (!empty($board) ? '
						AND t.id_board = {int:current_board}' : '') . ($modSettings['postmod_active'] ? '
						AND t.approved = {int:is_approved}' : '') . ($modSettings['enable_unwatch'] ? '
						AND IFNULL(lt.unwatched, 0) != 1' : '') . '
					GROUP BY m.id_topic', array('current_board' => $board, 'current_member' => $user_info['id'], 'is_approved' => 1, 'string_zero' => '0', 'db_error_skip' => true)) !== false;
                // If that worked, create a sample of the log_topics table too.
                if ($have_temp_table) {
                    $have_temp_table = $db->query('', '
						CREATE TEMPORARY TABLE {db_prefix}log_topics_posted_in (
							PRIMARY KEY (id_topic)
						)
						SELECT lt.id_topic, lt.id_msg
						FROM {db_prefix}log_topics AS lt
							INNER JOIN {db_prefix}topics_posted_in AS pi ON (pi.id_topic = lt.id_topic)
						WHERE lt.id_member = {int:current_member}', array('current_member' => $user_info['id'], 'db_error_skip' => true)) !== false;
                }
            }
            if (!empty($have_temp_table)) {
                $request = $db->query('', '
					SELECT COUNT(*)
					FROM {db_prefix}topics_posted_in AS pi
						LEFT JOIN {db_prefix}log_topics_posted_in AS lt ON (lt.id_topic = pi.id_topic)
					WHERE pi.' . $query_this_board . '
						AND IFNULL(lt.id_msg, pi.id_msg) < pi.id_last_msg', array_merge($query_parameters, array()));
                list($num_topics) = $db->fetch_row($request);
                $db->free_result($request);
                $min_message = 0;
            } else {
                $request = $db->query('unread_fetch_topic_count', '
					SELECT COUNT(DISTINCT t.id_topic), MIN(t.id_last_msg)
					FROM {db_prefix}topics AS t
						INNER JOIN {db_prefix}messages AS m ON (m.id_topic = t.id_topic)
						LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})
						LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})
					WHERE t.' . $query_this_board . '
						AND m.id_member = {int:current_member}
						AND IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0)) < t.id_last_msg' . ($modSettings['postmod_active'] ? '
						AND t.approved = {int:is_approved}' : '') . ($modSettings['enable_unwatch'] ? '
						AND IFNULL(lt.unwatched, 0) != 1' : ''), array_merge($query_parameters, array('current_member' => $user_info['id'], 'is_approved' => 1)));
                list($num_topics, $min_message) = $db->fetch_row($request);
                $db->free_result($request);
            }
            // Make sure the starting place makes sense and construct the page index.
            $context['page_index'] = constructPageIndex($scripturl . '?action=' . $_REQUEST['action'] . $context['querystring_board_limits'] . $context['querystring_sort_limits'], $_REQUEST['start'], $num_topics, $context['topics_per_page'], true);
            $context['current_page'] = (int) $_REQUEST['start'] / $context['topics_per_page'];
            $context['links'] += array('first' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], 0) . $context['querystring_sort_limits'] : '', 'prev' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] - $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'next' => $_REQUEST['start'] + $context['topics_per_page'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], $_REQUEST['start'] + $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'last' => $_REQUEST['start'] + $context['topics_per_page'] < $num_topics ? $scripturl . '?action=' . $_REQUEST['action'] . ($context['showing_all_topics'] ? ';all' : '') . sprintf($context['querystring_board_limits'], floor(($num_topics - 1) / $context['topics_per_page']) * $context['topics_per_page']) . $context['querystring_sort_limits'] : '', 'up' => $scripturl);
            $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['topics_per_page'] + 1, 'num_pages' => floor(($num_topics - 1) / $context['topics_per_page']) + 1);
            if ($num_topics == 0) {
                $context['topics'] = array();
                if ($context['querystring_board_limits'] == ';start=%d') {
                    $context['querystring_board_limits'] = '';
                } else {
                    $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']);
                }
                return;
            }
            if (!empty($have_temp_table)) {
                $request = $db->query('', '
					SELECT t.id_topic
					FROM {db_prefix}topics_posted_in AS t
						LEFT JOIN {db_prefix}log_topics_posted_in AS lt ON (lt.id_topic = t.id_topic)
					WHERE t.' . $query_this_board . '
						AND IFNULL(lt.id_msg, t.id_msg) < t.id_last_msg
					ORDER BY {raw:order}
					LIMIT {int:offset}, {int:limit}', array_merge($query_parameters, array('order' => (in_array($_REQUEST['sort'], array('t.id_last_msg', 't.id_topic')) ? $_REQUEST['sort'] : 't.sort_key') . ($ascending ? '' : ' DESC'), 'offset' => $_REQUEST['start'], 'limit' => $context['topics_per_page'])));
            } else {
                $request = $db->query('unread_replies', '
					SELECT DISTINCT t.id_topic
					FROM {db_prefix}topics AS t
						INNER JOIN {db_prefix}messages AS m ON (m.id_topic = t.id_topic AND m.id_member = {int:current_member})' . (strpos($_REQUEST['sort'], 'ms.') === false ? '' : '
						INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg)') . (strpos($_REQUEST['sort'], 'mems.') === false ? '' : '
						LEFT JOIN {db_prefix}members AS mems ON (mems.id_member = ms.id_member)') . '
						LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})
						LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})
					WHERE t.' . $query_this_board . '
						AND t.id_last_msg >= {int:min_message}
						AND (IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0))) < t.id_last_msg' . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved}' : '') . ($modSettings['enable_unwatch'] ? ' AND IFNULL(lt.unwatched, 0) != 1' : '') . '
					ORDER BY {raw:order}
					LIMIT {int:offset}, {int:limit}', array_merge($query_parameters, array('current_member' => $user_info['id'], 'min_message' => (int) $min_message, 'is_approved' => 1, 'order' => $_REQUEST['sort'] . ($ascending ? '' : ' DESC'), 'offset' => $_REQUEST['start'], 'limit' => $context['topics_per_page'], 'sort' => $_REQUEST['sort'])));
            }
            $topics = array();
            while ($row = $db->fetch_assoc($request)) {
                $topics[] = $row['id_topic'];
            }
            $db->free_result($request);
            // Sanity... where have you gone?
            if (empty($topics)) {
                $context['topics'] = array();
                if ($context['querystring_board_limits'] == ';start=%d') {
                    $context['querystring_board_limits'] = '';
                } else {
                    $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']);
                }
                return;
            }
            $request = $db->query('substring', '
				SELECT ' . $select_clause . '
				FROM {db_prefix}topics AS t
					INNER JOIN {db_prefix}messages AS ms ON (ms.id_topic = t.id_topic AND ms.id_msg = t.id_first_msg)
					INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
					INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
					LEFT JOIN {db_prefix}members AS mems ON (mems.id_member = ms.id_member)
					LEFT JOIN {db_prefix}members AS meml ON (meml.id_member = ml.id_member)
					LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})
					LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})
				WHERE t.id_topic IN ({array_int:topic_list})
				ORDER BY ' . $_REQUEST['sort'] . ($ascending ? '' : ' DESC') . '
				LIMIT ' . count($topics), array('current_member' => $user_info['id'], 'topic_list' => $topics));
        }
        $context['topics'] = array();
        $topic_ids = array();
        while ($row = $db->fetch_assoc($request)) {
            $topic_ids[] = $row['id_topic'];
            if (!empty($modSettings['message_index_preview'])) {
                // Limit them to 128 characters - do this FIRST because it's a lot of wasted censoring otherwise.
                $row['first_body'] = strip_tags(strtr(parse_bbc($row['first_body'], false, $row['id_first_msg']), array('<br />' => "\n", '&nbsp;' => ' ')));
                $row['first_body'] = Util::shorten_text($row['first_body'], !empty($modSettings['preview_characters']) ? $modSettings['preview_characters'] : 128, true);
                // No reply then they are the same, no need to process it again
                if ($row['num_replies'] == 0) {
                    $row['last_body'] == $row['first_body'];
                } else {
                    $row['last_body'] = strip_tags(strtr(parse_bbc($row['last_body'], false, $row['id_last_msg']), array('<br />' => "\n", '&nbsp;' => ' ')));
                    $row['last_body'] = Util::shorten_text($row['last_body'], !empty($modSettings['preview_characters']) ? $modSettings['preview_characters'] : 128, true);
                }
                // Censor the subject and message preview.
                censorText($row['first_subject']);
                censorText($row['first_body']);
                // Don't censor them twice!
                if ($row['id_first_msg'] == $row['id_last_msg']) {
                    $row['last_subject'] = $row['first_subject'];
                    $row['last_body'] = $row['first_body'];
                } else {
                    censorText($row['last_subject']);
                    censorText($row['last_body']);
                }
            } else {
                $row['first_body'] = '';
                $row['last_body'] = '';
                censorText($row['first_subject']);
                if ($row['id_first_msg'] == $row['id_last_msg']) {
                    $row['last_subject'] = $row['first_subject'];
                } else {
                    censorText($row['last_subject']);
                }
            }
            // Decide how many pages the topic should have.
            $topic_length = $row['num_replies'] + 1;
            $messages_per_page = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) ? $options['messages_per_page'] : $modSettings['defaultMaxMessages'];
            if ($topic_length > $messages_per_page) {
                $start = -1;
                $pages = constructPageIndex($scripturl . '?topic=' . $row['id_topic'] . '.%1$d;topicseen', $start, $topic_length, $messages_per_page, true, array('prev_next' => false, 'all' => !empty($modSettings['enableAllMessages']) && $topic_length < $modSettings['enableAllMessages']));
            } else {
                $pages = '';
            }
            // We need to check the topic icons exist... you can never be too sure!
            if (!empty($modSettings['messageIconChecks_enable'])) {
                // First icon first... as you'd expect.
                if (!isset($context['icon_sources'][$row['first_icon']])) {
                    $context['icon_sources'][$row['first_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['first_icon'] . '.png') ? 'images_url' : 'default_images_url';
                }
                // Last icon... last... duh.
                if (!isset($context['icon_sources'][$row['last_icon']])) {
                    $context['icon_sources'][$row['last_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['last_icon'] . '.png') ? 'images_url' : 'default_images_url';
                }
            }
            // And build the array.
            $context['topics'][$row['id_topic']] = array('id' => $row['id_topic'], 'first_post' => array('id' => $row['id_first_msg'], 'member' => array('name' => $row['first_poster_name'], 'id' => $row['id_first_member'], 'href' => $scripturl . '?action=profile;u=' . $row['id_first_member'], 'link' => !empty($row['id_first_member']) ? '<a class="preview" href="' . $scripturl . '?action=profile;u=' . $row['id_first_member'] . '" title="' . $txt['profile_of'] . ' ' . $row['first_poster_name'] . '">' . $row['first_poster_name'] . '</a>' : $row['first_poster_name']), 'time' => standardTime($row['first_poster_time']), 'html_time' => htmlTime($row['first_poster_time']), 'timestamp' => forum_time(true, $row['first_poster_time']), 'subject' => $row['first_subject'], 'preview' => $row['first_body'], 'icon' => $row['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['first_icon']]] . '/post/' . $row['first_icon'] . '.png', 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.0;topicseen', 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0;topicseen">' . $row['first_subject'] . '</a>'), 'last_post' => array('id' => $row['id_last_msg'], 'member' => array('name' => $row['last_poster_name'], 'id' => $row['id_last_member'], 'href' => $scripturl . '?action=profile;u=' . $row['id_last_member'], 'link' => !empty($row['id_last_member']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_last_member'] . '">' . $row['last_poster_name'] . '</a>' : $row['last_poster_name']), 'time' => standardTime($row['last_poster_time']), 'html_time' => htmlTime($row['last_poster_time']), 'timestamp' => forum_time(true, $row['last_poster_time']), 'subject' => $row['last_subject'], 'preview' => $row['last_body'], 'icon' => $row['last_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['last_icon']]] . '/post/' . $row['last_icon'] . '.png', 'href' => $scripturl . '?topic=' . $row['id_topic'] . ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['id_last_msg']) . ';topicseen#msg' . $row['id_last_msg'], 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['id_last_msg']) . ';topicseen#msg' . $row['id_last_msg'] . '" rel="nofollow">' . $row['last_subject'] . '</a>'), 'default_preview' => trim($row[!empty($modSettings['message_index_preview']) && $modSettings['message_index_preview'] == 2 ? 'last_body' : 'first_body']), 'new_from' => $row['new_from'], 'new_href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['new_from'] . ';topicseen#new', 'href' => $scripturl . '?topic=' . $row['id_topic'] . ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['new_from']) . ';topicseen' . ($row['num_replies'] == 0 ? '' : 'new'), 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['new_from']) . ';topicseen#msg' . $row['new_from'] . '" rel="nofollow">' . $row['first_subject'] . '</a>', 'is_sticky' => !empty($modSettings['enableStickyTopics']) && !empty($row['is_sticky']), 'is_locked' => !empty($row['locked']), 'is_poll' => !empty($modSettings['pollMode']) && $row['id_poll'] > 0, 'is_hot' => !empty($modSettings['useLikesNotViews']) ? $row['num_likes'] >= $modSettings['hotTopicPosts'] : $row['num_replies'] >= $modSettings['hotTopicPosts'], 'is_very_hot' => !empty($modSettings['useLikesNotViews']) ? $row['num_likes'] >= $modSettings['hotTopicVeryPosts'] : $row['num_replies'] >= $modSettings['hotTopicVeryPosts'], 'is_posted_in' => false, 'icon' => $row['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['first_icon']]] . '/post/' . $row['first_icon'] . '.png', 'subject' => $row['first_subject'], 'pages' => $pages, 'replies' => comma_format($row['num_replies']), 'views' => comma_format($row['num_views']), 'likes' => comma_format($row['num_likes']), 'board' => array('id' => $row['id_board'], 'name' => $row['bname'], 'href' => $scripturl . '?board=' . $row['id_board'] . '.0', 'link' => '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['bname'] . '</a>'));
            $context['topics'][$row['id_topic']]['first_post']['started_by'] = sprintf($txt['topic_started_by_in'], '<strong>' . $context['topics'][$row['id_topic']]['first_post']['member']['link'] . '</strong>', '<em>' . $context['topics'][$row['id_topic']]['board']['link'] . '</em>');
            determineTopicClass($context['topics'][$row['id_topic']]);
        }
        $db->free_result($request);
        if ($is_topics && !empty($modSettings['enableParticipation']) && !empty($topic_ids)) {
            require_once SUBSDIR . '/MessageIndex.subs.php';
            $topics_participated_in = topicsParticipation($user_info['id'], $topic_ids);
            foreach ($topics_participated_in as $topic) {
                if (empty($context['topics'][$topic['id_topic']]['is_posted_in'])) {
                    $context['topics'][$topic['id_topic']]['is_posted_in'] = true;
                    $context['topics'][$topic['id_topic']]['class'] = 'my_' . $context['topics'][$topic['id_topic']]['class'];
                }
            }
        }
        $context['querystring_board_limits'] = sprintf($context['querystring_board_limits'], $_REQUEST['start']);
        $context['topics_to_mark'] = implode('-', $topic_ids);
        if ($settings['show_mark_read']) {
            // Build the recent button array.
            if ($is_topics) {
                $context['recent_buttons'] = array('markread' => array('text' => !empty($context['no_board_limits']) ? 'mark_as_read' : 'mark_read_short', 'image' => 'markread.png', 'lang' => true, 'custom' => 'onclick="return markunreadButton(this);"', 'url' => $scripturl . '?action=markasread;sa=' . (!empty($context['no_board_limits']) ? 'all' : 'board' . $context['querystring_board_limits']) . ';' . $context['session_var'] . '=' . $context['session_id']));
                if ($context['showCheckboxes']) {
                    $context['recent_buttons']['markselectread'] = array('text' => 'quick_mod_markread', 'image' => 'markselectedread.png', 'lang' => true, 'url' => 'javascript:document.quickModForm.submit();');
                }
                if (!empty($context['topics']) && !$context['showing_all_topics']) {
                    $context['recent_buttons']['readall'] = array('text' => 'unread_topics_all', 'image' => 'markreadall.png', 'lang' => true, 'url' => $scripturl . '?action=unread;all' . $context['querystring_board_limits'], 'active' => true);
                }
            } elseif (!$is_topics && isset($context['topics_to_mark'])) {
                $context['recent_buttons'] = array('markread' => array('text' => 'mark_as_read', 'image' => 'markread.png', 'lang' => true, 'url' => $scripturl . '?action=markasread;sa=unreadreplies;topics=' . $context['topics_to_mark'] . ';' . $context['session_var'] . '=' . $context['session_id']));
                if ($context['showCheckboxes']) {
                    $context['recent_buttons']['markselectread'] = array('text' => 'quick_mod_markread', 'image' => 'markselectedread.png', 'lang' => true, 'url' => 'javascript:document.quickModForm.submit();');
                }
            }
            // Allow mods to add additional buttons here
            call_integration_hook('integrate_recent_buttons');
        }
        // Allow helpdesks and bug trackers and what not to add their own unread data (just add a template_layer to show custom stuff in the template!)
        call_integration_hook('integrate_unread_list');
    }
Esempio n. 15
0
function showPosts($memID)
{
    global $txt, $user_info, $scripturl, $modSettings;
    global $context, $user_profile, $sourcedir, $board, $memberContext, $options;
    EoS_Smarty::loadTemplate('profile/profile_base');
    $context['need_synhlt'] = true;
    // Some initial context.
    $context['start'] = (int) $_REQUEST['start'];
    $context['current_member'] = $memID;
    // Create the tabs for the template.
    $context[$context['profile_menu_name']]['tab_data'] = array('title' => $txt['showPosts'], 'description' => $txt['showPosts_help'], 'tabs' => array('messages' => array(), 'topics' => array(), 'attach' => array()));
    // Set the page title
    $context['page_title'] = $txt['showPosts'] . ' - ' . $user_profile[$memID]['real_name'];
    $context['pageindex_multiplier'] = commonAPI::getMessagesPerPage();
    $context['can_approve_posts'] = false;
    // Is the load average too high to allow searching just now?
    if (!empty($context['load_average']) && !empty($modSettings['loadavg_show_posts']) && $context['load_average'] >= $modSettings['loadavg_show_posts']) {
        fatal_lang_error('loadavg_show_posts_disabled', false);
    }
    if (isset($_GET['sa']) && !empty($modSettings['karmaMode']) && ($_GET['sa'] == 'likes' || $_GET['sa'] == 'likesout')) {
        require_once $sourcedir . '/Ratings.php';
        return LikesByUser($memID);
    }
    EoS_Smarty::getConfigInstance()->registerHookTemplate('profile_content_area', 'profile/show_content');
    $boards_hidden_1 = boardsAllowedTo('see_hidden1');
    $boards_hidden_2 = boardsAllowedTo('see_hidden2');
    $boards_hidden_3 = boardsAllowedTo('see_hidden3');
    // If we're specifically dealing with attachments use that function!
    if (isset($_GET['sa']) && $_GET['sa'] == 'attach') {
        return showAttachments($memID);
    }
    // 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.
        $request = smf_db_query('
			SELECT subject, id_member, id_topic, id_board
			FROM {db_prefix}messages
			WHERE id_msg = {int:id_msg}', array('id_msg' => (int) $_GET['delete']));
        $info = mysql_fetch_row($request);
        mysql_free_result($request);
        // 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.
        require_once $sourcedir . '/RemoveTopic.php';
        removeMessage((int) $_GET['delete']);
        // Add it to the mod log.
        if (allowedTo('delete_any') && (!allowedTo('delete_own') || $info[1] != $user_info['id'])) {
            logAction('delete', array('topic' => $info[2], 'subject' => $info[0], 'member' => $info[1], 'board' => $info[3]));
        }
        // 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']) {
        $request = smf_db_query('
			SELECT COUNT(*)
			FROM {db_prefix}topics AS t' . ($user_info['query_see_board'] == '1=1' ? '' : '
				INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board AND {query_see_board})') . '
			WHERE t.id_member_started = {int:current_member}' . (!empty($board) ? '
				AND t.id_board = {int:board}' : '') . (!$modSettings['postmod_active'] || $context['user']['is_owner'] ? '' : '
				AND t.approved = {int:is_approved}'), array('current_member' => $memID, 'is_approved' => 1, 'board' => $board));
    } else {
        $request = smf_db_query('
			SELECT COUNT(*)
			FROM {db_prefix}messages AS m' . ($user_info['query_see_board'] == '1=1' ? '' : '
				INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board AND {query_see_board})') . '
			WHERE m.id_member = {int:current_member}' . (!empty($board) ? '
				AND m.id_board = {int:board}' : '') . (!$modSettings['postmod_active'] || $context['user']['is_owner'] ? '' : '
				AND m.approved = {int:is_approved}'), array('current_member' => $memID, 'is_approved' => 1, 'board' => $board));
    }
    list($msgCount) = mysql_fetch_row($request);
    mysql_free_result($request);
    $request = smf_db_query('
		SELECT MIN(id_msg), MAX(id_msg)
		FROM {db_prefix}messages AS m
		WHERE m.id_member = {int:current_member}' . (!empty($board) ? '
			AND m.id_board = {int:board}' : '') . (!$modSettings['postmod_active'] || $context['user']['is_owner'] ? '' : '
			AND m.approved = {int:is_approved}'), array('current_member' => $memID, 'is_approved' => 1, 'board' => $board));
    list($min_msg_member, $max_msg_member) = mysql_fetch_row($request);
    mysql_free_result($request);
    $reverse = false;
    $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' : '') . (!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 && !$context['is_topics']) {
        $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.
    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.  The left join on categories somehow makes this faster, weird as it looks.
    $context['results_counter'] = 0;
    $topicids = array();
    if ($context['is_topics']) {
        $context['postbit_callback'] = 'template_topicbit';
        $prereq = smf_db_query('
			SELECT t.id_topic FROM {db_prefix}topics AS t
			LEFT JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
			WHERE t.id_member_started = {int:current_member}' . (!empty($board) ? '
				AND t.id_board = {int:board}' : '') . '
				AND {query_see_board}' . (!$modSettings['postmod_active'] || $context['user']['is_owner'] ? '' : '
				AND t.approved = {int:is_approved}') . '
			ORDER BY t.id_topic DESC
			LIMIT ' . $start . ', ' . $modSettings['defaultMaxMessages'], array('current_member' => $memID, 'is_approved' => 1, 'board' => $board));
        while ($row = mysql_fetch_row($prereq)) {
            $topicids[] = $row[0];
        }
        mysql_free_result($prereq);
        if (count($topicids)) {
            $request = smf_db_query('
				SELECT
					b.id_board, b.name AS board_name, t.id_member_started, t.id_first_msg, t.id_last_msg, t.id_prefix, t.is_sticky, t.locked, t.num_views, t.num_replies, t.id_poll,
					t.approved, t.unapproved_posts, m.id_member, m.subject AS first_subject, m.poster_time, m.id_topic, m.id_msg, m.icon,
					m2.poster_name AS last_member_name, m2.id_member AS last_id_member, m2.poster_time AS last_post_time,
					IFNULL(meml.real_name, m2.poster_name) AS last_display_name, m2.subject AS last_subject, m2.icon AS last_icon,
					p.name AS prefix_name
				FROM {db_prefix}topics AS t
					LEFT JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)
					LEFT JOIN {db_prefix}members AS meml ON (meml.id_member = t.id_member_updated)
					LEFT JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
					LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat)
					LEFT JOIN {db_prefix}messages AS m2 ON (m2.id_msg = t.id_last_msg)
					LEFT JOIN {db_prefix}prefixes AS p ON (p.id_prefix = t.id_prefix)
				WHERE t.id_topic IN({array_int:topicids})
				ORDER BY t.id_topic DESC', array('topicids' => $topicids));
        }
    } else {
        $context['postbit_callback'] = 'template_postbit_compact';
        $request = smf_db_query('
			SELECT
				b.id_board, b.name AS bname, c.id_cat, c.name AS cname, m.id_topic, m.id_msg,
				t.id_member_started, t.id_first_msg, t.id_last_msg, m.body, m.smileys_enabled, m.id_member, m.icon,
				m.subject, m.poster_time, m.modified_time, m.approved, mc.body AS cached_body, ' . (!empty($modSettings['karmaMode']) ? 'c1.likes_count, c1.like_status, c1.updated AS like_updated, l.rtype AS liked, ' : '0 AS likes_count, 0 AS like_status, 0 AS like_updated, 0 AS liked, ') . '
				m2.id_member AS id_first_member, m2.subject AS first_subject, m2.poster_time AS time_started,
				IFNULL(mem2.real_name, m2.poster_name) AS first_poster_name
			FROM {db_prefix}messages AS m
				INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)
				INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
				INNER JOIN {db_prefix}messages AS m2 ON (m2.id_msg = t.id_first_msg)
				LEFT JOIN {db_prefix}members AS mem2 ON (mem2.id_member = m2.id_member)
				LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat) ' . (!empty($modSettings['karmaMode']) ? '
					LEFT JOIN {db_prefix}likes AS l ON (l.id_msg = m.id_msg AND l.ctype = 1 AND l.id_user = {int:id_user})
					LEFT JOIN {db_prefix}like_cache AS c1 ON (c1.id_msg = m.id_msg AND c1.ctype = 1)' : '') . '
				LEFT JOIN {db_prefix}messages_cache AS mc on mc.id_msg = m.id_msg AND mc.style = {int:style} AND mc.lang = {int:lang}
			WHERE m.id_member = {int:current_member}' . (!empty($board) ? '
				AND b.id_board = {int:board}' : '') . (empty($range_limit) ? '' : '
				AND ' . $range_limit) . '
				AND {query_see_board}' . (!$modSettings['postmod_active'] || $context['user']['is_owner'] ? '' : '
				AND t.approved = {int:is_approved} AND m.approved = {int:is_approved}') . '
			ORDER BY m.id_msg ' . ($reverse ? 'ASC' : 'DESC') . '
			LIMIT ' . $start . ', ' . $maxIndex, array('current_member' => $memID, 'is_approved' => 1, 'board' => $board, 'style' => $user_info['smiley_set_id'], 'lang' => $user_info['language_id'], 'id_user' => $user_info['id']));
    }
    // 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());
    if (!empty($modSettings['karmaMode'])) {
        require_once $sourcedir . '/lib/Subs-Ratings.php';
        $boards_like_see = boardsAllowedTo('like_see');
        $boards_like_give = boardsAllowedTo('like_give');
    } else {
        $boards_like_see = array();
        $boards_like_give = array();
        $context['can_see_like'] = $context['can_give_like'] = false;
    }
    $time_now = time();
    if ($context['is_topics']) {
        $context['topics_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['topics_per_page']) ? $options['topics_per_page'] : $modSettings['defaultMaxTopics'];
        $context['messages_per_page'] = commonAPI::getMessagesPerPage();
        if (count($topicids)) {
            loadMemberContext($memID, true);
            while ($row = mysql_fetch_assoc($request)) {
                $context['results_counter']++;
                if ($row['num_replies'] + 1 > $context['messages_per_page']) {
                    $pages = '&nbsp;&nbsp;';
                    // We can't pass start by reference.
                    $start = -1;
                    $pages .= constructPageIndex(URL::topic($row['id_topic'], $row['first_subject'], '%1$d'), $start, $row['num_replies'] + 1, $context['messages_per_page'], true);
                    // If we can use all, show all.
                    if (!empty($modSettings['enableAllMessages']) && $row['num_replies'] + 1 < $modSettings['enableAllMessages']) {
                        $pages .= '<a class="navPages" href="' . URL::topic($row['id_topic'], $row['first_subject'], 0) . ';all">' . $txt['show_all'] . '</a>';
                    }
                    $pages .= ' ';
                } else {
                    $pages = '';
                }
                $f_post_mem_href = !empty($row['id_member_started']) ? URL::user($row['id_member_started'], $memberContext[$memID]['name']) : '';
                $t_href = URL::topic($row['id_topic'], $row['first_subject'], 0);
                $l_post_mem_href = !empty($row['last_id_member']) ? URL::user($row['last_id_member'], $row['last_display_name']) : '';
                $l_post_msg_href = URL::topic($row['id_topic'], $row['last_subject'], $user_info['is_guest'] ? !empty($options['view_newest_first']) ? 0 : (int) ($row['num_replies'] / $context['pageindex_multiplier']) * $context['pageindex_multiplier'] : 0, $user_info['is_guest'] ? true : false, $user_info['is_guest'] ? '' : '.msg' . $row['id_last_msg'], $user_info['is_guest'] ? '#msg' . $row['id_last_msg'] : '#new');
                $context['topics'][$row['id_topic']] = array('id' => $row['id_topic'], 'first_post' => array('member' => array('username' => $memberContext[$memID]['username'], 'name' => $memberContext[$memID]['name'], 'id' => $memID, 'href' => $f_post_mem_href, 'link' => !empty($row['first_id_member']) ? '<a onclick="getMcard(' . $row['id_member_started'] . ', $(this));return(false);" href="' . $f_post_mem_href . '" title="' . $txt['profile_of'] . ' ' . $row['first_display_name'] . '">' . $row['first_display_name'] . '</a>' : $memberContext[$memID]['name'], 'avatar' => &$memberContext[$memID]['avatar']['image']), 'icon_url' => getPostIcon($row['icon']), 'time' => timeformat($row['poster_time']), 'href' => $t_href, 'link' => '<a href="' . $t_href . '">' . $row['first_subject'] . '</a>', 'id' => $row['id_first_msg']), 'last_post' => array('id' => $row['id_last_msg'], 'member' => array('username' => $row['last_member_name'], 'name' => $row['last_display_name'], 'id' => $row['last_id_member'], 'href' => $l_post_mem_href, 'link' => !empty($row['last_id_member']) ? '<a onclick="getMcard(' . $row['last_id_member'] . ', $(this));return(false);" href="' . $l_post_mem_href . '">' . $row['last_display_name'] . '</a>' : $row['last_display_name']), 'time' => timeformat($row['last_post_time']), 'timestamp' => forum_time(true, $row['last_post_time']), 'subject' => $row['last_subject'], 'icon' => $row['last_icon'], 'icon_url' => getPostIcon($row['last_icon']), 'href' => $l_post_msg_href, 'link' => '<a href="' . $l_post_msg_href . ($row['num_replies'] == 0 ? '' : ' rel="nofollow"') . '>' . $row['last_subject'] . '</a>'), 'is_posted_in' => false, 'new' => false, 'is_sticky' => $row['is_sticky'], 'is_locked' => $row['locked'], 'is_poll' => $modSettings['pollMode'] == '1' && $row['id_poll'] > 0, 'is_hot' => $row['num_replies'] >= $modSettings['hotTopicPosts'], 'is_very_hot' => $row['num_replies'] >= $modSettings['hotTopicVeryPosts'], 'views' => $row['num_views'], 'replies' => $row['num_replies'], 'prefix' => $row['prefix_name'] ? '<a href="' . $scripturl . '?board=' . $board . ';prefix=' . $row['id_prefix'] . '" class="prefix">' . (html_entity_decode($row['prefix_name']) . '</a>') : '', 'pages' => $pages, 'approved' => $row['approved'], 'unapproved_posts' => $row['unapproved_posts'], 'is_old' => !empty($modSettings['oldTopicDays']) ? $context['time_now'] - $row['last_post_time'] > $modSettings['oldTopicDays'] * 86400 : false, 'board' => isset($row['id_board']) && !empty($row['id_board']) ? array('name' => $row['board_name'], 'id' => $row['id_board'], 'href' => URL::board($row['id_board'], $row['board_name'])) : array('name' => '', 'id' => 0, 'href' => ''));
                determineTopicClass($context['topics'][$row['id_topic']]);
            }
            mysql_free_result($request);
        }
    } else {
        loadMemberContext($memID);
        while ($row = mysql_fetch_assoc($request)) {
            $context['results_counter']++;
            $check_boards = array(0, $row['id_board']);
            // 0 is for admin
            $context['can_see_hidden_level1'] = count(array_intersect($check_boards, $boards_hidden_1)) > 0;
            $context['can_see_hidden_level2'] = count(array_intersect($check_boards, $boards_hidden_2)) > 0;
            $context['can_see_hidden_level3'] = count(array_intersect($check_boards, $boards_hidden_3)) > 0;
            $context['can_see_like'] = count(array_intersect($check_boards, $boards_like_see)) > 0;
            $context['can_give_like'] = count(array_intersect($check_boards, $boards_like_give)) > 0;
            // Censor....
            censorText($row['body']);
            censorText($row['subject']);
            getCachedPost($row);
            // And the array...
            $i = $counter += $reverse ? -1 : 1;
            $thref = URL::topic($row['id_topic'], $row['first_subject'], 0, false, '.msg' . $row['id_msg'], '#' . $row['id_msg']);
            $topichref = URL::topic($row['id_topic'], $row['first_subject'], 0);
            $bhref = URL::board($row['id_board'], $row['bname'], 0, false);
            $fhref = empty($row['id_first_member']) ? '' : URL::user($row['id_first_member'], $row['first_poster_name']);
            $context['posts'][$i] = array('body' => $row['body'], 'counter' => $counter, 'icon' => $row['icon'], 'icon_url' => getPostIcon($row['icon']), 'category' => array('id' => $row['id_cat'], 'name' => $row['cname'], 'href' => $scripturl . '#c' . $row['id_cat'], 'link' => '<a href="' . $scripturl . '#c' . $row['id_cat'] . '">' . $row['cname'] . '</a>'), 'board' => array('id' => $row['id_board'], 'name' => $row['bname'], 'href' => $bhref, 'link' => '<a href="' . $bhref . '">' . $row['bname'] . '</a>'), 'member' => &$memberContext[$memID], 'href' => $thref, 'link' => '<a href="' . $thref . '" rel="nofollow">' . $row['subject'] . '</a>', 'subject' => $row['subject'], 'time' => timeformat($row['poster_time']), 'timestamp' => forum_time(true, $row['poster_time']), 'first_poster' => array('id' => $row['id_first_member'], 'name' => $row['first_poster_name'], 'href' => $fhref, 'link' => empty($row['id_first_member']) ? $row['first_poster_name'] : '<a href="' . $fhref . '">' . $row['first_poster_name'] . '</a>', 'time' => timeformat($row['time_started'])), 'topic' => array('id' => $row['id_topic'], 'href' => $topichref, 'link' => '<a href="' . $topichref . '" rel="nofollow">' . $row['first_subject'] . '</a>'), 'permahref' => $scripturl . '?msg=' . $row['id_msg'], 'permalink' => $txt['view_in_thread'], 'id' => $row['id_msg'], 'id_member' => $memID, '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'], 'likes_count' => $row['likes_count'], 'like_status' => $row['like_status'], 'liked' => $row['liked'], 'like_updated' => $row['like_updated'], 'likers' => '', 'likelink' => '');
            if ($context['can_see_like']) {
                Ratings::addContent($context['posts'][$i], $context['can_give_like'], $time_now);
            }
            if ($user_info['id'] == $row['id_member_started']) {
                $board_ids['own'][$row['id_board']][] = $counter;
            }
            $board_ids['any'][$row['id_board']][] = $counter;
        }
        mysql_free_result($request);
    }
    // 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][$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]['can_delete'] &= $context['posts'][$counter]['delete_possible'];
        $context['posts'][$counter]['can_quote'] = $context['posts'][$counter]['can_reply'] && $quote_enabled;
    }
}
Esempio n. 16
0
function MessageIndex()
{
    global $txt, $scripturl, $board, $modSettings, $context;
    global $options, $settings, $board_info, $user_info, $smcFunc, $sourcedir;
    global $memberContext;
    // If this is a redirection board head off.
    if ($board_info['redirect']) {
        smf_db_query('
			UPDATE {db_prefix}boards
			SET num_posts = num_posts + 1
			WHERE id_board = {int:current_board}', array('current_board' => $board));
        redirectexit($board_info['redirect']);
    }
    EoS_Smarty::loadTemplate('messageindex');
    fetchNewsItems($board, 0);
    $context['act_as_cat'] = $board_info['allow_topics'] ? false : true;
    $context['name'] = $board_info['name'];
    $context['description'] = $board_info['description'];
    // How many topics do we have in total?
    $board_info['total_topics'] = allowedTo('approve_posts') ? $board_info['num_topics'] + $board_info['unapproved_topics'] : $board_info['num_topics'] + $board_info['unapproved_user_topics'];
    // View all the topics, or just a few?
    $context['topics_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['topics_per_page']) ? $options['topics_per_page'] : $modSettings['defaultMaxTopics'];
    $context['messages_per_page'] = commonAPI::getMessagesPerPage();
    $maxindex = isset($_REQUEST['all']) && !empty($modSettings['enableAllMessages']) ? $board_info['total_topics'] : $context['topics_per_page'];
    // Right, let's only index normal stuff!
    if (count($_GET) > 1) {
        $session_name = session_name();
        foreach ($_GET as $k => $v) {
            if (!in_array($k, array('board', 'start', $session_name))) {
                $context['robot_no_index'] = true;
            }
        }
    }
    if (!empty($_REQUEST['start']) && (!is_numeric($_REQUEST['start']) || $_REQUEST['start'] % $context['messages_per_page'] != 0)) {
        $context['robot_no_index'] = true;
    }
    // If we can view unapproved messages and there are some build up a list.
    if (allowedTo('approve_posts') && ($board_info['unapproved_topics'] || $board_info['unapproved_posts'])) {
        $untopics = $board_info['unapproved_topics'] ? '<a href="' . $scripturl . '?action=moderate;area=postmod;sa=topics;brd=' . $board . '">' . $board_info['unapproved_topics'] . '</a>' : 0;
        $unposts = $board_info['unapproved_posts'] ? '<a href="' . $scripturl . '?action=moderate;area=postmod;sa=posts;brd=' . $board . '">' . ($board_info['unapproved_posts'] - $board_info['unapproved_topics']) . '</a>' : 0;
        $context['unapproved_posts_message'] = sprintf($txt['there_are_unapproved_topics'], $untopics, $unposts, $scripturl . '?action=moderate;area=postmod;sa=' . ($board_info['unapproved_topics'] ? 'topics' : 'posts') . ';brd=' . $board);
    }
    // Make sure the starting place makes sense and construct the page index.
    if (isset($_REQUEST['sort'])) {
        $context['page_index'] = constructPageIndex(URL::board($board_info['id'], $board_info['name'], '%1$d;sort=' . $_REQUEST['sort'] . (isset($_REQUEST['desc']) ? ';desc' : ''), true), $_REQUEST['start'], $board_info['total_topics'], $maxindex, true);
    } else {
        //$context['page_index'] = constructPageIndex($scripturl . '?board=' . $board . '.%1$d', $_REQUEST['start'], $board_info['total_topics'], $maxindex, true);
        $context['page_index'] = constructPageIndex(URL::board($board_info['id'], $board_info['name'], '%1$d', true), $_REQUEST['start'], $board_info['total_topics'], $maxindex, true);
    }
    $context['start'] =& $_REQUEST['start'];
    setcookie('smf_topicstart', intval($board) . '_' . $context['start'], time() + 86400, '/');
    // Set a canonical URL for this page.
    $context['canonical_url'] = URL::board($board, $board_info['name'], $context['start'], true);
    $context['links'] = array('first' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?board=' . $board . '.0' : '', 'prev' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?board=' . $board . '.' . ($_REQUEST['start'] - $context['topics_per_page']) : '', 'next' => $_REQUEST['start'] + $context['topics_per_page'] < $board_info['total_topics'] ? $scripturl . '?board=' . $board . '.' . ($_REQUEST['start'] + $context['topics_per_page']) : '', 'last' => $_REQUEST['start'] + $context['topics_per_page'] < $board_info['total_topics'] ? $scripturl . '?board=' . $board . '.' . floor(($board_info['total_topics'] - 1) / $context['topics_per_page']) * $context['topics_per_page'] : '', 'up' => $board_info['parent'] == 0 ? $scripturl . '?' : $scripturl . '?board=' . $board_info['parent'] . '.0');
    $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['topics_per_page'] + 1, 'num_pages' => floor(($board_info['total_topics'] - 1) / $context['topics_per_page']) + 1);
    if (isset($_REQUEST['all']) && !empty($modSettings['enableAllMessages']) && $maxindex > $modSettings['enableAllMessages']) {
        $maxindex = $modSettings['enableAllMessages'];
        $_REQUEST['start'] = 0;
    }
    // Build a list of the board's moderators.
    $context['moderators'] =& $board_info['moderators'];
    $context['link_moderators'] = array();
    if (!empty($board_info['moderators'])) {
        foreach ($board_info['moderators'] as $mod) {
            $context['link_moderators'][] = '<a href="' . $scripturl . '?action=profile;u=' . $mod['id'] . '" title="' . $txt['board_moderator'] . '">' . $mod['name'] . '</a>';
        }
        //$context['linktree'][count($context['linktree']) - 1]['extra_after'] = ' (' . (count($context['link_moderators']) == 1 ? $txt['moderator'] : $txt['moderators']) . ': ' . implode(', ', $context['link_moderators']) . ')';
    }
    // Mark current and parent boards as seen.
    if (!$user_info['is_guest']) {
        // We can't know they read it if we allow prefetches.
        if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') {
            ob_end_clean();
            header('HTTP/1.1 403 Prefetch Forbidden');
            die;
        }
        smf_db_insert('replace', '{db_prefix}log_boards', array('id_msg' => 'int', 'id_member' => 'int', 'id_board' => 'int'), array($modSettings['maxMsgID'], $user_info['id'], $board), array('id_member', 'id_board'));
        if (!empty($board_info['parent_boards'])) {
            smf_db_query('
				UPDATE {db_prefix}log_boards
				SET id_msg = {int:id_msg}
				WHERE id_member = {int:current_member}
					AND id_board IN ({array_int:board_list})', array('current_member' => $user_info['id'], 'board_list' => array_keys($board_info['parent_boards']), 'id_msg' => $modSettings['maxMsgID']));
            // We've seen all these boards now!
            foreach ($board_info['parent_boards'] as $k => $dummy) {
                if (isset($_SESSION['topicseen_cache'][$k])) {
                    unset($_SESSION['topicseen_cache'][$k]);
                }
            }
        }
        if (isset($_SESSION['topicseen_cache'][$board])) {
            unset($_SESSION['topicseen_cache'][$board]);
        }
        $request = smf_db_query('
			SELECT sent
			FROM {db_prefix}log_notify
			WHERE id_board = {int:current_board}
				AND id_member = {int:current_member}
			LIMIT 1', array('current_board' => $board, 'current_member' => $user_info['id']));
        $context['is_marked_notify'] = mysql_num_rows($request) != 0;
        if ($context['is_marked_notify']) {
            list($sent) = mysql_fetch_row($request);
            if (!empty($sent)) {
                smf_db_query('
					UPDATE {db_prefix}log_notify
					SET sent = {int:is_sent}
					WHERE id_board = {int:current_board}
						AND id_member = {int:current_member}', array('current_board' => $board, 'current_member' => $user_info['id'], 'is_sent' => 0));
            }
        }
        mysql_free_result($request);
    } else {
        $context['is_marked_notify'] = false;
    }
    // 'Print' the header and board info.
    $context['page_number'] = isset($_REQUEST['start']) ? $_REQUEST['start'] / $context['topics_per_page'] : 0;
    $context['page_title'] = strip_tags($board_info['name'] . ((int) $context['page_number'] > 0 ? ' - ' . $txt['page'] . ' ' . ($context['page_number'] + 1) : ''));
    $context['meta_page_description'] = !empty($board_info['description']) ? $board_info['description'] : $context['page_title'];
    // Set the variables up for the template.
    $context['can_mark_notify'] = allowedTo('mark_notify') && !$user_info['is_guest'];
    $context['can_post_new'] = allowedTo('post_new') || $modSettings['postmod_active'] && allowedTo('post_unapproved_topics');
    $context['can_post_poll'] = $modSettings['pollMode'] == '1' && allowedTo('poll_post') && $context['can_post_new'];
    $context['can_moderate_forum'] = allowedTo('moderate_forum');
    $context['can_approve_posts'] = allowedTo('approve_posts');
    require_once $sourcedir . '/lib/Subs-BoardIndex.php';
    $boardIndexOptions = array('include_categories' => false, 'base_level' => $board_info['child_level'] + 1, 'parent_id' => $board_info['id'], 'set_latest_post' => false, 'countChildPosts' => !empty($modSettings['countChildPosts']));
    $context['boards'] = getBoardIndex($boardIndexOptions);
    // Nosey, nosey - who's viewing this topic?
    if (!empty($settings['display_who_viewing'])) {
        $context['view_members'] = array();
        $context['view_members_list'] = array();
        $context['view_num_hidden'] = 0;
        $request = smf_db_query('
			SELECT
				lo.id_member, lo.log_time, mem.real_name, mem.member_name, mem.show_online, mem.id_group, mem.id_post_group
			FROM {db_prefix}log_online AS lo
				LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lo.id_member)
			WHERE INSTR(lo.url, {string:in_url_string}) > 0 OR lo.session = {string:session}', array('reg_member_group' => 0, 'in_url_string' => 's:5:"board";i:' . $board . ';', 'session' => $user_info['is_guest'] ? 'ip' . $user_info['ip'] : session_id()));
        while ($row = mysql_fetch_assoc($request)) {
            if (empty($row['id_member'])) {
                continue;
            }
            $class = 'member group_' . (empty($row['id_group']) ? $row['id_post_group'] : $row['id_group']) . (in_array($row['id_member'], $user_info['buddies']) ? ' buddy' : '');
            $href = URL::user($row['id_member'], $row['real_name']);
            if ($row['id_member'] == $user_info['id']) {
                $link = '<strong>' . $txt['you'] . '</strong>';
            } else {
                $link = '<a onclick="getMcard(' . $row['id_member'] . ');return(false);" class="' . $class . '" href="' . $href . '">' . $row['real_name'] . '</a>';
            }
            if (!empty($row['show_online']) || allowedTo('moderate_forum')) {
                $context['view_members_list'][$row['log_time'] . $row['member_name']] = empty($row['show_online']) ? '<em>' . $link . '</em>' : $link;
            }
            $context['view_members'][$row['log_time'] . $row['member_name']] = array('id' => $row['id_member'], 'username' => $row['member_name'], 'name' => $row['real_name'], 'group' => $row['id_group'], 'href' => $href, 'link' => $link, 'hidden' => empty($row['show_online']));
            if (empty($row['show_online'])) {
                $context['view_num_hidden']++;
            }
        }
        $context['view_num_guests'] = mysql_num_rows($request) - count($context['view_members']);
        mysql_free_result($request);
        // Put them in "last clicked" order.
        krsort($context['view_members_list']);
        krsort($context['view_members']);
        $context['full_members_viewing_list'] = empty($context['view_members_list']) ? '0 ' . $txt['members'] : implode(', ', $context['view_members_list']) . ((empty($context['view_num_hidden']) or $context['can_moderate_forum']) ? '' : ' (+ ' . $context['view_num_hidden'] . ' ' . $txt['hidden'] . ')');
    }
    // Default sort methods.
    $sort_methods = array('subject' => 'mf.subject', 'starter' => 'IFNULL(memf.real_name, mf.poster_name)', 'last_poster' => 'IFNULL(meml.real_name, ml.poster_name)', 'replies' => 't.num_replies', 'views' => 't.num_views', 'first_post' => 't.id_topic', 'last_post' => 't.id_last_msg');
    // They didn't pick one, default to by last post descending.
    if (!isset($_REQUEST['sort']) || !isset($sort_methods[$_REQUEST['sort']])) {
        $context['sort_by'] = 'last_post';
        $_REQUEST['sort'] = 'id_last_msg';
        $ascending = isset($_REQUEST['asc']);
    } else {
        $context['sort_by'] = $_REQUEST['sort'];
        $_REQUEST['sort'] = $sort_methods[$_REQUEST['sort']];
        $ascending = !isset($_REQUEST['desc']);
    }
    $context['sort_direction'] = $ascending ? 'up' : 'down';
    // Calculate the fastest way to get the topics.
    $start = (int) $_REQUEST['start'];
    if ($start > ($board_info['total_topics'] - 1) / 2) {
        $ascending = !$ascending;
        $fake_ascending = true;
        $maxindex = $board_info['total_topics'] < $start + $maxindex + 1 ? $board_info['total_topics'] - $start : $maxindex;
        $start = $board_info['total_topics'] < $start + $maxindex + 1 ? 0 : $board_info['total_topics'] - $start - $maxindex;
    } else {
        $fake_ascending = false;
    }
    $topic_ids = array();
    $context['topics'] = array();
    $prefixid = isset($_REQUEST['prefix']) ? (int) $_REQUEST['prefix'] : 0;
    $prefixfilter = !empty($prefixid) ? 't.id_prefix = {int:id_prefix} AND ' : '';
    // Sequential pages are often not optimized, so we add an additional query.
    $pre_query = $start > 0;
    if ($pre_query && $maxindex > 0) {
        $request = smf_db_query('
			SELECT t.id_topic
			FROM {db_prefix}topics AS t' . ($context['sort_by'] === 'last_poster' ? '
				INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)' : (in_array($context['sort_by'], array('starter', 'subject')) ? '
				INNER JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg)' : '')) . ($context['sort_by'] === 'starter' ? '
				LEFT JOIN {db_prefix}members AS memf ON (memf.id_member = mf.id_member)' : '') . ($context['sort_by'] === 'last_poster' ? '
				LEFT JOIN {db_prefix}members AS meml ON (meml.id_member = ml.id_member)' : '') . '
			WHERE ' . $prefixfilter . ' t.id_board = {int:current_board}' . (!$modSettings['postmod_active'] || $context['can_approve_posts'] ? '' : '
				AND (t.approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR t.id_member_started = {int:current_member}') . ')') . '
			ORDER BY ' . (!empty($modSettings['enableStickyTopics']) ? 'is_sticky' . ($fake_ascending ? '' : ' DESC') . ', ' : '') . $_REQUEST['sort'] . ($ascending ? '' : ' DESC') . '
			LIMIT {int:start}, {int:maxindex}', array('current_board' => $board, 'current_member' => $user_info['id'], 'is_approved' => 1, 'id_member_guest' => 0, 'start' => $start, 'maxindex' => $maxindex, 'id_prefix' => $prefixid));
        $topic_ids = array();
        while ($row = mysql_fetch_assoc($request)) {
            $topic_ids[] = $row['id_topic'];
        }
    }
    // Grab the appropriate topic information...
    if (!$pre_query || !empty($topic_ids)) {
        // For search engine effectiveness we'll link guests differently.
        $context['pageindex_multiplier'] = commonAPI::getMessagesPerPage();
        $result = smf_db_query('
			SELECT 
				t.id_topic, t.num_replies, t.locked, t.num_views, t.is_sticky, t.id_poll, t.id_previous_board,
				' . ($user_info['is_guest'] ? '0' : 'IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1') . ' AS new_from,
				t.id_last_msg, t.approved, t.unapproved_posts, t.id_prefix, ml.poster_time AS last_poster_time,
				ml.id_msg_modified, ml.subject AS last_subject, ml.icon AS last_icon,
				ml.poster_name AS last_member_name, ml.id_member AS last_id_member,
				IFNULL(meml.real_name, ml.poster_name) AS last_display_name, t.id_first_msg,
				mf.poster_time AS first_poster_time, mf.subject AS first_subject, mf.icon AS first_icon,
				mf.poster_name AS first_member_name, mf.id_member AS first_id_member,
				IFNULL(memf.real_name, mf.poster_name) AS first_display_name,
				ml.smileys_enabled AS last_smileys, mf.smileys_enabled AS first_smileys,
				p.name AS prefix_name
			FROM {db_prefix}topics AS t	
				INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
				INNER JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg)
				LEFT JOIN {db_prefix}members AS meml ON (meml.id_member = ml.id_member)
				LEFT JOIN {db_prefix}members AS memf ON (memf.id_member = mf.id_member)' . ($user_info['is_guest'] ? '' : '
				LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})
				LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = {int:current_board} AND lmr.id_member = {int:current_member})') . '
				LEFT JOIN {db_prefix}prefixes AS p ON p.id_prefix = t.id_prefix 
			WHERE ' . $prefixfilter . ($pre_query ? 't.id_topic IN ({array_int:topic_list})' : 't.id_board = {int:current_board}') . (!$modSettings['postmod_active'] || $context['can_approve_posts'] ? '' : '
				AND (t.approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR t.id_member_started = {int:current_member}') . ')') . '
			ORDER BY ' . ($pre_query ? 'FIND_IN_SET(t.id_topic, {string:find_set_topics})' : (!empty($modSettings['enableStickyTopics']) ? 'is_sticky' . ($fake_ascending ? '' : ' DESC') . ', ' : '') . $_REQUEST['sort'] . ($ascending ? '' : ' DESC')) . '
			LIMIT ' . ($pre_query ? '' : '{int:start}, ') . '{int:maxindex}', array('current_board' => $board, 'current_member' => $user_info['id'], 'topic_list' => $topic_ids, 'is_approved' => 1, 'find_set_topics' => implode(',', $topic_ids), 'start' => $start, 'maxindex' => $maxindex, 'id_prefix' => $prefixid));
        // Begin 'printing' the message index for current board.
        $first_posters = array();
        while ($row = mysql_fetch_assoc($result)) {
            if ($row['id_poll'] > 0 && $modSettings['pollMode'] == '0') {
                continue;
            }
            if (!$pre_query) {
                $topic_ids[] = $row['id_topic'];
            }
            $row['first_body'] = '';
            $row['last_body'] = '';
            censorText($row['first_subject']);
            if ($row['id_first_msg'] == $row['id_last_msg']) {
                $row['last_subject'] = $row['first_subject'];
            } else {
                censorText($row['last_subject']);
            }
            // Decide how many pages the topic should have.
            if ($row['num_replies'] + 1 > $context['messages_per_page']) {
                $pages = '&nbsp;&nbsp;';
                // We can't pass start by reference.
                $start = -1;
                $pages .= constructPageIndex(URL::topic($row['id_topic'], $row['first_subject'], '%1$d'), $start, $row['num_replies'] + 1, $context['messages_per_page'], true, false, true);
                // If we can use all, show all.
                if (!empty($modSettings['enableAllMessages']) && $row['num_replies'] + 1 < $modSettings['enableAllMessages']) {
                    $pages .= '<a class="navPages compact" href="' . URL::topic($row['id_topic'], $row['first_subject'], 0) . ';all">' . $txt['show_all'] . '</a>';
                }
                $pages .= ' ';
            } else {
                $pages = '';
            }
            $first_posters[$row['id_topic']] = $row['first_id_member'];
            // 'Print' the topic info.
            $f_post_mem_href = !empty($row['first_id_member']) ? URL::user($row['first_id_member'], $row['first_display_name']) : '';
            $t_href = URL::topic($row['id_topic'], $row['first_subject'], 0);
            $l_post_mem_href = !empty($row['last_id_member']) ? URL::user($row['last_id_member'], $row['last_display_name']) : '';
            $l_post_msg_href = URL::topic($row['id_topic'], $row['last_subject'], $user_info['is_guest'] ? !empty($options['view_newest_first']) ? 0 : (int) ($row['num_replies'] / $context['pageindex_multiplier']) * $context['pageindex_multiplier'] : 0, $user_info['is_guest'] ? true : false, $user_info['is_guest'] ? '' : '.msg' . $row['id_last_msg'], $user_info['is_guest'] ? '#msg' . $row['id_last_msg'] : '#new');
            $context['topics'][$row['id_topic']] = array('id' => $row['id_topic'], 'first_post' => array('id' => $row['id_first_msg'], 'member' => array('username' => $row['first_member_name'], 'name' => $row['first_display_name'], 'id' => $row['first_id_member'], 'href' => $f_post_mem_href, 'link' => !empty($row['first_id_member']) ? '<a onclick="getMcard(' . $row['first_id_member'] . ', $(this));return(false);" href="' . $f_post_mem_href . '" title="' . $txt['profile_of'] . ' ' . $row['first_display_name'] . '">' . $row['first_display_name'] . '</a>' : $row['first_display_name']), 'time' => timeformat($row['first_poster_time']), 'timestamp' => forum_time(true, $row['first_poster_time']), 'subject' => $row['first_subject'], 'icon' => $row['first_icon'], 'icon_url' => getPostIcon($row['first_icon']), 'href' => $t_href, 'link' => '<a href="' . $t_href . '">' . $row['first_subject'] . '</a>'), 'last_post' => array('id' => $row['id_last_msg'], 'member' => array('username' => $row['last_member_name'], 'name' => $row['last_display_name'], 'id' => $row['last_id_member'], 'href' => $l_post_mem_href, 'link' => !empty($row['last_id_member']) ? '<a onclick="getMcard(' . $row['last_id_member'] . ', $(this));return(false);" href="' . $l_post_mem_href . '">' . $row['last_display_name'] . '</a>' : $row['last_display_name']), 'time' => timeformat($row['last_poster_time']), 'timestamp' => forum_time(true, $row['last_poster_time']), 'subject' => $row['last_subject'], 'icon' => $row['last_icon'], 'icon_url' => getPostIcon($row['last_icon']), 'href' => $l_post_msg_href, 'link' => '<a href="' . $l_post_msg_href . ($row['num_replies'] == 0 ? '' : ' rel="nofollow"') . '>' . $row['last_subject'] . '</a>'), 'prefix' => $row['prefix_name'] ? '<a href="' . $scripturl . '?board=' . $board . ';prefix=' . $row['id_prefix'] . '" class="prefix">' . (html_entity_decode($row['prefix_name']) . '</a>') : '', 'is_sticky' => !empty($modSettings['enableStickyTopics']) && !empty($row['is_sticky']), 'is_locked' => !empty($row['locked']), 'is_poll' => $modSettings['pollMode'] == '1' && $row['id_poll'] > 0, 'is_hot' => $row['num_replies'] >= $modSettings['hotTopicPosts'], 'is_very_hot' => $row['num_replies'] >= $modSettings['hotTopicVeryPosts'], 'is_posted_in' => false, 'is_old' => !empty($modSettings['oldTopicDays']) ? $context['time_now'] - $row['last_poster_time'] > $modSettings['oldTopicDays'] * 86400 : false, 'subject' => $row['first_subject'], 'new' => $row['new_from'] <= $row['id_msg_modified'], 'new_from' => $row['new_from'], 'newtime' => $row['new_from'], 'new_href' => URL::topic($row['id_topic'], $row['first_subject'], 0, false, '.msg' . $row['new_from'], '#new'), 'pages' => $pages, 'replies' => comma_format($row['num_replies']), 'views' => comma_format($row['num_views']), 'approved' => $row['approved'], 'unapproved_posts' => $row['unapproved_posts']);
            determineTopicClass($context['topics'][$row['id_topic']]);
            if (!empty($context['topics'][$row['id_topic']]['prefix'])) {
                $context['topics'][$row['id_topic']]['prefix'] .= '&nbsp;';
            }
        }
        if (!empty($settings['show_user_images']) && empty($options['show_no_avatars'])) {
            $all_posters = array_unique($first_posters);
            loadMemberData($all_posters);
            foreach ($context['topics'] as &$_topic) {
                if (!isset($memberContext[$first_posters[$_topic['id']]])) {
                    loadMemberContext($first_posters[$_topic['id']], true);
                }
                if (isset($memberContext[$first_posters[$_topic['id']]]['avatar']['image'])) {
                    $_topic['first_post']['member']['avatar'] =& $memberContext[$first_posters[$_topic['id']]]['avatar']['image'];
                }
            }
        }
        mysql_free_result($result);
        // Fix the sequence of topics if they were retrieved in the wrong order. (for speed reasons...)
        if ($fake_ascending) {
            $context['topics'] = array_reverse($context['topics'], true);
        }
        if (!empty($modSettings['enableParticipation']) && !$user_info['is_guest'] && !empty($topic_ids)) {
            $result = smf_db_query('
				SELECT id_topic
				FROM {db_prefix}messages
				WHERE id_topic IN ({array_int:topic_list})
					AND id_member = {int:current_member}
				GROUP BY id_topic
				LIMIT ' . count($topic_ids), array('current_member' => $user_info['id'], 'topic_list' => $topic_ids));
            while ($row = mysql_fetch_assoc($result)) {
                if ($context['topics'][$row['id_topic']]['first_post']['member']['id'] != $user_info['id']) {
                    $context['topics'][$row['id_topic']]['is_posted_in'] = true;
                }
            }
            mysql_free_result($result);
        }
    }
    $context['jump_to'] = array('label' => addslashes(un_htmlspecialchars($txt['jump_to'])), 'board_name' => htmlspecialchars(strtr(strip_tags($board_info['name']), array('&amp;' => '&'))), 'child_level' => $board_info['child_level']);
    // Is Quick Moderation active/needed?
    if (!empty($options['display_quick_mod']) && !empty($context['topics'])) {
        $context['can_lock'] = allowedTo('lock_any');
        $context['can_sticky'] = allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']);
        $context['can_move'] = allowedTo('move_any');
        $context['can_remove'] = allowedTo('remove_any');
        $context['can_merge'] = allowedTo('merge_any');
        // Ignore approving own topics as it's unlikely to come up...
        $context['can_approve'] = $modSettings['postmod_active'] && allowedTo('approve_posts') && !empty($board_info['unapproved_topics']);
        // Can we restore topics?
        $context['can_restore'] = allowedTo('move_any') && !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board;
        // Set permissions for all the topics.
        foreach ($context['topics'] as $t => $topic) {
            $started = $topic['first_post']['member']['id'] == $user_info['id'];
            $context['topics'][$t]['quick_mod'] = array('lock' => allowedTo('lock_any') || $started && allowedTo('lock_own'), 'sticky' => allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']), 'move' => allowedTo('move_any') || $started && allowedTo('move_own'), 'modify' => allowedTo('modify_any') || $started && allowedTo('modify_own'), 'remove' => allowedTo('remove_any') || $started && allowedTo('remove_own'), 'approve' => $context['can_approve'] && $topic['unapproved_posts']);
            $context['can_lock'] |= $started && allowedTo('lock_own');
            $context['can_move'] |= $started && allowedTo('move_own');
            $context['can_remove'] |= $started && allowedTo('remove_own');
        }
        // Find the boards/cateogories they can move their topic to.
        if ($options['display_quick_mod'] && $context['can_move'] && !empty($context['topics'])) {
            require_once $sourcedir . '/lib/Subs-MessageIndex.php';
            $boardListOptions = array('excluded_boards' => array($board), 'not_redirection' => true, 'use_permissions' => true, 'selected_board' => empty($_SESSION['move_to_topic']) ? null : $_SESSION['move_to_topic']);
            $context['move_to_boards'] = getBoardList($boardListOptions);
            // Make the boards safe for display.
            foreach ($context['move_to_boards'] as $id_cat => $cat) {
                $context['move_to_boards'][$id_cat]['name'] = strip_tags($cat['name']);
                foreach ($cat['boards'] as $id_board => $board) {
                    $context['move_to_boards'][$id_cat]['boards'][$id_board]['name'] = strip_tags($board['name']);
                }
            }
            // With no other boards to see, it's useless to move.
            if (empty($context['move_to_boards'])) {
                $context['can_move'] = false;
            }
        }
        // Can we use quick moderation checkboxes?
        if ($options['display_quick_mod']) {
            $context['can_quick_mod'] = $context['user']['is_logged'] || $context['can_approve'] || $context['can_remove'] || $context['can_lock'] || $context['can_sticky'] || $context['can_move'] || $context['can_merge'] || $context['can_restore'];
        }
    }
    // If there are children, but no topics and no ability to post topics...
    $context['no_topic_listing'] = !empty($context['boards']) && empty($context['topics']) && !$context['can_post_new'];
    $context['normal_buttons'] = array('new_topic' => array('test' => 'can_post_new', 'text' => 'new_topic', 'image' => 'new_topic.gif', 'lang' => true, 'url' => $scripturl . '?action=post;board=' . $context['current_board'] . '.0', 'active' => true), 'post_poll' => array('test' => 'can_post_poll', 'text' => 'new_poll', 'image' => 'new_poll.gif', 'lang' => true, 'url' => $scripturl . '?action=post;board=' . $context['current_board'] . '.0;poll'), 'notify' => array('test' => 'can_mark_notify', 'text' => $context['is_marked_notify'] ? 'unnotify' : 'notify', 'image' => ($context['is_marked_notify'] ? 'un' : '') . 'notify.gif', 'lang' => true, 'custom' => 'onclick="return confirm(\'' . ($context['is_marked_notify'] ? $txt['notification_disable_board'] : $txt['notification_enable_board']) . '\');"', 'url' => $scripturl . '?action=notifyboard;sa=' . ($context['is_marked_notify'] ? 'off' : 'on') . ';board=' . $context['current_board'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'markread' => array('text' => 'mark_read_short', 'image' => 'markread.gif', 'lang' => true, 'url' => $scripturl . '?action=markasread;sa=board;board=' . $context['current_board'] . '.0;' . $context['session_var'] . '=' . $context['session_id']));
    if (!empty($context['topics'])) {
        $context['subject_sort_header'] = '<a rel="nofollow" href="' . $scripturl . '?board=' . $context['current_board'] . '.' . $context['start'] . ';sort=subject' . ($context['sort_by'] == 'subject' && $context['sort_direction'] == 'up' ? ';desc' : '') . '">' . $txt['subject'] . ($context['sort_by'] == 'subject' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.gif" alt="" />' : '') . '</a> / <a rel="nofollow" href="' . $scripturl . '?board=' . $context['current_board'] . '.' . $context['start'] . ';sort=starter' . ($context['sort_by'] == 'starter' && $context['sort_direction'] == 'up' ? ';desc' : '') . '">' . $txt['started_by'] . ($context['sort_by'] == 'starter' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.gif" alt="" />' : '') . '</a>';
        $context['views_sort_header'] = '<a rel="nofollow" href="' . $scripturl . '?board=' . $context['current_board'] . '.' . $context['start'] . ';sort=replies' . ($context['sort_by'] == 'replies' && $context['sort_direction'] == 'up' ? ';desc' : '') . '">' . $txt['replies'] . ($context['sort_by'] == 'replies' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.gif" alt="" />' : '') . '</a> / <a href="' . $scripturl . '?board=' . $context['current_board'] . '.' . $context['start'] . ';sort=views' . ($context['sort_by'] == 'views' && $context['sort_direction'] == 'up' ? ';desc' : '') . '">' . $txt['views'] . ($context['sort_by'] == 'views' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.gif" alt="" />' : '') . '</a>';
        $context['lastpost_sort_header'] = '<a rel="nofollow" href="' . $scripturl . '?board=' . $context['current_board'] . '.' . $context['start'] . ';sort=last_post' . ($context['sort_by'] == 'last_post' && $context['sort_direction'] == 'up' ? ';desc' : '') . '">' . $txt['last_post'] . ($context['sort_by'] == 'last_post' ? ' <img src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.gif" alt="" />' : '') . '</a>';
    }
    // They can only mark read if they are logged in and it's enabled!
    if (!$context['user']['is_logged'] || !$settings['show_mark_read']) {
        unset($context['normal_buttons']['markread']);
    }
    HookAPI::callHook('messageindex_buttons', array(&$normal_buttons));
    enqueueThemeScript('topic', 'scripts/topic.js', true);
    HookAPI::callHook('messageindex', array(&$board_info));
}