function PrintTopic() { global $topic, $txt, $scripturl, $context, $user_info; global $board_info, $smcFunc, $modSettings; // Redirect to the boardindex if no valid topic id is provided. if (empty($topic)) { redirectexit(); } // Whatever happens don't index this. $context['robot_no_index'] = true; // Get the topic starter information. $request = smf_db_query(' SELECT m.poster_time, IFNULL(mem.real_name, m.poster_name) AS poster_name FROM {db_prefix}messages AS m LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) WHERE m.id_topic = {int:current_topic} ORDER BY m.id_msg LIMIT 1', array('current_topic' => $topic)); // Redirect to the boardindex if no valid topic id is provided. if (mysql_num_rows($request) == 0) { redirectexit(); } $row = mysql_fetch_assoc($request); mysql_free_result($request); // Lets "output" all that info. EoS_Smarty::loadTemplate('topic/printpage'); $context['board_name'] = $board_info['name']; $context['category_name'] = $board_info['cat']['name']; $context['poster_name'] = $row['poster_name']; $context['post_time'] = timeformat($row['poster_time'], false); $context['parent_boards'] = array(); foreach ($board_info['parent_boards'] as $parent) { $context['parent_boards'][] = $parent['name']; } // Split the topics up so we can print them. $request = smf_db_query(' SELECT subject, poster_time, body, IFNULL(mem.real_name, poster_name) AS poster_name FROM {db_prefix}messages AS m LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) WHERE m.id_topic = {int:current_topic}' . ($modSettings['postmod_active'] && !allowedTo('approve_posts') ? ' AND (m.approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR m.id_member = {int:current_member}') . ')' : '') . ' ORDER BY m.id_msg', array('current_topic' => $topic, 'is_approved' => 1, 'current_member' => $user_info['id'])); $context['posts'] = array(); while ($row = mysql_fetch_assoc($request)) { // Censor the subject and message. censorText($row['subject']); censorText($row['body']); $context['posts'][] = array('subject' => $row['subject'], 'member' => $row['poster_name'], 'time' => timeformat($row['poster_time'], false), 'timestamp' => forum_time(true, $row['poster_time']), 'body' => parse_bbc($row['body'], 'print')); if (!isset($context['topic_subject'])) { $context['topic_subject'] = $row['subject']; } } mysql_free_result($request); // Set a canonical URL for this page. $context['canonical_url'] = $scripturl . '?topic=' . $topic . '.0'; }
function UnapprovedAttachments() { global $txt, $scripturl, $context, $user_info, $sourcedir, $backend_subdir; $context['page_title'] = $txt['mc_unapproved_attachments']; // Once again, permissions are king! $approve_boards = boardsAllowedTo('approve_posts'); if ($approve_boards == array(0)) { $approve_query = ''; } elseif (!empty($approve_boards)) { $approve_query = ' AND m.id_board IN (' . implode(',', $approve_boards) . ')'; } else { $approve_query = ' AND 0'; } // Get together the array of things to act on, if any. $attachments = array(); if (isset($_GET['approve'])) { $attachments[] = (int) $_GET['approve']; } elseif (isset($_GET['delete'])) { $attachments[] = (int) $_GET['delete']; } elseif (isset($_POST['item'])) { foreach ($_POST['item'] as $item) { $attachments[] = (int) $item; } } // Are we approving or deleting? if (isset($_GET['approve']) || isset($_POST['do']) && $_POST['do'] == 'approve') { $curAction = 'approve'; } elseif (isset($_GET['delete']) || isset($_POST['do']) && $_POST['do'] == 'delete') { $curAction = 'delete'; } // Something to do, let's do it! if (!empty($attachments) && isset($curAction)) { checkSession('request'); // This will be handy. require_once $sourcedir . '/lib/Subs-ManageAttachments.php'; // Confirm the attachments are eligible for changing! $request = smf_db_query(' SELECT a.id_attach FROM {db_prefix}attachments AS a INNER JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg) LEFT JOIN {db_prefix}boards AS b ON (m.id_board = b.id_board) WHERE a.id_attach IN ({array_int:attachments}) AND a.approved = {int:not_approved} AND a.attachment_type = {int:attachment_type} AND {query_see_board} ' . $approve_query, array('attachments' => $attachments, 'not_approved' => 0, 'attachment_type' => 0)); $attachments = array(); while ($row = mysql_fetch_assoc($request)) { $attachments[] = $row['id_attach']; } mysql_free_result($request); // Assuming it wasn't all like, proper illegal, we can do the approving. if (!empty($attachments)) { if ($curAction == 'approve') { ApproveAttachments($attachments); } else { removeAttachments(array('id_attach' => $attachments)); } } } // How many unapproved attachments in total? $request = smf_db_query(' SELECT COUNT(*) FROM {db_prefix}attachments AS a INNER JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg) INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board) WHERE a.approved = {int:not_approved} AND a.attachment_type = {int:attachment_type} AND {query_see_board} ' . $approve_query, array('not_approved' => 0, 'attachment_type' => 0)); list($context['total_unapproved_attachments']) = mysql_fetch_row($request); mysql_free_result($request); $context['page_index'] = constructPageIndex($scripturl . '?action=moderate;area=attachmod;sa=attachments', $_GET['start'], $context['total_unapproved_attachments'], 10); $context['start'] = $_GET['start']; // Get all unapproved attachments. $request = smf_db_query(' SELECT a.id_attach, a.filename, a.size, m.id_msg, m.id_topic, m.id_board, m.subject, m.body, m.id_member, IFNULL(mem.real_name, m.poster_name) AS poster_name, m.poster_time, t.id_member_started, t.id_first_msg, b.name AS board_name, c.id_cat, c.name AS cat_name FROM {db_prefix}attachments AS a INNER JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg) 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 = m.id_board) LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat) WHERE a.approved = {int:not_approved} AND a.attachment_type = {int:attachment_type} AND {query_see_board} ' . $approve_query . ' LIMIT ' . $context['start'] . ', 10', array('not_approved' => 0, 'attachment_type' => 0)); $context['unapproved_items'] = array(); for ($i = 1; $row = mysql_fetch_assoc($request); $i++) { $context['unapproved_items'][] = array('id' => $row['id_attach'], 'alternate' => $i % 2, 'filename' => $row['filename'], 'size' => round($row['size'] / 1024, 2), 'time' => timeformat($row['poster_time']), 'poster' => array('id' => $row['id_member'], 'name' => $row['poster_name'], 'link' => $row['id_member'] ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['poster_name'] . '</a>' : $row['poster_name'], 'href' => $scripturl . '?action=profile;u=' . $row['id_member']), 'message' => array('id' => $row['id_msg'], 'subject' => $row['subject'], 'body' => parse_bbc($row['body']), 'time' => timeformat($row['poster_time']), 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg']), 'topic' => array('id' => $row['id_topic']), 'board' => array('id' => $row['id_board'], 'name' => $row['board_name']), 'category' => array('id' => $row['id_cat'], 'name' => $row['cat_name'])); } mysql_free_result($request); EoS_Smarty::loadTemplate('modcenter/modcenter_base'); EoS_Smarty::getConfigInstance()->registerHookTemplate('modcenter_content_area', 'modcenter/unapproved_attachments'); // The ever popular approve button, with the massively unpopular delete. $context['approve_button'] = create_button('approve', 'approve'); $context['remove_button'] = create_button('remove_message', 'remove'); }
function showPermissions($memID) { global $txt, $board; global $user_profile, $context, $sourcedir, $backend_subdir; // Verify if the user has sufficient permissions. isAllowedTo('manage_permissions'); loadLanguage('ManagePermissions'); loadLanguage('Admin'); //loadAdminTemplate('ManageMembers'); EoS_Smarty::loadTemplate('profile/profile_base'); EoS_Smarty::getConfigInstance()->registerHookTemplate('profile_content_area', 'profile/permissions'); // Load all the permission profiles. require_once $sourcedir . '/' . $backend_subdir . '/ManagePermissions.php'; loadPermissionProfiles(); $context['member']['id'] = $memID; $context['member']['name'] = $user_profile[$memID]['real_name']; $context['page_title'] = $txt['showPermissions']; $board = empty($board) ? 0 : (int) $board; $context['board'] = $board; // Determine which groups this user is in. if (empty($user_profile[$memID]['additional_groups'])) { $curGroups = array(); } else { $curGroups = explode(',', $user_profile[$memID]['additional_groups']); } $curGroups[] = $user_profile[$memID]['id_group']; $curGroups[] = $user_profile[$memID]['id_post_group']; // Load a list of boards for the jump box - except the defaults. $request = smf_db_query(' SELECT b.id_board, b.name, b.id_profile, b.member_groups, IFNULL(mods.id_member, 0) AS is_mod FROM {db_prefix}boards AS b LEFT JOIN {db_prefix}moderators AS mods ON (mods.id_board = b.id_board AND mods.id_member = {int:current_member}) WHERE {query_see_board}', array('current_member' => $memID)); $context['boards'] = array(); $context['no_access_boards'] = array(); while ($row = mysql_fetch_assoc($request)) { if (count(array_intersect($curGroups, explode(',', $row['member_groups']))) === 0 && !$row['is_mod']) { $context['no_access_boards'][] = array('id' => $row['id_board'], 'name' => $row['name'], 'is_last' => false); } elseif ($row['id_profile'] != 1 || $row['is_mod']) { $context['boards'][$row['id_board']] = array('id' => $row['id_board'], 'name' => $row['name'], 'selected' => $board == $row['id_board'], 'profile' => $row['id_profile'], 'profile_name' => $context['profiles'][$row['id_profile']]['name']); } } mysql_free_result($request); if (!empty($context['no_access_boards'])) { $context['no_access_boards'][count($context['no_access_boards']) - 1]['is_last'] = true; } $context['member']['permissions'] = array('general' => array(), 'board' => array()); // If you're an admin we know you can do everything, we might as well leave. $context['member']['has_all_permissions'] = in_array(1, $curGroups); if ($context['member']['has_all_permissions']) { return; } $denied = array(); // Get all general permissions. $result = smf_db_query(' SELECT p.permission, p.add_deny, mg.group_name, p.id_group FROM {db_prefix}permissions AS p LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = p.id_group) WHERE p.id_group IN ({array_int:group_list}) ORDER BY p.add_deny DESC, p.permission, mg.min_posts, CASE WHEN mg.id_group < {int:newbie_group} THEN mg.id_group ELSE 4 END, mg.group_name', array('group_list' => $curGroups, 'newbie_group' => 4)); while ($row = mysql_fetch_assoc($result)) { // We don't know about this permission, it doesn't exist :P. if (!isset($txt['permissionname_' . $row['permission']])) { continue; } if (empty($row['add_deny'])) { $denied[] = $row['permission']; } // Permissions that end with _own or _any consist of two parts. if (in_array(substr($row['permission'], -4), array('_own', '_any')) && isset($txt['permissionname_' . substr($row['permission'], 0, -4)])) { $name = $txt['permissionname_' . substr($row['permission'], 0, -4)] . ' - ' . $txt['permissionname_' . $row['permission']]; } else { $name = $txt['permissionname_' . $row['permission']]; } // Add this permission if it doesn't exist yet. if (!isset($context['member']['permissions']['general'][$row['permission']])) { $context['member']['permissions']['general'][$row['permission']] = array('id' => $row['permission'], 'groups' => array('allowed' => array(), 'denied' => array()), 'name' => $name, 'is_denied' => false, 'is_global' => true); } // Add the membergroup to either the denied or the allowed groups. $context['member']['permissions']['general'][$row['permission']]['groups'][empty($row['add_deny']) ? 'denied' : 'allowed'][] = $row['id_group'] == 0 ? $txt['membergroups_members'] : $row['group_name']; // Once denied is always denied. $context['member']['permissions']['general'][$row['permission']]['is_denied'] |= empty($row['add_deny']); } mysql_free_result($result); $request = smf_db_query(' SELECT bp.add_deny, bp.permission, bp.id_group, mg.group_name' . (empty($board) ? '' : ', b.id_profile, CASE WHEN mods.id_member IS NULL THEN 0 ELSE 1 END AS is_moderator') . ' FROM {db_prefix}board_permissions AS bp' . (empty($board) ? '' : ' INNER JOIN {db_prefix}boards AS b ON (b.id_board = {int:current_board}) LEFT JOIN {db_prefix}moderators AS mods ON (mods.id_board = b.id_board AND mods.id_member = {int:current_member})') . ' LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = bp.id_group) WHERE bp.id_profile = {raw:current_profile} AND bp.id_group IN ({array_int:group_list}' . (empty($board) ? ')' : ', {int:moderator_group}) AND (mods.id_member IS NOT NULL OR bp.id_group != {int:moderator_group})'), array('current_board' => $board, 'group_list' => $curGroups, 'current_member' => $memID, 'current_profile' => empty($board) ? '1' : 'b.id_profile', 'moderator_group' => 3)); while ($row = mysql_fetch_assoc($request)) { // We don't know about this permission, it doesn't exist :P. if (!isset($txt['permissionname_' . $row['permission']])) { continue; } // The name of the permission using the format 'permission name' - 'own/any topic/event/etc.'. if (in_array(substr($row['permission'], -4), array('_own', '_any')) && isset($txt['permissionname_' . substr($row['permission'], 0, -4)])) { $name = $txt['permissionname_' . substr($row['permission'], 0, -4)] . ' - ' . $txt['permissionname_' . $row['permission']]; } else { $name = $txt['permissionname_' . $row['permission']]; } // Create the structure for this permission. if (!isset($context['member']['permissions']['board'][$row['permission']])) { $context['member']['permissions']['board'][$row['permission']] = array('id' => $row['permission'], 'groups' => array('allowed' => array(), 'denied' => array()), 'name' => $name, 'is_denied' => false, 'is_global' => empty($board)); } $context['member']['permissions']['board'][$row['permission']]['groups'][empty($row['add_deny']) ? 'denied' : 'allowed'][$row['id_group']] = $row['id_group'] == 0 ? $txt['membergroups_members'] : $row['group_name']; $context['member']['permissions']['board'][$row['permission']]['is_denied'] |= empty($row['add_deny']); } mysql_free_result($request); }
function EditPoll() { global $txt, $user_info, $context, $topic, $board, $smcFunc, $sourcedir, $scripturl; if (empty($topic)) { fatal_lang_error('no_access', false); } loadLanguage('Post'); EoS_Smarty::loadTemplate('topic/poll'); $context['can_moderate_poll'] = isset($_REQUEST['add']) ? 1 : allowedTo('moderate_board'); $context['start'] = (int) $_REQUEST['start']; $context['is_edit'] = isset($_REQUEST['add']) ? 0 : 1; // Check if a poll currently exists on this topic, and get the id, question and starter. $request = smf_db_query(' SELECT t.id_member_started, p.id_poll, p.question, p.hide_results, p.expire_time, p.max_votes, p.change_vote, m.subject, p.guest_vote, p.id_member AS poll_starter FROM {db_prefix}topics AS t INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg) LEFT JOIN {db_prefix}polls AS p ON (p.id_poll = t.id_poll) WHERE t.id_topic = {int:current_topic} LIMIT 1', array('current_topic' => $topic)); // Assume the the topic exists, right? if (mysql_num_rows($request) == 0) { fatal_lang_error('no_board'); } // Get the poll information. $pollinfo = mysql_fetch_assoc($request); mysql_free_result($request); // If we are adding a new poll - make sure that there isn't already a poll there. if (!$context['is_edit'] && !empty($pollinfo['id_poll'])) { fatal_lang_error('poll_already_exists'); } elseif ($context['is_edit'] && empty($pollinfo['id_poll'])) { fatal_lang_error('poll_not_found'); } // Can you do this? if ($context['is_edit'] && !allowedTo('poll_edit_any')) { isAllowedTo('poll_edit_' . ($user_info['id'] == $pollinfo['id_member_started'] || $pollinfo['poll_starter'] != 0 && $user_info['id'] == $pollinfo['poll_starter'] ? 'own' : 'any')); } elseif (!$context['is_edit'] && !allowedTo('poll_add_any')) { isAllowedTo('poll_add_' . ($user_info['id'] == $pollinfo['id_member_started'] ? 'own' : 'any')); } // Do we enable guest voting? require_once $sourcedir . '/lib/Subs-Members.php'; $groupsAllowedVote = groupsAllowedTo('poll_vote', $board); // Want to make sure before you actually submit? Must be a lot of options, or something. if (isset($_POST['preview'])) { $question = commonAPI::htmlspecialchars($_POST['question']); // Basic theme info... $context['poll'] = array('id' => $pollinfo['id_poll'], 'question' => $question, 'hide_results' => empty($_POST['poll_hide']) ? 0 : $_POST['poll_hide'], 'change_vote' => isset($_POST['poll_change_vote']), 'guest_vote' => isset($_POST['poll_guest_vote']), 'guest_vote_allowed' => in_array(-1, $groupsAllowedVote['allowed']), 'max_votes' => empty($_POST['poll_max_votes']) ? '1' : max(1, $_POST['poll_max_votes'])); // Start at number one with no last id to speak of. $number = 1; $last_id = 0; // Get all the choices - if this is an edit. if ($context['is_edit']) { $request = smf_db_query(' SELECT label, votes, id_choice FROM {db_prefix}poll_choices WHERE id_poll = {int:id_poll}', array('id_poll' => $pollinfo['id_poll'])); $context['choices'] = array(); while ($row = mysql_fetch_assoc($request)) { // Get the highest id so we can add more without reusing. if ($row['id_choice'] >= $last_id) { $last_id = $row['id_choice'] + 1; } // They cleared this by either omitting it or emptying it. if (!isset($_POST['options'][$row['id_choice']]) || $_POST['options'][$row['id_choice']] == '') { continue; } censorText($row['label']); // Add the choice! $context['choices'][$row['id_choice']] = array('id' => $row['id_choice'], 'number' => $number++, 'votes' => $row['votes'], 'label' => $row['label'], 'is_last' => false); } mysql_free_result($request); } // Work out how many options we have, so we get the 'is_last' field right... $totalPostOptions = 0; foreach ($_POST['options'] as $id => $label) { if ($label != '') { $totalPostOptions++; } } $count = 1; // If an option exists, update it. If it is new, add it - but don't reuse ids! foreach ($_POST['options'] as $id => $label) { $label = commonAPI::htmlspecialchars($label); censorText($label); if (isset($context['choices'][$id])) { $context['choices'][$id]['label'] = $label; } elseif ($label != '') { $context['choices'][] = array('id' => $last_id++, 'number' => $number++, 'label' => $label, 'votes' => -1, 'is_last' => $count++ == $totalPostOptions && $totalPostOptions > 1 ? true : false); } } // Make sure we have two choices for sure! if ($totalPostOptions < 2) { // Need two? if ($totalPostOptions == 0) { $context['choices'][] = array('id' => $last_id++, 'number' => $number++, 'label' => '', 'votes' => -1, 'is_last' => false); } $poll_errors[] = 'poll_few'; } // Always show one extra box... $context['choices'][] = array('id' => $last_id++, 'number' => $number++, 'label' => '', 'votes' => -1, 'is_last' => true); if ($context['can_moderate_poll']) { $context['poll']['expiration'] = $_POST['poll_expire']; } // Check the question/option count for errors. if (trim($_POST['question']) == '' && empty($context['poll_error'])) { $poll_errors[] = 'no_question'; } // No check is needed, since nothing is really posted. checkSubmitOnce('free'); // Take a check for any errors... assuming we haven't already done so! if (!empty($poll_errors) && empty($context['poll_error'])) { loadLanguage('Errors'); $context['poll_error'] = array('messages' => array()); foreach ($poll_errors as $poll_error) { $context['poll_error'][$poll_error] = true; $context['poll_error']['messages'][] = $txt['error_' . $poll_error]; } } } else { // Basic theme info... $context['poll'] = array('id' => $pollinfo['id_poll'], 'question' => $pollinfo['question'], 'hide_results' => $pollinfo['hide_results'], 'max_votes' => $pollinfo['max_votes'], 'change_vote' => !empty($pollinfo['change_vote']), 'guest_vote' => !empty($pollinfo['guest_vote']), 'guest_vote_allowed' => in_array(-1, $groupsAllowedVote['allowed'])); // Poll expiration time? $context['poll']['expiration'] = empty($pollinfo['expire_time']) || !allowedTo('moderate_board') ? '' : ceil($pollinfo['expire_time'] <= time() ? -1 : ($pollinfo['expire_time'] - time()) / (3600 * 24)); // Get all the choices - if this is an edit. if ($context['is_edit']) { $request = smf_db_query(' SELECT label, votes, id_choice FROM {db_prefix}poll_choices WHERE id_poll = {int:id_poll}', array('id_poll' => $pollinfo['id_poll'])); $context['choices'] = array(); $number = 1; while ($row = mysql_fetch_assoc($request)) { censorText($row['label']); $context['choices'][$row['id_choice']] = array('id' => $row['id_choice'], 'number' => $number++, 'votes' => $row['votes'], 'label' => $row['label'], 'is_last' => false); } mysql_free_result($request); $last_id = max(array_keys($context['choices'])) + 1; // Add an extra choice... $context['choices'][] = array('id' => $last_id, 'number' => $number, 'votes' => -1, 'label' => '', 'is_last' => true); } else { // Setup the default poll options. $context['poll'] = array('id' => 0, 'question' => '', 'hide_results' => 0, 'max_votes' => 1, 'change_vote' => 0, 'guest_vote' => 0, 'guest_vote_allowed' => in_array(-1, $groupsAllowedVote['allowed']), 'expiration' => ''); // Make all five poll choices empty. $context['choices'] = array(array('id' => 0, 'number' => 1, 'votes' => -1, 'label' => '', 'is_last' => false), array('id' => 1, 'number' => 2, 'votes' => -1, 'label' => '', 'is_last' => false), array('id' => 2, 'number' => 3, 'votes' => -1, 'label' => '', 'is_last' => false), array('id' => 3, 'number' => 4, 'votes' => -1, 'label' => '', 'is_last' => false), array('id' => 4, 'number' => 5, 'votes' => -1, 'label' => '', 'is_last' => true)); } } $context['page_title'] = $context['is_edit'] ? $txt['poll_edit'] : $txt['add_poll']; // Build the link tree. censorText($pollinfo['subject']); $context['linktree'][] = array('url' => $scripturl . '?topic=' . $topic . '.0', 'name' => $pollinfo['subject']); $context['linktree'][] = array('name' => $context['page_title']); $context['poll_script'] = ' <script type="text/javascript"><!-- // --><![CDATA[ var pollOptionNum = 0; function addPollOption() { if (pollOptionNum == 0) { for (var i = 0; i < document.forms.postmodify.elements.length; i++) if (document.forms.postmodify.elements[i].id.substr(0, 8) == "options-") pollOptionNum++; } pollOptionNum++ setOuterHTML(document.getElementById("pollMoreOptions"), \'<li><label for="options-\' + pollOptionNum + \'" ' . (isset($context['poll_error']['no_question']) ? ' class="error"' : '') . '>' . $txt['option'] . ' \' + pollOptionNum + \'</label>: <input type="text" name="options[\' + (pollOptionNum - 1) + \']" id="options-\' + (pollOptionNum - 1) + \'" value="" size="80" maxlength="255" class="input_text" /></li><li id="pollMoreOptions"></li\'); } // ]]></script>'; // Register this form in the session variables. checkSubmitOnce('register'); }
function ViewModlog() { global $txt, $modSettings, $context, $scripturl, $sourcedir, $user_info, $smcFunc, $settings; // Are we looking at the moderation log or the administration log. $context['log_type'] = isset($_REQUEST['sa']) && $_REQUEST['sa'] == 'adminlog' ? 3 : 1; if ($context['log_type'] == 3) { isAllowedTo('admin_forum'); } // These change dependant on whether we are viewing the moderation or admin log. if ($context['log_type'] == 3 || $_REQUEST['action'] == 'admin') { $context['url_start'] = '?action=admin;area=logs;sa=' . ($context['log_type'] == 3 ? 'adminlog' : 'modlog') . ';type=' . $context['log_type']; } else { $context['url_start'] = '?action=moderate;area=modlog;type=' . $context['log_type']; } $context['can_delete'] = allowedTo('admin_forum'); loadLanguage('Modlog'); $context['page_title'] = $context['log_type'] == 3 ? $txt['modlog_admin_log'] : $txt['modlog_view']; // The number of entries to show per page of log file. $context['displaypage'] = 30; // Amount of hours that must pass before allowed to delete file. $context['hoursdisable'] = 24; // Handle deletion... if (isset($_POST['removeall']) && $context['can_delete']) { checkSession(); smf_db_query(' DELETE FROM {db_prefix}log_actions WHERE id_log = {int:moderate_log} AND log_time < {int:twenty_four_hours_wait}', array('twenty_four_hours_wait' => time() - $context['hoursdisable'] * 3600, 'moderate_log' => $context['log_type'])); } elseif (!empty($_POST['remove']) && isset($_POST['delete']) && $context['can_delete']) { checkSession(); smf_db_query(' DELETE FROM {db_prefix}log_actions WHERE id_log = {int:moderate_log} AND id_action IN ({array_string:delete_actions}) AND log_time < {int:twenty_four_hours_wait}', array('twenty_four_hours_wait' => time() - $context['hoursdisable'] * 3600, 'delete_actions' => array_unique($_POST['delete']), 'moderate_log' => $context['log_type'])); } // Do the column stuff! $sort_types = array('action' => 'lm.action', 'time' => 'lm.log_time', 'member' => 'mem.real_name', 'group' => 'mg.group_name', 'ip' => 'lm.ip'); // Setup the direction stuff... $context['order'] = isset($_REQUEST['sort']) && isset($sort_types[$_REQUEST['sort']]) ? $_REQUEST['sort'] : 'time'; // If we're coming from a search, get the variables. if (!empty($_REQUEST['params']) && empty($_REQUEST['is_search'])) { $search_params = base64_decode(strtr($_REQUEST['params'], array(' ' => '+'))); $search_params = @unserialize($search_params); } // This array houses all the valid search types. $searchTypes = array('action' => array('sql' => 'lm.action', 'label' => $txt['modlog_action']), 'member' => array('sql' => 'mem.real_name', 'label' => $txt['modlog_member']), 'group' => array('sql' => 'mg.group_name', 'label' => $txt['modlog_position']), 'ip' => array('sql' => 'lm.ip', 'label' => $txt['modlog_ip'])); if (!isset($search_params['string']) || !empty($_REQUEST['search']) && $search_params['string'] != $_REQUEST['search']) { $search_params_string = empty($_REQUEST['search']) ? '' : $_REQUEST['search']; } else { $search_params_string = $search_params['string']; } if (isset($_REQUEST['search_type']) || empty($search_params['type']) || !isset($searchTypes[$search_params['type']])) { $search_params_type = isset($_REQUEST['search_type']) && isset($searchTypes[$_REQUEST['search_type']]) ? $_REQUEST['search_type'] : (isset($searchTypes[$context['order']]) ? $context['order'] : 'member'); } else { $search_params_type = $search_params['type']; } $search_params_column = $searchTypes[$search_params_type]['sql']; $search_params = array('string' => $search_params_string, 'type' => $search_params_type); // Setup the search context. $context['search_params'] = empty($search_params['string']) ? '' : base64_encode(serialize($search_params)); $context['search'] = array('string' => htmlspecialchars($search_params['string']), 'type' => $search_params['type'], 'label' => $searchTypes[$search_params_type]['label']); // If they are searching by action, then we must do some manual intervention to search in their language! if ($search_params['type'] == 'action' && !empty($search_params['string'])) { // For the moment they can only search for ONE action! foreach ($txt as $key => $text) { if (substr($key, 0, 10) == 'modlog_ac_' && strpos($text, $search_params['string']) !== false) { $search_params['string'] = substr($key, 10); break; } } } require_once $sourcedir . '/lib/Subs-List.php'; // This is all the information required for a watched user listing. $listOptions = array('id' => 'moderation_log_list', 'title' => '<a href="' . $scripturl . '?action=helpadmin;help=' . ($context['log_type'] == 3 ? 'adminlog' : 'modlog') . '" onclick="return reqWin(this.href);" class="help"><strong>[' . $txt['help'] . '] </strong></a> ' . $txt['modlog_' . ($context['log_type'] == 3 ? 'admin' : 'moderation') . '_log'], 'width' => '100%', 'items_per_page' => $context['displaypage'], 'no_items_label' => $txt['modlog_' . ($context['log_type'] == 3 ? 'admin_log_' : '') . 'no_entries_found'], 'base_href' => $scripturl . $context['url_start'] . (!empty($context['search_params']) ? ';params=' . $context['search_params'] : ''), 'default_sort_col' => 'time', 'get_items' => array('function' => 'list_getModLogEntries', 'params' => array(!empty($search_params['string']) ? ' INSTR({raw:sql_type}, {string:search_string})' : '', array('sql_type' => $search_params_column, 'search_string' => $search_params['string']), $context['log_type'])), 'get_count' => array('function' => 'list_getModLogEntryCount', 'params' => array(!empty($search_params['string']) ? ' INSTR({raw:sql_type}, {string:search_string})' : '', array('sql_type' => $search_params_column, 'search_string' => $search_params['string']), $context['log_type'])), 'columns' => array('action' => array('header' => array('value' => $txt['modlog_action'], 'class' => 'lefttext first_th'), 'data' => array('db' => 'action_text', 'class' => 'smalltext'), 'sort' => array('default' => 'lm.action', 'reverse' => 'lm.action DESC')), 'time' => array('header' => array('value' => $txt['modlog_date'], 'class' => 'lefttext'), 'data' => array('db' => 'time', 'class' => 'smalltext'), 'sort' => array('default' => 'lm.log_time DESC', 'reverse' => 'lm.log_time')), 'moderator' => array('header' => array('value' => $txt['modlog_member'], 'class' => 'lefttext'), 'data' => array('db' => 'moderator_link', 'class' => 'smalltext'), 'sort' => array('default' => 'mem.real_name', 'reverse' => 'mem.real_name DESC')), 'position' => array('header' => array('value' => $txt['modlog_position'], 'class' => 'lefttext'), 'data' => array('db' => 'position', 'class' => 'smalltext'), 'sort' => array('default' => 'mg.group_name', 'reverse' => 'mg.group_name DESC')), 'ip' => array('header' => array('value' => $txt['modlog_ip'], 'class' => 'lefttext'), 'data' => array('db' => 'ip', 'class' => 'smalltext'), 'sort' => array('default' => 'lm.ip', 'reverse' => 'lm.ip DESC')), 'delete' => array('header' => array('value' => '<input type="checkbox" name="all" class="input_check" onclick="invertAll(this, this.form);" />'), 'data' => array('function' => create_function('$entry', ' return \'<input type="checkbox" class="input_check" name="delete[]" value="\' . $entry[\'id\'] . \'"\' . ($entry[\'editable\'] ? \'\' : \' disabled="disabled"\') . \' />\'; '), 'style' => 'text-align: center;'))), 'form' => array('href' => $scripturl . $context['url_start'], 'include_sort' => true, 'include_start' => true, 'hidden_fields' => array($context['session_var'] => $context['session_id'], 'params' => $context['search_params'])), 'additional_rows' => array(array('position' => 'after_title', 'value' => $txt['modlog_' . ($context['log_type'] == 3 ? 'admin' : 'moderation') . '_log_desc'], 'class' => 'smalltext', 'style' => 'padding: 2ex;'), array('position' => 'below_table_data', 'value' => ' ' . $txt['modlog_search'] . ' (' . $txt['modlog_by'] . ': ' . $context['search']['label'] . '): <input type="text" name="search" size="18" value="' . $context['search']['string'] . '" class="input_text" /> <input type="submit" name="is_search" value="' . $txt['modlog_go'] . '" class="button_submit" /> ' . ($context['can_delete'] ? ' | <input type="submit" name="remove" value="' . $txt['modlog_remove'] . '" class="button_submit" /> <input type="submit" name="removeall" value="' . $txt['modlog_removeall'] . '" class="button_submit" />' : '')))); EoS_Smarty::loadTemplate('modcenter/modcenter_base'); EoS_Smarty::getConfigInstance()->registerHookTemplate('modcenter_content_area', 'modcenter/modlog'); // Create the watched user list. createList($listOptions); //$context['sub_template'] = 'show_list'; $context['default_list'] = 'moderation_log_list'; }
function BoardIndex() { global $txt, $user_info, $sourcedir, $modSettings, $context, $settings, $scripturl, $boardurl, $boarddir; EoS_Smarty::loadTemplate('boardindex'); $context['is_board_index'] = true; $context['sidebar_template'] = 'sidebars/sidebar_on_index.tpl'; $context['show_sidebar'] = true; $context['sidebar_class'] = 'index'; GetSidebarVisibility('index'); // Set a canonical URL for this page. $context['canonical_url'] = $scripturl; $context['share_url'] = $boardurl; // Do not let search engines index anything if there is a random thing in $_GET. if (!empty($_GET)) { $context['robot_no_index'] = true; } // Retrieve the categories and boards. require_once $sourcedir . '/lib/Subs-BoardIndex.php'; $boardIndexOptions = array('include_categories' => true, 'base_level' => 0, 'parent_id' => 0, 'set_latest_post' => true, 'countChildPosts' => !empty($modSettings['countChildPosts'])); $context['categories'] = getBoardIndex($boardIndexOptions); // Get the user online list. require_once $sourcedir . '/lib/Subs-MembersOnline.php'; $membersOnlineOptions = array('show_hidden' => allowedTo('moderate_forum'), 'sort' => 'log_time', 'reverse_sort' => true); $context += getMembersOnlineStats($membersOnlineOptions); $context['show_buddies'] = !empty($user_info['buddies']); // Are we showing all membergroups on the board index? if (!empty($settings['show_group_key'])) { $context['membergroups'] = cache_quick_get('membergroup_list', 'lib/Subs-Membergroups.php', 'cache_getMembergroupList', array()); } // Track most online statistics? (Subs-MembersOnline.php) if (!empty($modSettings['trackStats'])) { trackStatsUsersOnline($context['num_guests'] + $context['num_spiders'] + $context['num_users_online']); } // Retrieve the latest posts if the theme settings require it. if (isset($settings['number_recent_posts']) && $settings['number_recent_posts'] > 1) { $latestPostOptions = array('number_posts' => $settings['number_recent_posts']); $context['latest_posts'] = cache_quick_get('boardindex-latest_posts:' . md5($user_info['query_wanna_see_board'] . $user_info['language']), 'lib/Subs-Recent.php', 'cache_getLastPosts', array($latestPostOptions)); } $settings['display_recent_bar'] = !empty($settings['number_recent_posts']) ? $settings['number_recent_posts'] : 0; $settings['show_member_bar'] &= allowedTo('view_mlist'); $context['show_stats'] = allowedTo('view_stats') && !empty($modSettings['trackStats']); $context['show_member_list'] = allowedTo('view_mlist'); $context['show_who'] = allowedTo('who_view') && !empty($modSettings['who_enabled']); // Load the calendar? if (!empty($modSettings['cal_enabled']) && allowedTo('calendar_view')) { // Retrieve the calendar data (events, birthdays, holidays). $eventOptions = array('include_holidays' => $modSettings['cal_showholidays'] > 1, 'include_birthdays' => $modSettings['cal_showbdays'] > 1, 'include_events' => $modSettings['cal_showevents'] > 1, 'num_days_shown' => empty($modSettings['cal_days_for_index']) || $modSettings['cal_days_for_index'] < 1 ? 1 : $modSettings['cal_days_for_index']); $context += cache_quick_get('calendar_index_offset_' . ($user_info['time_offset'] + $modSettings['time_offset']), 'lib/Subs-Calendar.php', 'cache_getRecentEvents', array($eventOptions)); // Whether one or multiple days are shown on the board index. $context['calendar_only_today'] = $modSettings['cal_days_for_index'] == 1; // This is used to show the "how-do-I-edit" help. $context['calendar_can_edit'] = allowedTo('calendar_edit_any'); } else { $context['show_calendar'] = false; } $context['page_title'] = sprintf($txt['forum_index'], $context['forum_name']); $context['template_hooks']['boardindex'] = array('above_boardlisting' => '', 'below_boardlisting' => ''); if (isset($context['show_who'])) { $bracketList = array(); if ($context['show_buddies']) { $bracketList[] = comma_format($context['num_buddies']) . ' ' . ($context['num_buddies'] == 1 ? $txt['buddy'] : $txt['buddies']); } if (!empty($context['num_spiders'])) { $bracketList[] = comma_format($context['num_spiders']) . ' ' . ($context['num_spiders'] == 1 ? $txt['spider'] : $txt['spiders']); } if (!empty($context['num_users_hidden'])) { $bracketList[] = comma_format($context['num_users_hidden']) . ' ' . $txt['hidden']; } if (!empty($bracketList)) { $context['show_who_formatted'] = ' (' . implode(', ', $bracketList) . ')'; } } $context['mark_read_button'] = array('markread' => array('text' => 'mark_as_read', 'image' => 'markread.gif', 'lang' => true, 'url' => $scripturl . '?action=markasread;sa=all;' . $context['session_var'] . '=' . $context['session_id'])); HookAPI::callHook('boardindex', array()); fetchNewsItems(0, 0); }
function adminLogin() { global $context, $scripturl, $txt, $user_info, $user_settings; loadLanguage('Admin'); EoS_Smarty::loadTemplate('generic_skeleton'); EoS_Smarty::getConfigInstance()->registerHookTemplate('generic_content_area', 'loginout/adminlogin'); // They used a wrong password, log it and unset that. if (isset($_POST['admin_hash_pass']) || isset($_POST['admin_pass'])) { $txt['security_wrong'] = sprintf($txt['security_wrong'], isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $txt['unknown'], $_SERVER['HTTP_USER_AGENT'], $user_info['ip']); log_error($txt['security_wrong'], 'critical'); if (isset($_POST['admin_hash_pass'])) { unset($_POST['admin_hash_pass']); } if (isset($_POST['admin_pass'])) { unset($_POST['admin_pass']); } $context['incorrect_password'] = true; } // Figure out the get data and post data. $context['get_data'] = '?' . construct_query_string($_GET); $context['post_data'] = ''; // Now go through $_POST. Make sure the session hash is sent. $_POST[$context['session_var']] = $context['session_id']; foreach ($_POST as $k => $v) { $context['post_data'] .= adminLogin_outputPostVars($k, $v); } // And title the page something like "Login". if (!isset($context['page_title'])) { $context['page_title'] = $txt['login']; } obExit(); // We MUST exit at this point, because otherwise we CANNOT KNOW that the user is privileged. trigger_error('Hacking attempt...', E_USER_ERROR); }
function PlushSearch2() { global $scripturl, $modSettings, $sourcedir, $txt; global $user_info, $context, $options, $messages_request, $boards_can; global $excludedWords, $participants, $search_versions, $searchAPI; if (!empty($context['load_average']) && !empty($modSettings['loadavg_search']) && $context['load_average'] >= $modSettings['loadavg_search']) { fatal_lang_error('loadavg_search_disabled', false); } $_ctx = new SearchContext(); // No, no, no... this is a bit hard on the server, so don't you go prefetching it! if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') { ob_end_clean(); header('HTTP/1.1 403 Forbidden'); die; } $weight_factors = array('frequency', 'age', 'length', 'subject', 'first_message', 'sticky'); $weight = array(); $weight_total = 0; foreach ($weight_factors as $weight_factor) { $weight[$weight_factor] = empty($modSettings['search_weight_' . $weight_factor]) ? 0 : (int) $modSettings['search_weight_' . $weight_factor]; $weight_total += $weight[$weight_factor]; } // Zero weight. Weightless :P. if (empty($weight_total)) { fatal_lang_error('search_invalid_weights'); } // These vars don't require an interface, they're just here for tweaking. $recentPercentage = 0.3; $humungousTopicPosts = 200; $maxMembersToSearch = 500; $maxMessageResults = empty($modSettings['search_max_results']) ? 0 : $modSettings['search_max_results'] * 5; // Start with no errors. $context['search_errors'] = array(); // Number of pages hard maximum - normally not set at all. $modSettings['search_max_results'] = empty($modSettings['search_max_results']) ? 200 * $modSettings['search_results_per_page'] : (int) $modSettings['search_max_results']; // Maximum length of the string. $context['search_string_limit'] = 100; loadLanguage('Search'); // Are you allowed? isAllowedTo('search_posts'); require_once $sourcedir . '/Display.php'; require_once $sourcedir . '/lib/Subs-Package.php'; // Search has a special database set. db_extend('search'); // Load up the search API we are going to use. $modSettings['search_index'] = empty($modSettings['search_index']) ? 'standard' : $modSettings['search_index']; if (!file_exists($sourcedir . '/SearchAPI-' . ucwords($modSettings['search_index']) . '.php')) { fatal_lang_error('search_api_missing'); } loadClassFile('SearchAPI-' . ucwords($modSettings['search_index']) . '.php'); // Create an instance of the search API and check it is valid for this version of SMF. $search_class_name = $modSettings['search_index'] . '_search'; $searchAPI = new $search_class_name(); if (!$searchAPI || $searchAPI->supportsMethod('isValid') && !$searchAPI->isValid() || !matchPackageVersion($search_versions['forum_version'], $searchAPI->min_smf_version . '-' . $searchAPI->version_compatible)) { // Log the error. loadLanguage('Errors'); log_error(sprintf($txt['search_api_not_compatible'], 'SearchAPI-' . ucwords($modSettings['search_index']) . '.php'), 'critical'); loadClassFile('SearchAPI-Standard.php'); $searchAPI = new standard_search(); } // $search_params will carry all settings that differ from the default search parameters. // That way, the URLs involved in a search page will be kept as short as possible. $search_params = array(); if (isset($_REQUEST['params'])) { // Due to IE's 2083 character limit, we have to compress long search strings $temp_params = base64_decode(str_replace(array('-', '_', '.'), array('+', '/', '='), $_REQUEST['params'])); // Test for gzuncompress failing $temp_params2 = @gzuncompress($temp_params); $temp_params = explode('|"|', !empty($temp_params2) ? $temp_params2 : $temp_params); foreach ($temp_params as $i => $data) { @(list($k, $v) = explode('|\'|', $data)); $search_params[$k] = $v; } if (isset($search_params['brd'])) { $search_params['brd'] = empty($search_params['brd']) ? array() : explode(',', $search_params['brd']); } } // Store whether simple search was used (needed if the user wants to do another query). if (!isset($search_params['advanced'])) { $search_params['advanced'] = empty($_REQUEST['advanced']) ? 0 : 1; } // 1 => 'allwords' (default, don't set as param) / 2 => 'anywords'. if (!empty($search_params['searchtype']) || !empty($_REQUEST['searchtype']) && $_REQUEST['searchtype'] == 2) { $search_params['searchtype'] = 2; } // Minimum age of messages. Default to zero (don't set param in that case). if (!empty($search_params['minage']) || !empty($_REQUEST['minage']) && $_REQUEST['minage'] > 0) { $search_params['minage'] = !empty($search_params['minage']) ? (int) $search_params['minage'] : (int) $_REQUEST['minage']; } // Maximum age of messages. Default to infinite (9999 days: param not set). if (!empty($search_params['maxage']) || !empty($_REQUEST['maxage']) && $_REQUEST['maxage'] < 9999) { $search_params['maxage'] = !empty($search_params['maxage']) ? (int) $search_params['maxage'] : (int) $_REQUEST['maxage']; } // Searching a specific topic? if (!empty($_REQUEST['topic'])) { $search_params['topic'] = (int) $_REQUEST['topic']; $search_params['show_complete'] = true; } elseif (!empty($search_params['topic'])) { $search_params['topic'] = (int) $search_params['topic']; } if (!empty($search_params['minage']) || !empty($search_params['maxage'])) { $request = smf_db_query(' SELECT ' . (empty($search_params['maxage']) ? '0, ' : 'IFNULL(MIN(id_msg), -1), ') . (empty($search_params['minage']) ? '0' : 'IFNULL(MAX(id_msg), -1)') . ' FROM {db_prefix}messages WHERE 1=1' . ($modSettings['postmod_active'] ? ' AND approved = {int:is_approved_true}' : '') . (empty($search_params['minage']) ? '' : ' AND poster_time <= {int:timestamp_minimum_age}') . (empty($search_params['maxage']) ? '' : ' AND poster_time >= {int:timestamp_maximum_age}'), array('timestamp_minimum_age' => empty($search_params['minage']) ? 0 : time() - 86400 * $search_params['minage'], 'timestamp_maximum_age' => empty($search_params['maxage']) ? 0 : time() - 86400 * $search_params['maxage'], 'is_approved_true' => 1)); list($minMsgID, $maxMsgID) = mysql_fetch_row($request); if ($minMsgID < 0 || $maxMsgID < 0) { $context['search_errors']['no_messages_in_time_frame'] = true; } mysql_free_result($request); } // Default the user name to a wildcard matching every user (*). if (!empty($search_params['userspec']) || !empty($_REQUEST['userspec']) && $_REQUEST['userspec'] != '*') { $search_params['userspec'] = isset($search_params['userspec']) ? $search_params['userspec'] : $_REQUEST['userspec']; } // If there's no specific user, then don't mention it in the main query. if (empty($search_params['userspec'])) { $userQuery = ''; } else { $userString = strtr(commonAPI::htmlspecialchars($search_params['userspec'], ENT_QUOTES), array('"' => '"')); $userString = strtr($userString, array('%' => '\\%', '_' => '\\_', '*' => '%', '?' => '_')); preg_match_all('~"([^"]+)"~', $userString, $matches); $possible_users = array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $userString))); for ($k = 0, $n = count($possible_users); $k < $n; $k++) { $possible_users[$k] = trim($possible_users[$k]); if (strlen($possible_users[$k]) == 0) { unset($possible_users[$k]); } } // Create a list of database-escaped search names. $realNameMatches = array(); foreach ($possible_users as $possible_user) { $realNameMatches[] = smf_db_quote('{string:possible_user}', array('possible_user' => $possible_user)); } // Retrieve a list of possible members. $request = smf_db_query(' SELECT id_member FROM {db_prefix}members WHERE {raw:match_possible_users}', array('match_possible_users' => 'real_name LIKE ' . implode(' OR real_name LIKE ', $realNameMatches))); // Simply do nothing if there're too many members matching the criteria. if (mysql_num_rows($request) > $maxMembersToSearch) { $userQuery = ''; } elseif (mysql_num_rows($request) == 0) { $userQuery = smf_db_quote('m.id_member = {int:id_member_guest} AND ({raw:match_possible_guest_names})', array('id_member_guest' => 0, 'match_possible_guest_names' => 'm.poster_name LIKE ' . implode(' OR m.poster_name LIKE ', $realNameMatches))); } else { $memberlist = array(); while ($row = mysql_fetch_assoc($request)) { $memberlist[] = $row['id_member']; } $userQuery = smf_db_quote('(m.id_member IN ({array_int:matched_members}) OR (m.id_member = {int:id_member_guest} AND ({raw:match_possible_guest_names})))', array('matched_members' => $memberlist, 'id_member_guest' => 0, 'match_possible_guest_names' => 'm.poster_name LIKE ' . implode(' OR m.poster_name LIKE ', $realNameMatches))); } mysql_free_result($request); } // If the boards were passed by URL (params=), temporarily put them back in $_REQUEST. if (!empty($search_params['brd']) && is_array($search_params['brd'])) { $_REQUEST['brd'] = $search_params['brd']; } // Ensure that brd is an array. if (!empty($_REQUEST['brd']) && !is_array($_REQUEST['brd'])) { $_REQUEST['brd'] = strpos($_REQUEST['brd'], ',') !== false ? explode(',', $_REQUEST['brd']) : array($_REQUEST['brd']); } // Make sure all boards are integers. if (!empty($_REQUEST['brd'])) { foreach ($_REQUEST['brd'] as $id => $brd) { $_REQUEST['brd'][$id] = (int) $brd; } } // Special case for boards: searching just one topic? if (!empty($search_params['topic'])) { $request = smf_db_query(' SELECT b.id_board FROM {db_prefix}topics AS t INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) WHERE t.id_topic = {int:search_topic_id} AND {query_see_board}' . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved_true}' : '') . ' LIMIT 1', array('search_topic_id' => $search_params['topic'], 'is_approved_true' => 1)); if (mysql_num_rows($request) == 0) { fatal_lang_error('topic_gone', false); } $search_params['brd'] = array(); list($search_params['brd'][0]) = mysql_fetch_row($request); mysql_free_result($request); } elseif ($user_info['is_admin'] && (!empty($search_params['advanced']) || !empty($_REQUEST['brd']))) { $search_params['brd'] = empty($_REQUEST['brd']) ? array() : $_REQUEST['brd']; } else { $see_board = empty($search_params['advanced']) ? 'query_wanna_see_board' : 'query_see_board'; $request = smf_db_query(' SELECT b.id_board FROM {db_prefix}boards AS b WHERE {raw:boards_allowed_to_see} AND redirect = {string:empty_string}' . (empty($_REQUEST['brd']) ? !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? ' AND b.id_board != {int:recycle_board_id}' : '' : ' AND b.id_board IN ({array_int:selected_search_boards})'), array('boards_allowed_to_see' => $user_info[$see_board], 'empty_string' => '', 'selected_search_boards' => empty($_REQUEST['brd']) ? array() : $_REQUEST['brd'], 'recycle_board_id' => $modSettings['recycle_board'])); $search_params['brd'] = array(); while ($row = mysql_fetch_assoc($request)) { $search_params['brd'][] = $row['id_board']; } mysql_free_result($request); // This error should pro'bly only happen for hackers. if (empty($search_params['brd'])) { $context['search_errors']['no_boards_selected'] = true; } } if (count($search_params['brd']) != 0) { foreach ($search_params['brd'] as $k => $v) { $search_params['brd'][$k] = (int) $v; } // If we've selected all boards, this parameter can be left empty. $request = smf_db_query(' SELECT COUNT(*) FROM {db_prefix}boards WHERE redirect = {string:empty_string}', array('empty_string' => '')); list($num_boards) = mysql_fetch_row($request); mysql_free_result($request); if (count($search_params['brd']) == $num_boards) { $boardQuery = ''; } elseif (count($search_params['brd']) == $num_boards - 1 && !empty($modSettings['recycle_board']) && !in_array($modSettings['recycle_board'], $search_params['brd'])) { $boardQuery = '!= ' . $modSettings['recycle_board']; } else { $boardQuery = 'IN (' . implode(', ', $search_params['brd']) . ')'; } } else { $boardQuery = ''; } $search_params['show_complete'] = !empty($search_params['show_complete']) || !empty($_REQUEST['show_complete']); $search_params['subject_only'] = !empty($search_params['subject_only']) || !empty($_REQUEST['subject_only']); $context['compact'] = !$search_params['show_complete']; EoS_Smarty::loadTemplate('search/base'); if (!isset($_REQUEST['xml'])) { EoS_Smarty::getConfigInstance()->registerHookTemplate('search_content_area', $context['compact'] ? 'search/results_compact' : 'search/results_as_messages'); } else { EoS_Smarty::getConfigInstance()->registerHookTemplate('search_content_area', 'search/results_xml'); } // Get the sorting parameters right. Default to sort by relevance descending. $sort_columns = array('relevance', 'num_replies', 'id_msg'); if (empty($search_params['sort']) && !empty($_REQUEST['sort'])) { list($search_params['sort'], $search_params['sort_dir']) = array_pad(explode('|', $_REQUEST['sort']), 2, ''); } $search_params['sort'] = !empty($search_params['sort']) && in_array($search_params['sort'], $sort_columns) ? $search_params['sort'] : 'relevance'; if (!empty($search_params['topic']) && $search_params['sort'] === 'num_replies') { $search_params['sort'] = 'id_msg'; } // Sorting direction: descending unless stated otherwise. $search_params['sort_dir'] = !empty($search_params['sort_dir']) && $search_params['sort_dir'] == 'asc' ? 'asc' : 'desc'; // Determine some values needed to calculate the relevance. $minMsg = (int) ((1 - $recentPercentage) * $modSettings['maxMsgID']); $recentMsg = $modSettings['maxMsgID'] - $minMsg; // *** Parse the search query // Unfortunately, searching for words like this is going to be slow, so we're blacklisting them. // !!! Setting to add more here? // !!! Maybe only blacklist if they are the only word, or "any" is used? $blacklisted_words = array('img', 'url', 'quote', 'www', 'http', 'the', 'is', 'it', 'are', 'if'); // What are we searching for? if (empty($search_params['search'])) { if (isset($_GET['search'])) { $search_params['search'] = un_htmlspecialchars($_GET['search']); } elseif (isset($_POST['search'])) { $search_params['search'] = $_POST['search']; } else { $search_params['search'] = ''; } } // Nothing?? if (!isset($search_params['search']) || $search_params['search'] == '') { $context['search_errors']['invalid_search_string'] = true; } elseif (commonAPI::strlen($search_params['search']) > $context['search_string_limit']) { $context['search_errors']['string_too_long'] = true; $txt['error_string_too_long'] = sprintf($txt['error_string_too_long'], $context['search_string_limit']); } // Change non-word characters into spaces. $stripped_query = preg_replace('~(?:[\\x0B\\0' . ($context['server']['complex_preg_chars'] ? '\\x{A0}' : "Â ") . '\\t\\r\\s\\n(){}\\[\\]<>!@$%^*.,:+=`\\~\\?/\\\\]+|&(?:amp|lt|gt|quot);)+~u', ' ', $search_params['search']); // Make the query lower case. It's gonna be case insensitive anyway. $stripped_query = un_htmlspecialchars(commonAPI::strtolower($stripped_query)); // This (hidden) setting will do fulltext searching in the most basic way. if (!empty($modSettings['search_simple_fulltext'])) { $stripped_query = strtr($stripped_query, array('"' => '')); } $no_regexp = preg_match('~&#(?:\\d{1,7}|x[0-9a-fA-F]{1,6});~', $stripped_query) === 1; // Extract phrase parts first (e.g. some words "this is a phrase" some more words.) preg_match_all('/(?:^|\\s)([-]?)"([^"]+)"(?:$|\\s)/', $stripped_query, $matches, PREG_PATTERN_ORDER); $phraseArray = $matches[2]; // Remove the phrase parts and extract the words. $wordArray = explode(' ', preg_replace('~(?:^|\\s)(?:[-]?)"(?:[^"]+)"(?:$|\\s)~u', ' ', $search_params['search'])); // A minus sign in front of a word excludes the word.... so... $excludedWords = array(); $excludedIndexWords = array(); $excludedSubjectWords = array(); $excludedPhrases = array(); // .. first, we check for things like -"some words", but not "-some words". foreach ($matches[1] as $index => $word) { if ($word === '-') { if (($word = trim($phraseArray[$index], '-_\' ')) !== '' && !in_array($word, $blacklisted_words)) { $excludedWords[] = $word; } unset($phraseArray[$index]); } } // Now we look for -test, etc.... normaller. foreach ($wordArray as $index => $word) { if (strpos(trim($word), '-') === 0) { if (($word = trim($word, '-_\' ')) !== '' && !in_array($word, $blacklisted_words)) { $excludedWords[] = $word; } unset($wordArray[$index]); } } // The remaining words and phrases are all included. $searchArray = array_merge($phraseArray, $wordArray); // Trim everything and make sure there are no words that are the same. foreach ($searchArray as $index => $value) { // Skip anything practically empty. if (($searchArray[$index] = trim($value, '-_\' ')) === '') { unset($searchArray[$index]); } elseif (in_array($searchArray[$index], $blacklisted_words)) { $foundBlackListedWords = true; unset($searchArray[$index]); } elseif (commonAPI::strlen($value) < 2) { $context['search_errors']['search_string_small_words'] = true; unset($searchArray[$index]); } else { $searchArray[$index] = $searchArray[$index]; } } $searchArray = array_slice(array_unique($searchArray), 0, 10); // Create an array of replacements for highlighting. $context['mark'] = array(); foreach ($searchArray as $word) { $context['mark'][$word] = '<strong class="highlight">' . $word . '</strong>'; } // Initialize two arrays storing the words that have to be searched for. $orParts = array(); $searchWords = array(); // Make sure at least one word is being searched for. if (empty($searchArray)) { $context['search_errors']['invalid_search_string' . (!empty($foundBlackListedWords) ? '_blacklist' : '')] = true; } elseif (empty($search_params['searchtype'])) { $orParts[0] = $searchArray; } else { foreach ($searchArray as $index => $value) { $orParts[$index] = array($value); } } // Don't allow duplicate error messages if one string is too short. if (isset($context['search_errors']['search_string_small_words'], $context['search_errors']['invalid_search_string'])) { unset($context['search_errors']['invalid_search_string']); } // Make sure the excluded words are in all or-branches. foreach ($orParts as $orIndex => $andParts) { foreach ($excludedWords as $word) { $orParts[$orIndex][] = $word; } } // Determine the or-branches and the fulltext search words. foreach ($orParts as $orIndex => $andParts) { $searchWords[$orIndex] = array('indexed_words' => array(), 'words' => array(), 'subject_words' => array(), 'all_words' => array()); // Sort the indexed words (large words -> small words -> excluded words). if ($searchAPI->supportsMethod('searchSort')) { usort($orParts[$orIndex], 'searchSort'); } foreach ($orParts[$orIndex] as $word) { $is_excluded = in_array($word, $excludedWords); $searchWords[$orIndex]['all_words'][] = $word; $subjectWords = text2words($word); if (!$is_excluded || count($subjectWords) === 1) { $searchWords[$orIndex]['subject_words'] = array_merge($searchWords[$orIndex]['subject_words'], $subjectWords); if ($is_excluded) { $excludedSubjectWords = array_merge($excludedSubjectWords, $subjectWords); } } else { $excludedPhrases[] = $word; } // Have we got indexes to prepare? if ($searchAPI->supportsMethod('prepareIndexes')) { $searchAPI->prepareIndexes($word, $searchWords[$orIndex], $excludedIndexWords, $is_excluded); } } // Search_force_index requires all AND parts to have at least one fulltext word. if (!empty($modSettings['search_force_index']) && empty($searchWords[$orIndex]['indexed_words'])) { $context['search_errors']['query_not_specific_enough'] = true; break; } elseif ($search_params['subject_only'] && empty($searchWords[$orIndex]['subject_words']) && empty($excludedSubjectWords)) { $context['search_errors']['query_not_specific_enough'] = true; break; } else { $searchWords[$orIndex]['indexed_words'] = array_slice($searchWords[$orIndex]['indexed_words'], 0, 7); $searchWords[$orIndex]['subject_words'] = array_slice($searchWords[$orIndex]['subject_words'], 0, 7); } } // Let the user adjust the search query, should they wish? $context['search_params'] = $search_params; if (isset($context['search_params']['search'])) { $context['search_params']['search'] = commonAPI::htmlspecialchars($context['search_params']['search']); } if (isset($context['search_params']['userspec'])) { $context['search_params']['userspec'] = commonAPI::htmlspecialchars($context['search_params']['userspec']); } // Do we have captcha enabled? if ($user_info['is_guest'] && !empty($modSettings['search_enable_captcha']) && empty($_SESSION['ss_vv_passed']) && (empty($_SESSION['last_ss']) || $_SESSION['last_ss'] != $search_params['search'])) { // If we come from another search box tone down the error... if (!isset($_REQUEST['search_vv'])) { $context['search_errors']['need_verification_code'] = true; } else { require_once $sourcedir . '/lib/Subs-Editor.php'; $verificationOptions = array('id' => 'search', 'skip_template' => true); $context['require_verification'] = create_control_verification($verificationOptions, true); if (is_array($context['require_verification'])) { foreach ($context['require_verification'] as $error) { $context['search_errors'][$error] = true; } } else { $_SESSION['ss_vv_passed'] = true; } } } // *** Encode all search params // All search params have been checked, let's compile them to a single string... made less simple by PHP 4.3.9 and below. $temp_params = $search_params; if (isset($temp_params['brd'])) { $temp_params['brd'] = implode(',', $temp_params['brd']); } $context['params'] = array(); foreach ($temp_params as $k => $v) { $context['params'][] = $k . '|\'|' . $v; } if (!empty($context['params'])) { // Due to old IE's 2083 character limit, we have to compress long search strings $params = @gzcompress(implode('|"|', $context['params'])); // Gzcompress failed, use try non-gz if (empty($params)) { $params = implode('|"|', $context['params']); } // Base64 encode, then replace +/= with uri safe ones that can be reverted $context['params'] = str_replace(array('+', '/', '='), array('-', '_', '.'), base64_encode($params)); } // ... and add the links to the link tree. $context['linktree'][] = array('url' => $scripturl . '?action=search;params=' . $context['params'], 'name' => $txt['search']); $context['linktree'][] = array('url' => $scripturl . '?action=search2;params=' . $context['params'], 'name' => $txt['search_results']); // *** A last error check // One or more search errors? Go back to the first search screen. if (!empty($context['search_errors'])) { $_REQUEST['params'] = $context['params']; EoS_Smarty::resetTemplates(); return PlushSearch1(); } // Spam me not, Spam-a-lot? if (empty($_SESSION['last_ss']) || $_SESSION['last_ss'] != $search_params['search']) { spamProtection('search'); } // Store the last search string to allow pages of results to be browsed. $_SESSION['last_ss'] = $search_params['search']; // *** Reserve an ID for caching the search results. $query_params = array_merge($search_params, array('min_msg_id' => isset($minMsgID) ? (int) $minMsgID : 0, 'max_msg_id' => isset($maxMsgID) ? (int) $maxMsgID : 0, 'memberlist' => !empty($memberlist) ? $memberlist : array())); // Can this search rely on the API given the parameters? if ($searchAPI->supportsMethod('searchQuery', $query_params)) { $participants = array(); $searchArray = array(); $num_results = $searchAPI->searchQuery($query_params, $searchWords, $excludedIndexWords, $participants, $searchArray); } else { log_error('update cache'); $update_cache = empty($_SESSION['search_cache']) || $_SESSION['search_cache']['params'] != $context['params']; if ($update_cache) { // Increase the pointer... $modSettings['search_pointer'] = empty($modSettings['search_pointer']) ? 0 : (int) $modSettings['search_pointer']; // ...and store it right off. updateSettings(array('search_pointer' => $modSettings['search_pointer'] >= 255 ? 0 : $modSettings['search_pointer'] + 1)); // As long as you don't change the parameters, the cache result is yours. $_SESSION['search_cache'] = array('id_search' => $modSettings['search_pointer'], 'num_results' => -1, 'params' => $context['params']); // Clear the previous cache of the final results cache. smf_db_query(' DELETE FROM {db_prefix}log_search_results WHERE id_search = {int:search_id}', array('search_id' => $_SESSION['search_cache']['id_search'])); if ($search_params['subject_only']) { // We do this to try and avoid duplicate keys on databases not supporting INSERT IGNORE. $inserts = array(); foreach ($searchWords as $orIndex => $words) { $subject_query_params = array(); $subject_query = array('from' => '{db_prefix}topics AS t', 'inner_join' => array(), 'left_join' => array(), 'where' => array()); if ($modSettings['postmod_active']) { $subject_query['where'][] = 't.approved = {int:is_approved}'; } $numTables = 0; $prev_join = 0; $numSubjectResults = 0; foreach ($words['subject_words'] as $subjectWord) { $numTables++; if (in_array($subjectWord, $excludedSubjectWords)) { $subject_query['left_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.word ' . (empty($modSettings['search_match_words']) ? 'LIKE {string:subject_words_' . $numTables . '_wild}' : '= {string:subject_words_' . $numTables . '}') . ' AND subj' . $numTables . '.id_topic = t.id_topic)'; $subject_query['where'][] = '(subj' . $numTables . '.word IS NULL)'; } else { $subject_query['inner_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.id_topic = ' . ($prev_join === 0 ? 't' : 'subj' . $prev_join) . '.id_topic)'; $subject_query['where'][] = 'subj' . $numTables . '.word ' . (empty($modSettings['search_match_words']) ? 'LIKE {string:subject_words_' . $numTables . '_wild}' : '= {string:subject_words_' . $numTables . '}'); $prev_join = $numTables; } $subject_query_params['subject_words_' . $numTables] = $subjectWord; $subject_query_params['subject_words_' . $numTables . '_wild'] = '%' . $subjectWord . '%'; } if (!empty($userQuery)) { if ($subject_query['from'] != '{db_prefix}messages AS m') { $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_topic = t.id_topic)'; } $subject_query['where'][] = $userQuery; } if (!empty($search_params['topic'])) { $subject_query['where'][] = 't.id_topic = ' . $search_params['topic']; } if (!empty($minMsgID)) { $subject_query['where'][] = 't.id_first_msg >= ' . $minMsgID; } if (!empty($maxMsgID)) { $subject_query['where'][] = 't.id_last_msg <= ' . $maxMsgID; } if (!empty($boardQuery)) { $subject_query['where'][] = 't.id_board ' . $boardQuery; } if (!empty($excludedPhrases)) { if ($subject_query['from'] != '{db_prefix}messages AS m') { $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)'; } $count = 0; foreach ($excludedPhrases as $phrase) { $subject_query['where'][] = 'm.subject NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:excluded_phrases_' . $count . '}'; $subject_query_params['excluded_phrases_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($phrase, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $phrase), '\\\'') . '[[:>:]]'; } } $ignoreRequest = smf_db_query((1 ? ' INSERT IGNORE INTO {db_prefix}log_search_results (id_search, id_topic, relevance, id_msg, num_matches)' : '') . ' SELECT {int:id_search}, t.id_topic, 1000 * ( {int:weight_frequency} / (t.num_replies + 1) + {int:weight_age} * CASE WHEN t.id_first_msg < {int:min_msg} THEN 0 ELSE (t.id_first_msg - {int:min_msg}) / {int:recent_message} END + {int:weight_length} * CASE WHEN t.num_replies < {int:huge_topic_posts} THEN t.num_replies / {int:huge_topic_posts} ELSE 1 END + {int:weight_subject} + {int:weight_sticky} * t.is_sticky ) / {int:weight_total} AS relevance, ' . (empty($userQuery) ? 't.id_first_msg' : 'm.id_msg') . ', 1 FROM ' . $subject_query['from'] . (empty($subject_query['inner_join']) ? '' : ' INNER JOIN ' . implode(' INNER JOIN ', $subject_query['inner_join'])) . (empty($subject_query['left_join']) ? '' : ' LEFT JOIN ' . implode(' LEFT JOIN ', $subject_query['left_join'])) . ' WHERE ' . implode(' AND ', $subject_query['where']) . (empty($modSettings['search_max_results']) ? '' : ' LIMIT ' . ($modSettings['search_max_results'] - $numSubjectResults)), array_merge($subject_query_params, array('id_search' => $_SESSION['search_cache']['id_search'], 'weight_age' => $weight['age'], 'weight_frequency' => $weight['frequency'], 'weight_length' => $weight['length'], 'weight_sticky' => $weight['sticky'], 'weight_subject' => $weight['subject'], 'weight_total' => $weight_total, 'min_msg' => $minMsg, 'recent_message' => $recentMsg, 'huge_topic_posts' => $humungousTopicPosts, 'is_approved' => 1))); $numSubjectResults += smf_db_affected_rows(); if (!empty($modSettings['search_max_results']) && $numSubjectResults >= $modSettings['search_max_results']) { break; } } // If there's data to be inserted for non-IGNORE databases do it here! if (!empty($inserts)) { smf_db_insert('', '{db_prefix}log_search_results', array('id_search' => 'int', 'id_topic' => 'int', 'relevance' => 'int', 'id_msg' => 'int', 'num_matches' => 'int'), $inserts, array('id_search', 'id_topic')); } $_SESSION['search_cache']['num_results'] = $numSubjectResults; } else { $main_query = array('select' => array('id_search' => $_SESSION['search_cache']['id_search'], 'relevance' => '0'), 'weights' => array(), 'from' => '{db_prefix}topics AS t', 'inner_join' => array('{db_prefix}messages AS m ON (m.id_topic = t.id_topic)'), 'left_join' => array(), 'where' => array(), 'group_by' => array(), 'parameters' => array('min_msg' => $minMsg, 'recent_message' => $recentMsg, 'huge_topic_posts' => $humungousTopicPosts, 'is_approved' => 1)); if (empty($search_params['topic']) && empty($search_params['show_complete'])) { $main_query['select']['id_topic'] = 't.id_topic'; $main_query['select']['id_msg'] = 'MAX(m.id_msg) AS id_msg'; $main_query['select']['num_matches'] = 'COUNT(*) AS num_matches'; $main_query['weights'] = array('frequency' => 'COUNT(*) / (MAX(t.num_replies) + 1)', 'age' => 'CASE WHEN MAX(m.id_msg) < {int:min_msg} THEN 0 ELSE (MAX(m.id_msg) - {int:min_msg}) / {int:recent_message} END', 'length' => 'CASE WHEN MAX(t.num_replies) < {int:huge_topic_posts} THEN MAX(t.num_replies) / {int:huge_topic_posts} ELSE 1 END', 'subject' => '0', 'first_message' => 'CASE WHEN MIN(m.id_msg) = MAX(t.id_first_msg) THEN 1 ELSE 0 END', 'sticky' => 'MAX(t.is_sticky)'); $main_query['group_by'][] = 't.id_topic'; } else { // This is outrageous! $main_query['select']['id_topic'] = 'm.id_msg AS id_topic'; $main_query['select']['id_msg'] = 'm.id_msg'; $main_query['select']['num_matches'] = '1 AS num_matches'; $main_query['weights'] = array('age' => '((m.id_msg - t.id_first_msg) / CASE WHEN t.id_last_msg = t.id_first_msg THEN 1 ELSE t.id_last_msg - t.id_first_msg END)', 'first_message' => 'CASE WHEN m.id_msg = t.id_first_msg THEN 1 ELSE 0 END'); if (!empty($search_params['topic'])) { $main_query['where'][] = 't.id_topic = {int:topic}'; $main_query['parameters']['topic'] = $search_params['topic']; } if (!empty($search_params['show_complete'])) { $main_query['group_by'][] = 'm.id_msg, t.id_first_msg, t.id_last_msg'; } } // *** Get the subject results. $numSubjectResults = 0; if (empty($search_params['topic'])) { $inserts = array(); // Create a temporary table to store some preliminary results in. smf_db_query(' DROP TABLE IF EXISTS {db_prefix}tmp_log_search_topics', array('db_error_skip' => true)); $createTemporary = smf_db_query(' CREATE TEMPORARY TABLE {db_prefix}tmp_log_search_topics ( id_topic mediumint(8) unsigned NOT NULL default {string:string_zero}, PRIMARY KEY (id_topic) ) TYPE=HEAP', array('string_zero' => '0', 'db_error_skip' => true)) !== false; // Clean up some previous cache. if (!$createTemporary) { smf_db_query(' DELETE FROM {db_prefix}log_search_topics WHERE id_search = {int:search_id}', array('search_id' => $_SESSION['search_cache']['id_search'])); } foreach ($searchWords as $orIndex => $words) { $subject_query = array('from' => '{db_prefix}topics AS t', 'inner_join' => array(), 'left_join' => array(), 'where' => array(), 'params' => array()); $numTables = 0; $prev_join = 0; $count = 0; foreach ($words['subject_words'] as $subjectWord) { $numTables++; if (in_array($subjectWord, $excludedSubjectWords)) { if ($subject_query['from'] != '{db_prefix}messages AS m') { $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)'; } $subject_query['left_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.word ' . (empty($modSettings['search_match_words']) ? 'LIKE {string:subject_not_' . $count . '}' : '= {string:subject_not_' . $count . '}') . ' AND subj' . $numTables . '.id_topic = t.id_topic)'; $subject_query['params']['subject_not_' . $count] = empty($modSettings['search_match_words']) ? '%' . $subjectWord . '%' : $subjectWord; $subject_query['where'][] = '(subj' . $numTables . '.word IS NULL)'; $subject_query['where'][] = 'm.body NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:body_not_' . $count . '}'; $subject_query['params']['body_not_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($subjectWord, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $subjectWord), '\\\'') . '[[:>:]]'; } else { $subject_query['inner_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.id_topic = ' . ($prev_join === 0 ? 't' : 'subj' . $prev_join) . '.id_topic)'; $subject_query['where'][] = 'subj' . $numTables . '.word LIKE {string:subject_like_' . $count . '}'; $subject_query['params']['subject_like_' . $count++] = empty($modSettings['search_match_words']) ? '%' . $subjectWord . '%' : $subjectWord; $prev_join = $numTables; } } if (!empty($userQuery)) { if ($subject_query['from'] != '{db_prefix}messages AS m') { $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)'; } $subject_query['where'][] = '{raw:user_query}'; $subject_query['params']['user_query'] = $userQuery; } if (!empty($search_params['topic'])) { $subject_query['where'][] = 't.id_topic = {int:topic}'; $subject_query['params']['topic'] = $search_params['topic']; } if (!empty($minMsgID)) { $subject_query['where'][] = 't.id_first_msg >= {int:min_msg_id}'; $subject_query['params']['min_msg_id'] = $minMsgID; } if (!empty($maxMsgID)) { $subject_query['where'][] = 't.id_last_msg <= {int:max_msg_id}'; $subject_query['params']['max_msg_id'] = $maxMsgID; } if (!empty($boardQuery)) { $subject_query['where'][] = 't.id_board {raw:board_query}'; $subject_query['params']['board_query'] = $boardQuery; } if (!empty($excludedPhrases)) { if ($subject_query['from'] != '{db_prefix}messages AS m') { $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)'; } $count = 0; foreach ($excludedPhrases as $phrase) { $subject_query['where'][] = 'm.subject NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:exclude_phrase_' . $count . '}'; $subject_query['where'][] = 'm.body NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:exclude_phrase_' . $count . '}'; $subject_query['params']['exclude_phrase_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($phrase, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $phrase), '\\\'') . '[[:>:]]'; } } // Nothing to search for? if (empty($subject_query['where'])) { continue; } $ignoreRequest = smf_db_query((1 ? ' INSERT IGNORE INTO {db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics (' . ($createTemporary ? '' : 'id_search, ') . 'id_topic)' : '') . ' SELECT ' . ($createTemporary ? '' : $_SESSION['search_cache']['id_search'] . ', ') . 't.id_topic FROM ' . $subject_query['from'] . (empty($subject_query['inner_join']) ? '' : ' INNER JOIN ' . implode(' INNER JOIN ', $subject_query['inner_join'])) . (empty($subject_query['left_join']) ? '' : ' LEFT JOIN ' . implode(' LEFT JOIN ', $subject_query['left_join'])) . ' WHERE ' . implode(' AND ', $subject_query['where']) . (empty($modSettings['search_max_results']) ? '' : ' LIMIT ' . ($modSettings['search_max_results'] - $numSubjectResults)), $subject_query['params']); // Don't do INSERT IGNORE? Manually fix this up! $numSubjectResults += smf_db_affected_rows(); if (!empty($modSettings['search_max_results']) && $numSubjectResults >= $modSettings['search_max_results']) { break; } } // Got some non-MySQL data to plonk in? if (!empty($inserts)) { smf_db_insert('', '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics', $createTemporary ? array('id_topic' => 'int') : array('id_search' => 'int', 'id_topic' => 'int'), $inserts, $createTemporary ? array('id_topic') : array('id_search', 'id_topic')); } if ($numSubjectResults !== 0) { $main_query['weights']['subject'] = 'CASE WHEN MAX(lst.id_topic) IS NULL THEN 0 ELSE 1 END'; $main_query['left_join'][] = '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics AS lst ON (' . ($createTemporary ? '' : 'lst.id_search = {int:id_search} AND ') . 'lst.id_topic = t.id_topic)'; if (!$createTemporary) { $main_query['parameters']['id_search'] = $_SESSION['search_cache']['id_search']; } } } $indexedResults = 0; // We building an index? if ($searchAPI->supportsMethod('indexedWordQuery', $query_params)) { $inserts = array(); smf_db_query(' DROP TABLE IF EXISTS {db_prefix}tmp_log_search_messages', array('db_error_skip' => true)); $createTemporary = smf_db_query(' CREATE TEMPORARY TABLE {db_prefix}tmp_log_search_messages ( id_msg int(10) unsigned NOT NULL default {string:string_zero}, PRIMARY KEY (id_msg) ) TYPE=HEAP', array('string_zero' => '0', 'db_error_skip' => true)) !== false; // Clear, all clear! if (!$createTemporary) { smf_db_query(' DELETE FROM {db_prefix}log_search_messages WHERE id_search = {int:id_search}', array('id_search' => $_SESSION['search_cache']['id_search'])); } foreach ($searchWords as $orIndex => $words) { // Search for this word, assuming we have some words! if (!empty($words['indexed_words'])) { // Variables required for the search. $search_data = array('insert_into' => ($createTemporary ? 'tmp_' : '') . 'log_search_messages', 'no_regexp' => $no_regexp, 'max_results' => $maxMessageResults, 'indexed_results' => $indexedResults, 'params' => array('id_search' => !$createTemporary ? $_SESSION['search_cache']['id_search'] : 0, 'excluded_words' => $excludedWords, 'user_query' => !empty($userQuery) ? $userQuery : '', 'board_query' => !empty($boardQuery) ? $boardQuery : '', 'topic' => !empty($search_params['topic']) ? $search_params['topic'] : 0, 'min_msg_id' => !empty($minMsgID) ? $minMsgID : 0, 'max_msg_id' => !empty($maxMsgID) ? $maxMsgID : 0, 'excluded_phrases' => !empty($excludedPhrases) ? $excludedPhrases : array(), 'excluded_index_words' => !empty($excludedIndexWords) ? $excludedIndexWords : array(), 'excluded_subject_words' => !empty($excludedSubjectWords) ? $excludedSubjectWords : array())); $ignoreRequest = $searchAPI->indexedWordQuery($words, $search_data); $indexedResults += smf_db_affected_rows(); if (!empty($maxMessageResults) && $indexedResults >= $maxMessageResults) { break; } } } // More non-MySQL stuff needed? if (!empty($inserts)) { smf_db_insert('', '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_messages', $createTemporary ? array('id_msg' => 'int') : array('id_msg' => 'int', 'id_search' => 'int'), $inserts, $createTemporary ? array('id_msg') : array('id_msg', 'id_search')); } if (empty($indexedResults) && empty($numSubjectResults) && !empty($modSettings['search_force_index'])) { $context['search_errors']['query_not_specific_enough'] = true; $_REQUEST['params'] = $context['params']; EoS_Smarty::resetTemplates(); return PlushSearch1(); } elseif (!empty($indexedResults)) { $main_query['inner_join'][] = '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_messages AS lsm ON (lsm.id_msg = m.id_msg)'; if (!$createTemporary) { $main_query['where'][] = 'lsm.id_search = {int:id_search}'; $main_query['parameters']['id_search'] = $_SESSION['search_cache']['id_search']; } } } else { $orWhere = array(); $count = 0; foreach ($searchWords as $orIndex => $words) { $where = array(); foreach ($words['all_words'] as $regularWord) { $where[] = 'm.body' . (in_array($regularWord, $excludedWords) ? ' NOT' : '') . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:all_word_body_' . $count . '}'; if (in_array($regularWord, $excludedWords)) { $where[] = 'm.subject NOT' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:all_word_body_' . $count . '}'; } $main_query['parameters']['all_word_body_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($regularWord, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $regularWord), '\\\'') . '[[:>:]]'; } if (!empty($where)) { $orWhere[] = count($where) > 1 ? '(' . implode(' AND ', $where) . ')' : $where[0]; } } if (!empty($orWhere)) { $main_query['where'][] = count($orWhere) > 1 ? '(' . implode(' OR ', $orWhere) . ')' : $orWhere[0]; } if (!empty($userQuery)) { $main_query['where'][] = '{raw:user_query}'; $main_query['parameters']['user_query'] = $userQuery; } if (!empty($search_params['topic'])) { $main_query['where'][] = 'm.id_topic = {int:topic}'; $main_query['parameters']['topic'] = $search_params['topic']; } if (!empty($minMsgID)) { $main_query['where'][] = 'm.id_msg >= {int:min_msg_id}'; $main_query['parameters']['min_msg_id'] = $minMsgID; } if (!empty($maxMsgID)) { $main_query['where'][] = 'm.id_msg <= {int:max_msg_id}'; $main_query['parameters']['max_msg_id'] = $maxMsgID; } if (!empty($boardQuery)) { $main_query['where'][] = 'm.id_board {raw:board_query}'; $main_query['parameters']['board_query'] = $boardQuery; } } // Did we either get some indexed results, or otherwise did not do an indexed query? if (!empty($indexedResults) || !$searchAPI->supportsMethod('indexedWordQuery', $query_params)) { $relevance = '1000 * ('; $new_weight_total = 0; foreach ($main_query['weights'] as $type => $value) { $relevance .= $weight[$type] . ' * ' . $value . ' + '; $new_weight_total += $weight[$type]; } $main_query['select']['relevance'] = substr($relevance, 0, -3) . ') / ' . $new_weight_total . ' AS relevance'; $ignoreRequest = smf_db_query((1 ? ' INSERT IGNORE INTO ' . '{db_prefix}log_search_results (' . implode(', ', array_keys($main_query['select'])) . ')' : '') . ' SELECT ' . implode(', ', $main_query['select']) . ' FROM ' . $main_query['from'] . (empty($main_query['inner_join']) ? '' : ' INNER JOIN ' . implode(' INNER JOIN ', $main_query['inner_join'])) . (empty($main_query['left_join']) ? '' : ' LEFT JOIN ' . implode(' LEFT JOIN ', $main_query['left_join'])) . (!empty($main_query['where']) ? ' WHERE ' : '') . implode(' AND ', $main_query['where']) . (empty($main_query['group_by']) ? '' : ' GROUP BY ' . implode(', ', $main_query['group_by'])) . (empty($modSettings['search_max_results']) ? '' : ' LIMIT ' . $modSettings['search_max_results']), $main_query['parameters']); $_SESSION['search_cache']['num_results'] = smf_db_affected_rows(); } // Insert subject-only matches. if ($_SESSION['search_cache']['num_results'] < $modSettings['search_max_results'] && $numSubjectResults !== 0) { $usedIDs = array_flip(empty($inserts) ? array() : array_keys($inserts)); $ignoreRequest = smf_db_query((1 ? ' INSERT IGNORE INTO {db_prefix}log_search_results (id_search, id_topic, relevance, id_msg, num_matches)' : '') . ' SELECT {int:id_search}, t.id_topic, 1000 * ( {int:weight_frequency} / (t.num_replies + 1) + {int:weight_age} * CASE WHEN t.id_first_msg < {int:min_msg} THEN 0 ELSE (t.id_first_msg - {int:min_msg}) / {int:recent_message} END + {int:weight_length} * CASE WHEN t.num_replies < {int:huge_topic_posts} THEN t.num_replies / {int:huge_topic_posts} ELSE 1 END + {int:weight_subject} + {int:weight_sticky} * t.is_sticky ) / {int:weight_total} AS relevance, t.id_first_msg, 1 FROM {db_prefix}topics AS t INNER JOIN {db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics AS lst ON (lst.id_topic = t.id_topic)' . ($createTemporary ? '' : 'WHERE lst.id_search = {int:id_search}') . (empty($modSettings['search_max_results']) ? '' : ' LIMIT ' . ($modSettings['search_max_results'] - $_SESSION['search_cache']['num_results'])), array('id_search' => $_SESSION['search_cache']['id_search'], 'weight_age' => $weight['age'], 'weight_frequency' => $weight['frequency'], 'weight_length' => $weight['frequency'], 'weight_sticky' => $weight['frequency'], 'weight_subject' => $weight['frequency'], 'weight_total' => $weight_total, 'min_msg' => $minMsg, 'recent_message' => $recentMsg, 'huge_topic_posts' => $humungousTopicPosts)); // Once again need to do the inserts if the database don't support ignore! $_SESSION['search_cache']['num_results'] += smf_db_affected_rows(); } else { $_SESSION['search_cache']['num_results'] = 0; } } } // *** Retrieve the results to be shown on the page $participants = array(); $request = smf_db_query(' SELECT ' . (empty($search_params['topic']) ? 'lsr.id_topic' : $search_params['topic'] . ' AS id_topic') . ', lsr.id_msg, lsr.relevance, lsr.num_matches FROM {db_prefix}log_search_results AS lsr' . ($search_params['sort'] == 'num_replies' ? ' INNER JOIN {db_prefix}topics AS t ON (t.id_topic = lsr.id_topic)' : '') . ' WHERE lsr.id_search = {int:id_search} ORDER BY ' . $search_params['sort'] . ' ' . $search_params['sort_dir'] . ' LIMIT ' . (int) $_REQUEST['start'] . ', ' . $modSettings['search_results_per_page'], array('id_search' => $_SESSION['search_cache']['id_search'])); while ($row = mysql_fetch_assoc($request)) { $context['topics'][$row['id_msg']] = array('relevance' => round($row['relevance'] / 10, 1) . '%', 'num_matches' => $row['num_matches'], 'matches' => array()); // By default they didn't participate in the topic! $participants[$row['id_topic']] = false; } mysql_free_result($request); $num_results = $_SESSION['search_cache']['num_results']; } if (!empty($context['topics'])) { // Create an array for the permissions. $boards_can = array('post_reply_own' => boardsAllowedTo('post_reply_own'), 'post_reply_any' => boardsAllowedTo('post_reply_any'), 'mark_any_notify' => boardsAllowedTo('mark_any_notify')); // How's about some quick moderation? if (!empty($options['display_quick_mod'])) { $boards_can['lock_any'] = boardsAllowedTo('lock_any'); $boards_can['lock_own'] = boardsAllowedTo('lock_own'); $boards_can['make_sticky'] = boardsAllowedTo('make_sticky'); $boards_can['move_any'] = boardsAllowedTo('move_any'); $boards_can['move_own'] = boardsAllowedTo('move_own'); $boards_can['remove_any'] = boardsAllowedTo('remove_any'); $boards_can['remove_own'] = boardsAllowedTo('remove_own'); $boards_can['merge_any'] = boardsAllowedTo('merge_any'); $context['can_lock'] = in_array(0, $boards_can['lock_any']); $context['can_sticky'] = in_array(0, $boards_can['make_sticky']) && !empty($modSettings['enableStickyTopics']); $context['can_move'] = in_array(0, $boards_can['move_any']); $context['can_remove'] = in_array(0, $boards_can['remove_any']); $context['can_merge'] = in_array(0, $boards_can['merge_any']); } // What messages are we using? $msg_list = array_keys($context['topics']); // Load the posters... $request = smf_db_query(' SELECT id_member FROM {db_prefix}messages WHERE id_member != {int:no_member} AND id_msg IN ({array_int:message_list}) LIMIT ' . count($context['topics']), array('message_list' => $msg_list, 'no_member' => 0)); $posters = array(); while ($row = mysql_fetch_assoc($request)) { $posters[] = $row['id_member']; } mysql_free_result($request); if (!empty($posters)) { loadMemberData(array_unique($posters)); } // Get the messages out for the callback - select enough that it can be made to look just like Display. $messages_request = smf_db_query(' SELECT m.id_msg, m.subject, m.poster_name, m.poster_email, m.poster_time, m.id_member, m.icon, m.poster_ip, m.body, m.smileys_enabled, m.modified_time, m.modified_name, first_m.id_msg AS first_msg, first_m.subject AS first_subject, first_m.icon AS first_icon, first_m.poster_time AS first_poster_time, first_mem.id_member AS first_member_id, IFNULL(first_mem.real_name, first_m.poster_name) AS first_member_name, last_m.id_msg AS last_msg, last_m.poster_time AS last_poster_time, last_mem.id_member AS last_member_id, IFNULL(last_mem.real_name, last_m.poster_name) AS last_member_name, last_m.icon AS last_icon, last_m.subject AS last_subject, t.id_topic, t.is_sticky, t.locked, t.id_poll, t.num_replies, t.num_views, b.id_board, b.name AS board_name, c.id_cat, c.name AS cat_name FROM {db_prefix}messages AS m INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic) INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) INNER JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat) INNER JOIN {db_prefix}messages AS first_m ON (first_m.id_msg = t.id_first_msg) INNER JOIN {db_prefix}messages AS last_m ON (last_m.id_msg = t.id_last_msg) LEFT JOIN {db_prefix}members AS first_mem ON (first_mem.id_member = first_m.id_member) LEFT JOIN {db_prefix}members AS last_mem ON (last_mem.id_member = first_m.id_member) WHERE m.id_msg IN ({array_int:message_list})' . ($modSettings['postmod_active'] ? ' AND m.approved = {int:is_approved}' : '') . ' ORDER BY FIND_IN_SET(m.id_msg, {string:message_list_in_set}) LIMIT {int:limit}', array('message_list' => $msg_list, 'is_approved' => 1, 'message_list_in_set' => implode(',', $msg_list), 'limit' => count($context['topics']))); // If there are no results that means the things in the cache got deleted, so pretend we have no topics anymore. if (mysql_num_rows($messages_request) == 0) { $context['topics'] = array(); } // If we want to know who participated in what then load this now. if (!empty($modSettings['enableParticipation']) && !$user_info['is_guest']) { $result = 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($participants), array('current_member' => $user_info['id'], 'topic_list' => array_keys($participants))); while ($row = mysql_fetch_assoc($result)) { $participants[$row['id_topic']] = true; } mysql_free_result($result); } } // Now that we know how many results to expect we can start calculating the page numbers. $context['page_index'] = constructPageIndex($scripturl . '?action=search2;params=' . $context['params'], $_REQUEST['start'], $num_results, $modSettings['search_results_per_page'], false); // Consider the search complete! if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2) { CacheAPI::putCache('search_start:' . ($user_info['is_guest'] ? $user_info['ip'] : $user_info['id']), null, 90); } $context['key_words'] =& $searchArray; if (empty($context['compact'])) { $context['need_synhlt'] = 1; } $context['sub_template'] = 'results'; $context['page_title'] = $txt['search_results']; $context['get_topics'] = 'prepareSearchContext'; $context['can_send_pm'] = allowedTo('pm_send'); $context['jump_to'] = array('label' => addslashes(un_htmlspecialchars($txt['jump_to'])), 'board_name' => addslashes(un_htmlspecialchars($txt['select_destination']))); }
/** * @param $memID int member's ID * * grab a list of news items that were dismissed previously. Dismissed news item ids are * stored in the member's meta array. * * TODO: implement paging(?) - are we ever going to have that many board notices? */ function profileManageBoardNews($memID) { global $context, $user_info, $scripturl, $txt; EoS_Smarty::loadTemplate('profile/profile_base'); EoS_Smarty::getConfigInstance()->registerHookTemplate('profile_content_area', 'profile/manage_news'); $start = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0; if (isset($_REQUEST['sa']) && $_REQUEST['sa'] === 'reactivateall' && $user_info['id'] == $memID) { unset($user_info['meta']['dismissed_news_items']); updateMemberData($memID, array('meta' => @serialize($user_info['meta']))); redirectexit('action=profile;area=boardnews;u=' . $memID); } $context['items_per_page'] = commonAPI::getMessagesPerPage(); $context['dismissed_items'] = array(); if (!isset($user_info['meta']['dismissed_news_items'])) { $user_info['meta']['dismissed_news_items'] = array(); } if (count($user_info['meta']['dismissed_news_items'])) { $request = smf_db_query('SELECT * FROM {db_prefix}news WHERE id_news IN({array_int:ids}) LIMIT {int:start}, {int:perpage}', array('ids' => $user_info['meta']['dismissed_news_items'], 'start' => $start, 'perpage' => $context['items_per_page'])); while ($row = mysql_fetch_assoc($request)) { $groups_allowed = explode(',', $row['groups']); if (!empty($groups_allowed[0]) && !in_array($user_info['groups'], $groups_allowed)) { continue; } $context['dismissed_items'][$row['id_news']] = array('id' => $row['id_news'], 'teaser' => !empty($row['teaser']) ? parse_bbc($row['teaser']) : '', 'body' => parse_bbc($row['body']), 'groups' => explode(',', $row['groups']), 'on_index' => $row['on_index'] ? true : false, 'can_dismiss' => $row['can_dismiss'], 'topics' => explode(',', $row['topics']), 'boards' => explode(',', $row['boards'])); } mysql_free_result($request); } $context['have_items'] = count($context['dismissed_items']); $context['reactivate_link'] = $context['have_items'] ? '<a class="active" href="' . $scripturl . '?action=profile;area=boardnews;sa=reactivateall;u=' . $memID . '">' . $txt['news_items_reactivate'] . '</a>' : ''; }
function SecretAnswer2() { global $txt, $context, $modSettings, $smcFunc, $sourcedir; checkSession(); // Hacker? How did you get this far without an email or username? if (empty($_REQUEST['uid'])) { fatal_lang_error('username_no_exist', false); } loadLanguage('Login'); // Get the information from the database. $request = smf_db_query(' SELECT id_member, real_name, member_name, secret_answer, secret_question, openid_uri, email_address FROM {db_prefix}members WHERE id_member = {int:id_member} LIMIT 1', array('id_member' => $_REQUEST['uid'])); if (mysql_num_rows($request) == 0) { fatal_lang_error('username_no_exist', false); } $row = mysql_fetch_assoc($request); mysql_free_result($request); // Check if the secret answer is correct. if ($row['secret_question'] == '' || $row['secret_answer'] == '' || md5($_POST['secret_answer']) != $row['secret_answer']) { log_error(sprintf($txt['reminder_error'], $row['member_name']), 'user'); fatal_lang_error('incorrect_answer', false); } // If it's OpenID this is where the music ends. if (!empty($row['openid_uri'])) { $context['sub_template'] = 'sent'; $context['description'] = sprintf($txt['reminder_openid_is'], $row['openid_uri']); return; } // You can't use a blank one! if (strlen(trim($_POST['passwrd1'])) === 0) { fatal_lang_error('no_password', false); } // They have to be the same too. if ($_POST['passwrd1'] != $_POST['passwrd2']) { fatal_lang_error('passwords_dont_match', false); } // Make sure they have a strong enough password. require_once $sourcedir . '/lib/Subs-Auth.php'; $passwordError = validatePassword($_POST['passwrd1'], $row['member_name'], array($row['email_address'])); // Invalid? if ($passwordError != null) { fatal_lang_error('profile_error_password_' . $passwordError, false); } // Alright, so long as 'yer sure. updateMemberData($row['id_member'], array('passwd' => sha1(strtolower($row['member_name']) . $_POST['passwrd1']))); HookAPI::callHook('integrate_reset_pass', array($row['member_name'], $row['member_name'], $_POST['passwrd1'])); // Tell them it went fine. EoS_Smarty::loadTemplate('generic_skeleton'); EoS_Smarty::getConfigInstance()->registerHookTemplate('generic_content_area', 'loginout/login'); $context += array('page_title' => $txt['reminder_password_set'], 'default_username' => $row['member_name'], 'default_password' => $_POST['passwrd1'], 'never_expire' => false, 'description' => $txt['reminder_password_set']); }
function is_not_guest($message = '') { global $user_info, $txt, $context, $scripturl; // Luckily, this person isn't a guest. if (!$user_info['is_guest']) { return; } // People always worry when they see people doing things they aren't actually doing... $_GET['action'] = ''; $_GET['board'] = ''; $_GET['topic'] = ''; writeLog(true); // Just die. if (isset($_REQUEST['xml'])) { obExit(false); } // Attempt to detect if they came from dlattach. if (SMF != 'SSI' && empty($context['theme_loaded'])) { loadTheme(); } // Never redirect to an attachment if (strpos($_SERVER['REQUEST_URL'], 'dlattach') === false) { $_SESSION['login_url'] = $_SERVER['REQUEST_URL']; } // Load the Login template and language file. loadLanguage('Login'); // Apparently we're not in a position to handle this now. Let's go to a safer location for now. if (empty($context['template_layers'])) { $_SESSION['login_url'] = $scripturl . '?' . $_SERVER['QUERY_STRING']; redirectexit('action=login'); } else { EoS_Smarty::resetTemplates(); EoS_Smarty::loadTemplate('generic_skeleton'); EoS_Smarty::getConfigInstance()->registerHookTemplate('generic_content_area', 'loginout/login'); $context['is_kick_guest'] = true; $context['robot_no_index'] = true; } // Use the kick_guest sub template... $context['kick_message'] = $message; $context['page_title'] = $txt['login']; obExit(); // We should never get to this point, but if we did we wouldn't know the user isn't a guest. trigger_error('Hacking attempt...', E_USER_ERROR); }
function ManageRules() { global $txt, $context, $user_info, $scripturl, $smcFunc; // The link tree - gotta have this :o $context['linktree'][] = array('url' => $scripturl . '?action=pm;sa=manrules', 'name' => $txt['pm_manage_rules']); $_ctx = new PMContext(); $context['page_title'] = $txt['pm_manage_rules']; EoS_Smarty::loadTemplate('pm/base'); // Load them... load them!! LoadRules(); // Likely to need all the groups! $request = smf_db_query(' SELECT mg.id_group, mg.group_name, IFNULL(gm.id_member, 0) AS can_moderate, mg.hidden FROM {db_prefix}membergroups AS mg LEFT JOIN {db_prefix}group_moderators AS gm ON (gm.id_group = mg.id_group AND gm.id_member = {int:current_member}) WHERE mg.min_posts = {int:min_posts} AND mg.id_group != {int:moderator_group} AND mg.hidden = {int:not_hidden} ORDER BY mg.group_name', array('current_member' => $user_info['id'], 'min_posts' => -1, 'moderator_group' => 3, 'not_hidden' => 0)); $context['groups'] = array(); while ($row = mysql_fetch_assoc($request)) { // Hide hidden groups! if ($row['hidden'] && !$row['can_moderate'] && !allowedTo('manage_membergroups')) { continue; } $context['groups'][$row['id_group']] = $row['group_name']; } mysql_free_result($request); // Applying all rules? if (isset($_GET['apply'])) { checkSession('get'); ApplyRules(true); redirectexit('action=pm;sa=manrules'); } // Editing a specific one? if (isset($_GET['add'])) { $context['rid'] = isset($_GET['rid']) && isset($context['rules'][$_GET['rid']]) ? (int) $_GET['rid'] : 0; EoS_Smarty::getConfigInstance()->registerHookTemplate('pm_content_area', 'pm/add_rule'); // Current rule information... if ($context['rid']) { $context['rule'] = $context['rules'][$context['rid']]; $members = array(); // Need to get member names! foreach ($context['rule']['criteria'] as $k => $criteria) { if ($criteria['t'] == 'mid' && !empty($criteria['v'])) { $members[(int) $criteria['v']] = $k; } } if (!empty($members)) { $request = smf_db_query(' SELECT id_member, member_name FROM {db_prefix}members WHERE id_member IN ({array_int:member_list})', array('member_list' => array_keys($members))); while ($row = mysql_fetch_assoc($request)) { $context['rule']['criteria'][$members[$row['id_member']]]['v'] = $row['member_name']; } mysql_free_result($request); } } else { $context['rule'] = array('id' => '', 'name' => '', 'criteria' => array(), 'actions' => array(), 'logic' => 'and'); } $context['rule']['criteria'][] = array('t' => '', 'v' => ''); $context['rule']['actions'][] = array('t' => '', 'v' => ''); } elseif (isset($_GET['save'])) { checkSession('post'); $context['rid'] = isset($_GET['rid']) && isset($context['rules'][$_GET['rid']]) ? (int) $_GET['rid'] : 0; // Name is easy! $ruleName = commonAPI::htmlspecialchars(trim($_POST['rule_name'])); if (empty($ruleName)) { fatal_lang_error('pm_rule_no_name', false); } // Sanity check... if (empty($_POST['ruletype']) || empty($_POST['acttype'])) { fatal_lang_error('pm_rule_no_criteria', false); } // Let's do the criteria first - it's also hardest! $criteria = array(); foreach ($_POST['ruletype'] as $ind => $type) { // Check everything is here... if ($type == 'gid' && (!isset($_POST['ruledefgroup'][$ind]) || !isset($context['groups'][$_POST['ruledefgroup'][$ind]]))) { continue; } elseif ($type != 'bud' && !isset($_POST['ruledef'][$ind])) { continue; } // Members need to be found. if ($type == 'mid') { $name = trim($_POST['ruledef'][$ind]); $request = smf_db_query(' SELECT id_member FROM {db_prefix}members WHERE real_name = {string:member_name} OR member_name = {string:member_name}', array('member_name' => $name)); if (mysql_num_rows($request) == 0) { continue; } list($memID) = mysql_fetch_row($request); mysql_free_result($request); $criteria[] = array('t' => 'mid', 'v' => $memID); } elseif ($type == 'bud') { $criteria[] = array('t' => 'bud', 'v' => 1); } elseif ($type == 'gid') { $criteria[] = array('t' => 'gid', 'v' => (int) $_POST['ruledefgroup'][$ind]); } elseif (in_array($type, array('sub', 'msg')) && trim($_POST['ruledef'][$ind]) != '') { $criteria[] = array('t' => $type, 'v' => commonAPI::htmlspecialchars(trim($_POST['ruledef'][$ind]))); } } // Also do the actions! $actions = array(); $doDelete = 0; $isOr = $_POST['rule_logic'] == 'or' ? 1 : 0; foreach ($_POST['acttype'] as $ind => $type) { // Picking a valid label? if ($type == 'lab' && (!isset($_POST['labdef'][$ind]) || !isset($context['labels'][$_POST['labdef'][$ind] - 1]))) { continue; } // Record what we're doing. if ($type == 'del') { $doDelete = 1; } elseif ($type == 'lab') { $actions[] = array('t' => 'lab', 'v' => (int) $_POST['labdef'][$ind] - 1); } } if (empty($criteria) || empty($actions) && !$doDelete) { fatal_lang_error('pm_rule_no_criteria', false); } // What are we storing? $criteria = serialize($criteria); $actions = serialize($actions); // Create the rule? if (empty($context['rid'])) { smf_db_insert('', '{db_prefix}pm_rules', array('id_member' => 'int', 'rule_name' => 'string', 'criteria' => 'string', 'actions' => 'string', 'delete_pm' => 'int', 'is_or' => 'int'), array($user_info['id'], $ruleName, $criteria, $actions, $doDelete, $isOr), array('id_rule')); } else { smf_db_query(' UPDATE {db_prefix}pm_rules SET rule_name = {string:rule_name}, criteria = {string:criteria}, actions = {string:actions}, delete_pm = {int:delete_pm}, is_or = {int:is_or} WHERE id_rule = {int:id_rule} AND id_member = {int:current_member}', array('current_member' => $user_info['id'], 'delete_pm' => $doDelete, 'is_or' => $isOr, 'id_rule' => $context['rid'], 'rule_name' => $ruleName, 'criteria' => $criteria, 'actions' => $actions)); } redirectexit('action=pm;sa=manrules'); } elseif (isset($_POST['delselected']) && !empty($_POST['delrule'])) { checkSession('post'); $toDelete = array(); foreach ($_POST['delrule'] as $k => $v) { $toDelete[] = (int) $k; } if (!empty($toDelete)) { smf_db_query(' DELETE FROM {db_prefix}pm_rules WHERE id_rule IN ({array_int:delete_list}) AND id_member = {int:current_member}', array('current_member' => $user_info['id'], 'delete_list' => $toDelete)); } redirectexit('action=pm;sa=manrules'); } EoS_Smarty::getConfigInstance()->registerHookTemplate('pm_content_area', 'pm/manage_rules'); }
function TopicBans() { global $context, $board_info, $topic, $txt, $memberContext, $user_info; EoS_Smarty::loadTemplate('modcenter/modcenter_base'); if (isset($_REQUEST['sa']) && ($_REQUEST['sa'] === 'unban' || $_REQUEST['sa'] === 'ban')) { $is_ban = $_REQUEST['sa'] === 'ban' ? 1 : 0; $context['page_title'] = $is_ban ? $txt['mc_issue_topic_ban'] : $txt['mc_lift_topic_ban']; EoS_Smarty::getConfigInstance()->registerHookTemplate('modcenter_content_area', 'modcenter/topicban_issue_or_lift'); $context['op_errors'] = array(); $member = isset($_REQUEST['m']) ? (int) $_REQUEST['m'] : 0; if (!isset($topic) || empty($topic) || !isset($board_info) || empty($board_info) || 0 == $member) { $context['op_errors'][] = $txt['mc_lift_topic_ban_missing_data']; } if (!allowedTo('moderate_board')) { $context['op_errors'][] = $txt['mc_lift_topic_ban_not_allowed']; } if (loadMemberData($member) != false) { loadMemberContext($member); $context['banned_member'] =& $memberContext[$member]; } else { $context['op_errors'][] = $txt['mc_lift_topic_ban_invalid_member']; } // defaults $context['ban_data'] = array('expire' => 0, 'reason' => ''); if (isset($_REQUEST['save'])) { $context['ban_data']['expire'] = !empty($_POST['mc_expire']) ? (int) $_POST['mc_expire'] : 0; $context['ban_data']['reason'] = !empty($_POST['mc_reason']) ? htmlspecialchars($_POST['mc_reason']) : ''; } $context['ban_row'] = array(); // do not check this for admins - they can do whatever they want and even ban a moderator in his own board. Yes, admins are >> all :) if ($is_ban && !$user_info['is_admin']) { if (isUserAllowedTo('moderate_forum', 0, $member) || isUserAllowedTo('moderate_board', $board_info['id'], $member)) { $context['op_errors'][] = $txt['mc_topicban_not_bannable']; } } $request = smf_db_query('SELECT t.id_topic, ba.id_member, ba.updated, ba.reason, m.subject FROM {db_prefix}topics AS t LEFT JOIN {db_prefix}topicbans AS ba ON (ba.id_topic = t.id_topic AND ba.id_member = {int:member}) LEFT JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg) WHERE t.id_topic = {int:topic}', array('topic' => $topic, 'member' => $member)); if (mysql_num_rows($request) > 0) { $row = mysql_fetch_assoc($request); if (!empty($row['reason']) && strpos($row['reason'], '|')) { list($msg, $reason) = explode('|', $row['reason']); } else { $msg = 0; $reason = ''; } $context['ban_row'] = array('id_member' => $row['id_member'], 'id_topic' => $row['id_topic'], 'subject' => $row['subject'], 'ban_time' => timeformat($row['updated']), 'href' => URL::topic($topic, $row['subject']), 'is_banned' => $row['id_member'], 'msg' => $msg, 'reason' => $reason); if ($_REQUEST['sa'] == 'ban' && $context['ban_row']['is_banned']) { $context['op_errors'][] = $txt['mc_topicban_duplicate']; } elseif ($_REQUEST['sa'] == 'unban' && $context['ban_row']['is_banned'] == 0) { $context['op_errors'][] = $txt['mc_lift_ban_not_found']; } } else { $context['op_errors'][] = $txt['mc_lift_ban_not_found']; } mysql_free_result($request); $mid = isset($_REQUEST['mid']) ? (int) $_REQUEST['mid'] : 0; // save it $back_to_topic = URL::topic($topic, $context['ban_row']['subject'], 0, false, '.msg' . (int) $_REQUEST['mid'], '#msg' . (int) $_REQUEST['mid']); if (empty($context['op_errors'])) { if (isset($_REQUEST['save']) && $is_ban && empty($_POST['mc_reason'])) { $context['op_errors'][] = $txt['mc_topicban_missing_reason']; } if (isset($_REQUEST['save']) && empty($context['op_errors'])) { checkSession(); $context['success'] = 'Success'; $context['back_url'] = $back_to_topic; $context['back_label'] = $txt['mc_lift_ban_backtotopic']; if ($is_ban) { $ban_expire = isset($_REQUEST['mc_expire']) && !empty($_REQUEST['mc_expire']) ? (int) $_REQUEST['mc_expire'] * 86400 : 0; $ban_reason = (isset($_REQUEST['mid']) && !empty($_REQUEST['mid']) ? (int) $_REQUEST['mid'] : 0) . '|' . htmlspecialchars($_POST['mc_reason']); smf_db_insert('', '{db_prefix}topicbans', array('id_topic' => 'int', 'id_member' => 'int', 'updated' => 'int', 'expires' => 'int', 'reason' => 'string-255'), array($topic, $member, $context['time_now'], $ban_expire ? $context['time_now'] + $ban_expire : 0, $ban_reason), array('id')); } else { smf_db_query('DELETE FROM {db_prefix}topicbans WHERE id_topic = {int:topic} AND id_member = {int:member}', array('topic' => $topic, 'member' => $member)); } } else { $context['submit_url'] = URL::parse('?action=moderate;area=topicbans;sa=' . ($is_ban ? 'ban' : 'unban') . ';topic=' . $topic . ';m=' . $member . ';save' . ';mid=' . $mid); $context['back_url'] = $back_to_topic; $context['back_label'] = $txt['mc_lift_ban_backtotopic']; $context['submit_label'] = $is_ban ? $txt['mc_issue_ban'] : $txt['mc_lift_ban']; $context['topicban_message'] = $is_ban ? sprintf($txt['mc_topicban_message'], $context['banned_member']['link'], $context['ban_row']['href'], $context['ban_row']['subject']) : sprintf($txt['mc_lift_ban_message'], $context['banned_member']['link'], $context['ban_row']['href'], $context['ban_row']['subject'], $context['ban_row']['ban_time']); $context['submit'] = true; $context['is_ban'] = $is_ban; } } else { $context['back_url'] = $back_to_topic; $context['back_label'] = $txt['mc_lift_ban_backtotopic']; } } else { global $user_info, $context; $boards = array(); if ($user_info['is_admin'] || allowedTo('moderate_forum')) { // admins and global moderator can see all topic bans $board_query = '1=1'; } else { $boards = boardsAllowedTo('moderate_board'); if (empty($boards)) { fatal_lang_error('no_access', true); } // we cannot moderate any board, so we have no business in being here $board_query = 'b.id_board IN ({array_int:boards})'; } $member = isset($_REQUEST['m']) ? (int) $_REQUEST['m'] : 0; $topic = isset($_REQUEST['t']) ? (int) $_REQUEST['t'] : 0; $start = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0; $mode = isset($_REQUEST['sa']) ? $_REQUEST['sa'] : 'all'; $perpage = 25; if ($mode !== 'bymember' && $mode !== 'bytopic' && $mode !== 'all') { $mode = 'all'; } $base_query = '1=1'; if ($mode === 'bymember') { $base_query = $member ? 'ba.id_member = {int:member}' : $base_query; } else { $base_query = $topic ? 'ba.id_topic = {int:topic}' : $base_query; } EoS_Smarty::getConfigInstance()->registerHookTemplate('modcenter_content_area', 'modcenter/topicbans_list'); $context['page_title'] = $txt['mc_topicbans_view']; $context[$context['moderation_menu_name']]['tab_data'] = array('title' => $txt['mc_topicbans_view'], 'description' => $txt['mc_topicbans_view_desc']); $context['topicban_view_desc'] = $txt['mc_view_topicbans_all']; if ($mode === 'bytopic' && $topic == 0) { $context['error'] = $txt['mc_topicbans_notopic']; return; } else { if ($mode === 'bymember' && $member == 0) { $context['error'] = $txt['mc_topicbans_nomember']; return; } } $request = smf_db_query('SELECT COUNT(ba.id_topic) FROM {db_prefix}topicbans AS ba LEFT JOIN {db_prefix}topics AS t ON(t.id_topic = ba.id_topic) LEFT JOIN {db_prefix}boards AS b ON(b.id_board = t.id_board) WHERE ' . $base_query . ' AND ' . $board_query, array('member' => $member, 'topic' => $topic, 'boards' => $boards)); list($context['total_items']) = mysql_fetch_row($request); mysql_free_result($request); $pages_base = URL::parse('?action=moderate;area=topicbans;sa=' . $mode); $pages_base = URL::addParam($pages_base, 'start=%1$d', true); $context['pages'] = $context['total_items'] ? constructPageIndex($pages_base, $start, $context['total_items'], $perpage, true) : ''; $request = smf_db_query('SELECT ba.*, mem.real_name, m.subject FROM {db_prefix}topicbans AS ba LEFT JOIN {db_prefix}topics AS t ON(t.id_topic = ba.id_topic) LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = ba.id_member) LEFT JOIN {db_prefix}messages AS m ON(m.id_msg = t.id_first_msg) LEFT JOIN {db_prefix}boards AS b ON(b.id_board = t.id_board) WHERE ' . $base_query . ' AND ' . $board_query . ' LIMIT {int:start}, {int:perpage}', array('member' => $member, 'topic' => $topic, 'boards' => $boards, 'start' => $start, 'perpage' => $perpage)); $desc_done = 0; while ($row = mysql_fetch_assoc($request)) { if (!$desc_done) { switch ($mode) { case 'bymember': $link = '<a href="' . URL::user($member, $row['real_name']) . '" onclick="getMcard(' . $member . ');return(false)">' . $row['real_name'] . '</a>'; $context['topicban_view_desc'] = sprintf($txt['mc_view_topicbans_bymember'], $link); break; case 'bytopic': $link = '<a href="' . URL::topic($topic, $row['subject'], 0, false) . '">' . $row['subject'] . '</a>'; $context['topicban_view_desc'] = sprintf($txt['mc_view_topicbans_bytopic'], $link); break; } $desc_done = true; } $m_href = URL::user($row['id_member'], $row['real_name']); $t_href = URL::topic($row['id_topic'], $row['subject'], 0, false); if (!empty($row['reason']) && strpos($row['reason'], '|')) { list($msg, $reason) = explode('|', $row['reason']); } else { $reason = ''; } $timediff = $row['expires'] - $context['time_now']; $context['topicbans'][] = array('id' => $row['id'], 'id_member' => $row['id_member'], 'member' => array('id' => $row['id_member'], 'name' => $row['real_name'], 'href' => $m_href, 'link' => '<a href="' . $m_href . '" onclick="getMcard(' . $row['id_member'] . ');return(false)">' . $row['real_name'] . '</a>'), 'topic' => array('href' => $t_href, 'subject' => $row['subject'], 'id' => $row['id_topic'], 'link' => '<a href="' . $t_href . '">' . $row['subject'] . '</a>'), 'reason' => $txt['mc_topicban_reason'] . ': ' . $reason . ' (<a href="' . URL::parse('?msg=' . trim($msg) . ';perma') . '">' . $txt['mc_topicban_reason_see'] . '</a>)', 'issue_time' => timeformat($row['updated']), 'expires' => empty($row['expires']) ? $txt['mc_topicban_is_perma'] : ($timediff > 0 ? (int) ($timediff / 3600) . ' ' . $txt['mc_topicban_hours_left'] : $txt['mc_topicban_expires'])); } mysql_free_result($request); } }
/** * fetch new threads (all of them, read status doesn't matter) * * todo: respect ignored boards */ function WhatsNew() { global $context, $modSettings, $txt, $user_info, $scripturl; $cutoff_days = !empty($modSettings['whatsNewCutoffDays']) ? $modSettings['whatsNewCutoffDays'] : 30; $context['current_action'] = 'whatsnew'; $start = isset($_REQUEST['start']) ? $_REQUEST['start'] : 0; $context['topics_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['topics_per_page']) ? $options['topics_per_page'] : $modSettings['defaultMaxTopics']; // find the first post that is newer than our cutoff time... $request = smf_db_query('SELECT m.id_msg from {db_prefix}messages AS m LEFT JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic) LEFT JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) WHERE {query_wanna_see_board} AND m.approved = 1 AND m.poster_time > unix_timestamp(now()) - ({int:days_cutoff} * 86400) limit 1', array('days_cutoff' => $cutoff_days)); EoS_Smarty::loadTemplate('recent'); $context['template_functions'] = 'unread_topics'; $context['can_approve_posts'] = allowedTo('approve_posts'); $context['page_title'] = $context['page_header'] = sprintf($txt['whatsnew_title'], $cutoff_days); $context['subject_sort_header'] = $txt['subject']; $context['views_sort_header'] = $txt['views']; $context['lastpost_sort_header'] = $txt['last_post']; $context['querystring_board_limits'] = ''; $context['linktree'][] = array('url' => URL::parse($scripturl . '?action=whatsnew'), 'name' => $context['page_title']); if (0 == mysql_num_rows($request)) { mysql_free_result($request); return; } list($first_msg) = mysql_fetch_row($request); mysql_free_result($request); $request = smf_db_query('SELECT DISTINCT(t.id_topic), COUNT(t.id_topic) FROM {db_prefix}topics AS t LEFT JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) WHERE {query_wanna_see_board} AND t.id_last_msg >= {int:first_msg} limit 1', array('first_msg' => $first_msg)); list($id, $count) = mysql_fetch_row($request); mysql_free_result($request); $total = $count; $base_url = URL::parse($scripturl . '?action=whatsnew'); $context['page_index'] = constructPageIndex($base_url . ';start=%1$d', $start, $total, $context['topics_per_page'], true); $topic_ids = array(); $request = smf_db_query('SELECT DISTINCT t.id_topic FROM {db_prefix}topics AS t LEFT JOIN {db_prefix}boards AS b ON(b.id_board = t.id_board) WHERE {query_wanna_see_board} AND t.id_last_msg >= {int:first_msg} ORDER BY t.id_last_msg DESC LIMIT {int:start}, {int:perpage}', array('first_msg' => $first_msg, 'start' => $start, 'perpage' => $context['topics_per_page'])); while ($row = mysql_fetch_assoc($request)) { $topic_ids[] = $row['id_topic']; } mysql_free_result($request); $request = smf_db_query('SELECT t.id_topic, IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1 AS new_from, b.id_board, b.name AS board_name, t.num_replies, t.locked, t.num_views, t.is_sticky, t.approved, t.unapproved_posts, t.id_first_msg, t.id_last_msg, ms.subject, ml.subject AS last_subject, ms.id_member, IFNULL(mem.real_name, ms.poster_name) AS first_member_name, ms.poster_time AS first_poster_time, ms.icon AS first_icon, ml.id_msg_modified, ml.poster_time, ml.id_member AS id_member_updated, IFNULL(mem2.real_name, ml.poster_name) AS last_real_name, ml.poster_time AS last_post_time FROM {db_prefix}topics AS t INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_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 mem ON (mem.id_member = ms.id_member) LEFT JOIN {db_prefix}members AS mem2 ON (mem2.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}) LEFT JOIN {db_prefix}prefixes AS p ON (p.id_prefix = t.id_prefix) WHERE t.id_topic IN({array_int:topic_ids}) ORDER BY t.id_last_msg DESC', array('start' => $start, 'perpage' => $context['topics_per_page'], 'first_msg' => $first_msg, 'current_member' => $user_info['id'], 'topic_ids' => $topic_ids)); $topiclist = new Topiclist($request, $total, true); mysql_free_result($request); $context['showing_all_topics'] = true; $context['topics'] = $topiclist->getResult(); }
function QuoteFast() { global $modSettings, $user_info, $context, $options, $board; global $sourcedir; loadLanguage('Post'); if (!isset($_REQUEST['xml'])) { EoS_Smarty::loadTemplate('post/quotefast_response'); } include_once $sourcedir . '/lib/Subs-Post.php'; $moderate_boards = boardsAllowedTo('moderate_board'); // Where we going if we need to? $context['post_box_name'] = isset($_GET['pb']) ? $_GET['pb'] : ''; $request = smf_db_query(' SELECT IFNULL(mem.real_name, m.poster_name) AS poster_name, m.poster_time, m.body, m.id_topic, m.subject, m.id_board, m.id_member, m.approved 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 = m.id_board AND {query_see_board}) LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) WHERE m.id_msg = {int:id_msg}' . (isset($_REQUEST['modify']) || !empty($moderate_boards) && $moderate_boards[0] == 0 ? '' : ' AND (t.locked = {int:not_locked}' . (empty($moderate_boards) ? '' : ' OR b.id_board IN ({array_int:moderation_board_list})') . ')') . ' LIMIT 1', array('current_member' => $user_info['id'], 'moderation_board_list' => $moderate_boards, 'id_msg' => (int) $_REQUEST['quote'], 'not_locked' => 0)); $context['close_window'] = mysql_num_rows($request) == 0; $row = mysql_fetch_assoc($request); mysql_free_result($request); $board = $row['id_board']; // quick modify, attempt to find existing drafts and load them /* todo: drafts -> plugin if(!$context['close_window'] && isset($_REQUEST['modify']) && !$user_info['is_guest'] && in_array('dr', $context['admin_features']) && allowedTo('drafts_allow', $row['id_board']) && !empty($options['use_drafts'])) { $draftrequest = smf_db_query( ' SELECT body FROM {db_prefix}drafts WHERE id_msg = {int:id_msg} AND id_member = {int:user}', array('id_msg' => (int)$_REQUEST['quote'], 'user' => $user_info['id'])); $draftrow = mysql_fetch_assoc($draftrequest); mysql_free_result($draftrequest); } */ if (isset($_REQUEST['modify']) && isset($draftrow) && !empty($draftrow['body']) && !empty($row)) { $row['body'] = $draftrow['body']; } $context['sub_template'] = 'quotefast'; if (!empty($row)) { $can_view_post = $row['approved'] || $row['id_member'] != 0 && $row['id_member'] == $user_info['id'] || allowedTo('approve_posts', $row['id_board']); } if (!empty($can_view_post)) { // Remove special formatting we don't want anymore. $row['body'] = un_preparsecode($row['body']); // Censor the message! censorText($row['body']); $row['body'] = preg_replace('~<br ?/?' . '>~i', "\n", $row['body']); // Want to modify a single message by double clicking it? if (isset($_REQUEST['modify'])) { censorText($row['subject']); $context['sub_template'] = 'modifyfast'; $context['message'] = array('id' => $_REQUEST['quote'], 'body' => $row['body'], 'subject' => addcslashes($row['subject'], '"')); parse_bbc_stage2($context['message']['body'], 0, true); return; } // Remove any nested quotes. if (!empty($modSettings['removeNestedQuotes'])) { $row['body'] = preg_replace(array('~\\n?\\[quote.*?\\].+?\\[/quote\\]\\n?~is', '~^\\n~', '~\\[/quote\\]~'), '', $row['body']); } // Make the body HTML if need be. if (!empty($_REQUEST['mode'])) { require_once $sourcedir . '/lib/Subs-Editor.php'; $row['body'] = strtr($row['body'], array('<' => '#smlt#', '>' => '#smgt#', '&' => '#smamp#')); $row['body'] = bbc_to_html($row['body']); $lb = '<br />'; } else { $lb = "\n"; } parse_bbc_stage2($row['body'], 0, true); // Add a quote string on the front and end. $context['quote']['xml'] = '[quote author=' . $row['poster_name'] . ' link=topic=' . $row['id_topic'] . '.msg' . (int) $_REQUEST['quote'] . '#msg' . (int) $_REQUEST['quote'] . ' date=' . $row['poster_time'] . ']' . $lb . $row['body'] . $lb . '[/quote]' . "\n\n"; //$context['quote']['xml'] = '[quote author=' . $row['poster_name'] . ' link=topic=' . $row['id_topic'] . '.msg' . (int) $_REQUEST['quote'] . '#msg' . (int) $_REQUEST['quote'] . ' date=' . $row['poster_time'] . ']' . $lb . $row['body'] . $lb . '[/quote]'; $context['quote']['text'] = strtr(un_htmlspecialchars($context['quote']['xml']), array('\'' => '\\\'', '\\' => '\\\\', "\n" => '\\n', '</script>' => '</\' + \'script>')); $context['quote']['xml'] = strtr($context['quote']['xml'], array(' ' => ' ', '<' => '<', '>' => '>')); $context['quote']['mozilla'] = strtr(commonAPI::htmlspecialchars($context['quote']['text']), array('"' => '"')); } elseif (isset($_REQUEST['modify'])) { $context['sub_template'] = 'modifyfast'; $context['message'] = array('id' => 0, 'body' => '', 'subject' => ''); } else { $context['quote'] = array('xml' => '', 'mozilla' => '', 'text' => ''); } }
function WhoPosted() { global $context; $tid = isset($_REQUEST['t']) ? (int) $_REQUEST['t'] : 0; if ($tid) { $result = smf_db_query('SELECT t.id_board FROM {db_prefix}topics AS t INNER JOIN {db_prefix}boards AS b ON b.id_board = t.id_board WHERE t.id_topic = {int:topic} AND {query_see_board}', array('topic' => $tid)); $b = mysql_fetch_row($result); mysql_free_result($result); if ($b) { $result = smf_db_query(' SELECT mem.real_name, m.id_member, count(m.id_member) AS count FROM {db_prefix}messages AS m LEFT JOIN {db_prefix}members AS mem ON mem.id_member = m.id_member WHERE m.id_topic = {int:topic} GROUP BY m.id_member ORDER BY count DESC limit 20', array('topic' => $tid)); while ($row = mysql_fetch_assoc($result)) { $context['posters'][] = $row; } mysql_free_result($result); EoS_Smarty::loadTemplate('xml_blocks'); $context['template_functions'] = array('who_posted_xml'); } } }
function DismissNews() { global $context, $user_info, $txt; EoS_Smarty::loadTemplate('xml_blocks'); $context['template_functions'] = array('dismiss_newsitem'); $id = isset($_REQUEST['id']) ? (int) $_REQUEST['id'] : 0; $xml = isset($_REQUEST['xml']) ? true : false; $context['sub_template'] = 'dismiss_handler' . ($xml ? '_xml' : ''); $effective_id = 0; if ($id) { $result = smf_db_query('SELECT id_news, can_dismiss FROM {db_prefix}news WHERE id_news = {int:id}', array('id' => $id)); if (mysql_num_rows($result) > 0) { list($effective_id, $can_dismiss_item) = mysql_fetch_row($result); } mysql_free_result($result); if (!empty($effective_id)) { $context['raw_item_id'] = $effective_id; if ($user_info['is_admin'] || allowedTo('can_dismiss_news') && $can_dismiss_item != 0) { $context['item_to_dismiss'] = json_encode(array('id' => $effective_id)); if (!isset($user_info['meta']['dismissed_news_items'][$effective_id])) { $user_info['meta']['dismissed_news_items'][$effective_id] = $effective_id; updateMemberData($user_info['id'], array('meta' => @serialize($user_info['meta']))); } if ($xml) { $context['template_layers'] = array(); } return; } } } loadLanguage('Errors'); if (isset($_REQUEST['xml'])) { AjaxErrorMsg($txt['no_access']); } else { fatal_lang_error('no_access'); } }
function Credits($in_admin = false) { global $context, $modSettings, $forum_copyright, $forum_version, $boardurl, $txt, $user_info; // Don't blink. Don't even blink. Blink and you're dead. loadLanguage('Who'); $context['credits_intro'] = '<strong><span style="color:blue;">EosAlpha BBS</span></strong> is a software product based on the popular and successful <a href="http://www.simplemachines.org">Simple Machines Forum</a>, also known as simply SMF.<br> It started around mid-2011 as a fork of the then current code base of SMF 2.0 which had been released under a OSF compliant <a href="http://www.simplemachines.org/about/smf/license.php">BSD-style license</a> in June 2011. The goal is to create a new forum software with a fresh, modern and social touch. <br> <br> <dl><dt><strong>Developers</strong></dt> <dd>Alex "Silvercircle" Vie, Annika "Velvet" Ostrovsky</dd></dl>'; $context['credits'] = array(array('pretext' => $txt['credits_intro'], 'title' => $txt['credits_team'], 'groups' => array(array('title' => $txt['credits_groups_ps'], 'members' => array('Michael "Oldiesmann" Eshom', 'Amacythe', 'Jeremy "SleePy" Darwood', 'Justin "metallica48423" O\'Leary')), array('title' => $txt['credits_groups_dev'], 'members' => array('Norv', 'Aaron van Geffen', 'Antechinus', 'Bjoern "Bloc" Kristiansen', 'Hendrik Jan "Compuart" Visser', 'Juan "JayBachatero" Hernandez', 'Karl "RegularExpression" Benson', $user_info['is_admin'] ? 'Matt "Grudge" Wolf' : 'Grudge', 'Michael "Thantos" Miller', 'Selman "[SiNaN]" Eser', 'Theodore "Orstio" Hildebrandt', 'Thorsten "TE" Eurich', 'winrules')), array('title' => $txt['credits_groups_support'], 'members' => array('JimM', 'Adish "(F.L.A.M.E.R)" Patel', 'Aleksi "Lex" Kilpinen', 'Ben Scott', 'Bigguy', 'CapadY', 'Chas Large', 'Duncan85', 'Eliana Tamerin', 'Fiery', 'gbsothere', 'Harro', 'Huw', 'Jan-Olof "Owdy" Eriksson', 'Jeremy "jerm" Strike', 'Jessica "Miss All Sunday" Gonzales', 'K@', 'Kevin "greyknight17" Hou', 'KGIII', 'Kill Em All', 'Mattitude', 'Mashby', 'Mick G.', 'Michele "Illori" Davis', 'MrPhil', 'Nick "Fizzy" Dyer', 'Nick "Ha²"', 'Paul_Pauline', 'Piro "Sarge" Dhima', 'Rumbaar', 'Pitti', 'RedOne', 'S-Ace', 'Wade "sησω" Poulsen', 'xenovanis')), array('title' => $txt['credits_groups_customize'], 'members' => array('Brad "IchBin™" Grow', 'ディン1031', 'Brannon "B" Hall', 'Bryan "Runic" Deakin', 'Bulakbol', 'Colin "Shadow82x" Blaber', 'Daniel15', 'Eren Yasarkurt', 'Gary M. Gadsdon', 'Jason "JBlaze" Clemons', 'Jerry', 'Jonathan "vbgamer45" Valentin', 'Kays', 'Killer Possum', 'Kirby', 'Matt "SlammedDime" Zuba', 'Matthew "Labradoodle-360" Kerle', 'Nibogo', 'Niko', 'Peter "Arantor" Spicer', 'snork13', 'Spuds', 'Steven "Fustrate" Hoffman', 'Joey "Tyrsson" Smith')), array('title' => $txt['credits_groups_docs'], 'members' => array('Joshua "groundup" Dickerson', 'AngellinaBelle', 'Daniel Diehl', 'Dannii Willis', 'emanuele', 'Graeme Spence', 'Jack "akabugeyes" Thorsen', 'Jade Elizabeth Trainor', 'Peter Duggan')), array('title' => $txt['credits_groups_marketing'], 'members' => array('Kindred', 'Marcus "cσσкιє мσηѕтєя" Forsberg', 'Ralph "[n3rve]" Otowo', 'rickC', 'Tony Reid')), array('title' => $txt['credits_groups_internationalizers'], 'members' => array('Relyana', 'Akyhne', 'GravuTrad')), array('title' => $txt['credits_groups_servers'], 'members' => array('Derek Schwab', 'Liroy "CoreISP" van Hoewijk'))))); // Give the translators some credit for their hard work. if (!empty($txt['translation_credits'])) { $context['credits'][] = array('title' => $txt['credits_groups_translation'], 'groups' => array(array('title' => $txt['credits_groups_translation'], 'members' => $txt['translation_credits']))); } $context['credits'][] = array('title' => $txt['credits_special'], 'posttext' => $txt['credits_anyone'], 'groups' => array(array('title' => $txt['credits_groups_consultants'], 'members' => array('Brett Flannigan', 'Mark Rose', 'René-Gilles "Nao 尚" Deberdt')), array('title' => $txt['credits_groups_beta'], 'members' => array($txt['credits_beta_message'])), array('title' => $txt['credits_groups_translators'], 'members' => array($txt['credits_translators_message'])), array('title' => $txt['credits_groups_founder'], 'members' => array('Unknown W. "[Unknown]" Brackets')), array('title' => $txt['credits_groups_orignal_pm'], 'members' => array('Jeff Lewis', 'Joseph Fung', 'David Recordon')))); $context['copyrights'] = array('smf' => sprintf($forum_copyright, $forum_version), 'mods' => array()); foreach ($context['credits'] as &$credit) { foreach ($credit['groups'] as &$group) { if (count($group['members']) > 2) { $group['last_peep'] = array_pop($group['members']); } } } if (!$in_admin) { EoS_Smarty::loadTemplate('credits'); $context['robot_no_index'] = true; $context['page_title'] = $txt['credits']; } }
function ReportToModerator() { global $txt, $topic, $sourcedir, $modSettings, $user_info, $context, $smcFunc; $context['robot_no_index'] = true; // You can't use this if it's off or you are not allowed to do it. isAllowedTo('report_any'); // If they're posting, it should be processed by ReportToModerator2. if ((isset($_POST[$context['session_var']]) || isset($_POST['submit'])) && empty($context['post_errors'])) { ReportToModerator2(); } // We need a message ID to check! if (empty($_REQUEST['msg']) && empty($_REQUEST['mid'])) { fatal_lang_error('no_access', false); } // For compatibility, accept mid, but we should be using msg. (not the flavor kind!) $_REQUEST['msg'] = empty($_REQUEST['msg']) ? (int) $_REQUEST['mid'] : (int) $_REQUEST['msg']; // Check the message's ID - don't want anyone reporting a post they can't even see! $result = smf_db_query(' SELECT m.id_msg, m.id_member, t.id_member_started FROM {db_prefix}messages AS m INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic}) WHERE m.id_msg = {int:id_msg} AND m.id_topic = {int:current_topic} LIMIT 1', array('current_topic' => $topic, 'id_msg' => $_REQUEST['msg'])); if (mysql_num_rows($result) == 0) { fatal_lang_error('no_board', false); } list($_REQUEST['msg'], $member, $starter) = mysql_fetch_row($result); mysql_free_result($result); // Do we need to show the visual verification image? $context['require_verification'] = $user_info['is_guest'] && !empty($modSettings['guests_report_require_captcha']); if ($context['require_verification']) { require_once $sourcedir . '/lib/Subs-Editor.php'; $verificationOptions = array('id' => 'report'); $context['require_verification'] = create_control_verification($verificationOptions); $context['visual_verification_id'] = $verificationOptions['id']; } // Show the inputs for the comment, etc. loadLanguage('Post'); EoS_Smarty::loadTemplate('topic/send_or_report'); EoS_Smarty::getConfigInstance()->registerHookTemplate('send_report_content_area', 'topic/reporttm'); $context['comment_body'] = !isset($_POST['comment']) ? '' : trim($_POST['comment']); $context['email_address'] = !isset($_POST['email']) ? '' : trim($_POST['email']); // This is here so that the user could, in theory, be redirected back to the topic. $context['start'] = $_REQUEST['start']; $context['message_id'] = $_REQUEST['msg']; $context['page_title'] = $txt['report_to_mod']; $context['sub_template'] = 'report'; }
function MoveTopic() { global $txt, $board, $topic, $user_info, $context, $language, $scripturl, $settings, $smcFunc, $modSettings; if (empty($topic)) { fatal_lang_error('no_access', false); } $request = smf_db_query(' SELECT t.id_member_started, ms.subject, t.approved FROM {db_prefix}topics AS t INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg) WHERE t.id_topic = {int:current_topic} LIMIT 1', array('current_topic' => $topic)); list($id_member_started, $context['subject'], $context['is_approved']) = mysql_fetch_row($request); mysql_free_result($request); // Can they see it - if not approved? if ($modSettings['postmod_active'] && !$context['is_approved']) { isAllowedTo('approve_posts'); } // Permission check! // !!! if (!allowedTo('move_any')) { if ($id_member_started == $user_info['id']) { isAllowedTo('move_own'); //$boards = array_merge(boardsAllowedTo('move_own'), boardsAllowedTo('move_any')); } else { isAllowedTo('move_any'); } } //else //$boards = boardsAllowedTo('move_any'); EoS_Smarty::loadTemplate('topic/movetopic'); // Get a list of boards this moderator can move to. $request = smf_db_query(' SELECT b.id_board, b.name, b.child_level, c.name AS cat_name, c.id_cat FROM {db_prefix}boards AS b LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat) WHERE {query_see_board} AND b.redirect = {string:blank_redirect} AND b.id_board != {int:current_board}', array('blank_redirect' => '', 'current_board' => $board)); $context['boards'] = array(); while ($row = mysql_fetch_assoc($request)) { if (!isset($context['categories'][$row['id_cat']])) { $context['categories'][$row['id_cat']] = array('name' => strip_tags($row['cat_name']), 'boards' => array()); } $context['categories'][$row['id_cat']]['boards'][] = array('id' => $row['id_board'], 'name' => strip_tags($row['name']), 'category' => strip_tags($row['cat_name']), 'child_level' => $row['child_level'], 'selected' => !empty($_SESSION['move_to_topic']) && $_SESSION['move_to_topic'] == $row['id_board'] && $row['id_board'] != $board); } mysql_free_result($request); if (empty($context['categories'])) { fatal_lang_error('moveto_noboards', false); } $context['page_title'] = $txt['move_topic']; $context['linktree'][] = array('url' => $scripturl . '?topic=' . $topic . '.0', 'name' => $context['subject'], 'extra_before' => $settings['linktree_inline'] ? $txt['topic'] . ': ' : ''); $context['linktree'][] = array('name' => $txt['move_topic']); $context['back_to_topic'] = isset($_REQUEST['goback']); if ($user_info['language'] != $language) { loadLanguage('index', $language); $temp = $txt['movetopic_default']; loadLanguage('index'); $txt['movetopic_default'] = $temp; } // Register this form and get a sequence number in $context. checkSubmitOnce('register'); }
function Login2() { global $txt, $scripturl, $user_info, $user_settings, $smcFunc; global $cookiename, $maintenance, $modSettings, $context, $sc, $sourcedir; // Load cookie authentication stuff. require_once $sourcedir . '/lib/Subs-Auth.php'; if (isset($_GET['sa']) && $_GET['sa'] == 'salt' && !$user_info['is_guest']) { if (isset($_COOKIE[$cookiename]) && preg_match('~^a:[34]:\\{i:0;(i:\\d{1,6}|s:[1-8]:"\\d{1,8}");i:1;s:(0|40):"([a-fA-F0-9]{40})?";i:2;[id]:\\d{1,14};(i:3;i:\\d;)?\\}$~', $_COOKIE[$cookiename]) === 1) { list(, , $timeout) = @unserialize($_COOKIE[$cookiename]); } elseif (isset($_SESSION['login_' . $cookiename])) { list(, , $timeout) = @unserialize($_SESSION['login_' . $cookiename]); } else { trigger_error('Login2(): Cannot be logged in without a session or cookie', E_USER_ERROR); } $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4); updateMemberData($user_info['id'], array('password_salt' => $user_settings['password_salt'])); setLoginCookie($timeout - time(), $user_info['id'], sha1($user_settings['passwd'] . $user_settings['password_salt'])); redirectexit('action=login2;sa=check;member=' . $user_info['id'], $context['server']['needs_login_fix']); } elseif (isset($_GET['sa']) && $_GET['sa'] == 'check') { // Strike! You're outta there! if ($_GET['member'] != $user_info['id']) { fatal_lang_error('login_cookie_error', false); } // Some whitelisting for login_url... if (empty($_SESSION['login_url'])) { redirectexit(); } else { // Best not to clutter the session data too much... $temp = $_SESSION['login_url']; unset($_SESSION['login_url']); redirectexit($temp); } } // Beyond this point you are assumed to be a guest trying to login. if (!$user_info['is_guest']) { redirectexit(); } // Are you guessing with a script? spamProtection('login'); // Set the login_url if it's not already set (but careful not to send us to an attachment). if (empty($_SESSION['login_url']) && isset($_SESSION['old_url']) && strpos($_SESSION['old_url'], 'dlattach') === false && preg_match('~(board|topic)[=,]~', $_SESSION['old_url']) != 0) { $_SESSION['login_url'] = $_SESSION['old_url']; } // Been guessing a lot, haven't we? if (isset($_SESSION['failed_login']) && $_SESSION['failed_login'] >= $modSettings['failed_login_threshold'] * 3) { fatal_lang_error('login_threshold_fail', 'critical'); } // Set up the cookie length. (if it's invalid, just fall through and use the default.) if (isset($_POST['cookieneverexp']) || !empty($_POST['cookielength']) && $_POST['cookielength'] == -1) { $modSettings['cookieTime'] = 3153600; } elseif (!empty($_POST['cookielength']) && ($_POST['cookielength'] >= 1 || $_POST['cookielength'] <= 525600)) { $modSettings['cookieTime'] = (int) $_POST['cookielength']; } loadLanguage('Login'); EoS_Smarty::loadTemplate('generic_skeleton'); EoS_Smarty::getConfigInstance()->registerHookTemplate('generic_content_area', 'loginout/login'); // Set up the default/fallback stuff. $context['default_username'] = isset($_POST['user']) ? preg_replace('~&#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', htmlspecialchars($_POST['user'])) : ''; $context['default_password'] = ''; $context['never_expire'] = $modSettings['cookieTime'] == 525600 || $modSettings['cookieTime'] == 3153600; $context['login_errors'] = array($txt['error_occured']); $context['page_title'] = $txt['login']; // Add the login chain to the link tree. $context['linktree'][] = array('url' => $scripturl . '?action=login', 'name' => $txt['login']); if (!empty($_POST['openid_identifier']) && !empty($modSettings['enableOpenID'])) { require_once $sourcedir . '/lib/Subs-OpenID.php'; if (($open_id = smf_openID_validate($_POST['openid_identifier'])) !== 'no_data') { return $open_id; } } // You forgot to type your username, dummy! if (!isset($_POST['user']) || $_POST['user'] == '') { $context['login_errors'] = array($txt['need_username']); return; } // Hmm... maybe 'admin' will login with no password. Uhh... NO! if ((!isset($_POST['passwrd']) || $_POST['passwrd'] == '') && (!isset($_POST['hash_passwrd']) || strlen($_POST['hash_passwrd']) != 40)) { $context['login_errors'] = array($txt['no_password']); return; } // No funky symbols either. if (preg_match('~[<>&"\'=\\\\]~', preg_replace('~(&#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~', '', $_POST['user'])) != 0) { $context['login_errors'] = array($txt['error_invalid_characters_username']); return; } // Are we using any sort of integration to validate the login? if (in_array('retry', HookAPI::callHook('integrate_validate_login', array($_POST['user'], isset($_POST['hash_passwrd']) && strlen($_POST['hash_passwrd']) == 40 ? $_POST['hash_passwrd'] : null, $modSettings['cookieTime'])), true)) { $context['login_errors'] = array($txt['login_hash_error']); $context['disable_login_hashing'] = true; return; } // Load the data up! $request = smf_db_query(' SELECT passwd, id_member, id_group, lngfile, is_activated, email_address, additional_groups, member_name, password_salt, openid_uri, passwd_flood FROM {db_prefix}members WHERE ' . 'member_name = {string:user_name}' . ' LIMIT 1', array('user_name' => $_POST['user'])); // Probably mistyped or their email, try it as an email address. (member_name first, though!) if (mysql_num_rows($request) == 0) { mysql_free_result($request); $request = smf_db_query(' SELECT passwd, id_member, id_group, lngfile, is_activated, email_address, additional_groups, member_name, password_salt, openid_uri, passwd_flood FROM {db_prefix}members WHERE email_address = {string:user_name} LIMIT 1', array('user_name' => $_POST['user'])); // Let them try again, it didn't match anything... if (mysql_num_rows($request) == 0) { $context['login_errors'] = array($txt['username_no_exist']); return; } } $user_settings = mysql_fetch_assoc($request); mysql_free_result($request); // Figure out the password using SMF's encryption - if what they typed is right. if (isset($_POST['hash_passwrd']) && strlen($_POST['hash_passwrd']) == 40) { // Needs upgrading? if (strlen($user_settings['passwd']) != 40) { $context['login_errors'] = array($txt['login_hash_error']); $context['disable_login_hashing'] = true; unset($user_settings); return; } elseif ($_POST['hash_passwrd'] == sha1($user_settings['passwd'] . $sc)) { $sha_passwd = $user_settings['passwd']; } else { // Don't allow this! validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood']); $_SESSION['failed_login'] = @$_SESSION['failed_login'] + 1; if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold']) { redirectexit('action=reminder'); } else { log_error($txt['incorrect_password'] . ' - <span class="remove">' . $user_settings['member_name'] . '</span>', 'user'); $context['disable_login_hashing'] = true; $context['login_errors'] = array($txt['incorrect_password']); unset($user_settings); return; } } } else { $sha_passwd = sha1(strtolower($user_settings['member_name']) . un_htmlspecialchars($_POST['passwrd'])); } // Bad password! Thought you could fool the database?! if ($user_settings['passwd'] != $sha_passwd) { // Let's be cautious, no hacking please. thanx. validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood']); // Maybe we were too hasty... let's try some other authentication methods. $other_passwords = array(); // None of the below cases will be used most of the time (because the salt is normally set.) if ($user_settings['password_salt'] == '') { // YaBB SE, Discus, MD5 (used a lot), SHA-1 (used some), SMF 1.0.x, IkonBoard, and none at all. $other_passwords[] = crypt($_POST['passwrd'], substr($_POST['passwrd'], 0, 2)); $other_passwords[] = crypt($_POST['passwrd'], substr($user_settings['passwd'], 0, 2)); $other_passwords[] = md5($_POST['passwrd']); $other_passwords[] = sha1($_POST['passwrd']); $other_passwords[] = md5_hmac($_POST['passwrd'], strtolower($user_settings['member_name'])); $other_passwords[] = md5($_POST['passwrd'] . strtolower($user_settings['member_name'])); $other_passwords[] = md5(md5($_POST['passwrd'])); $other_passwords[] = $_POST['passwrd']; // This one is a strange one... MyPHP, crypt() on the MD5 hash. $other_passwords[] = crypt(md5($_POST['passwrd']), md5($_POST['passwrd'])); // Snitz style - SHA-256. Technically, this is a downgrade, but most PHP configurations don't support sha256 anyway. if (strlen($user_settings['passwd']) == 64 && function_exists('mhash') && defined('MHASH_SHA256')) { $other_passwords[] = bin2hex(mhash(MHASH_SHA256, $_POST['passwrd'])); } // phpBB3 users new hashing. We now support it as well ;). $other_passwords[] = phpBB3_password_check($_POST['passwrd'], $user_settings['passwd']); // APBoard 2 Login Method. $other_passwords[] = md5(crypt($_POST['passwrd'], 'CRYPT_MD5')); } elseif (strlen($user_settings['passwd']) == 32) { // vBulletin 3 style hashing? Let's welcome them with open arms \o/. $other_passwords[] = md5(md5($_POST['passwrd']) . $user_settings['password_salt']); // Hmm.. p'raps it's Invision 2 style? $other_passwords[] = md5(md5($user_settings['password_salt']) . md5($_POST['passwrd'])); // Some common md5 ones. $other_passwords[] = md5($user_settings['password_salt'] . $_POST['passwrd']); $other_passwords[] = md5($_POST['passwrd'] . $user_settings['password_salt']); } elseif (strlen($user_settings['passwd']) == 40) { // Maybe they are using a hash from before the password fix. $other_passwords[] = sha1(strtolower($user_settings['member_name']) . un_htmlspecialchars($_POST['passwrd'])); // BurningBoard3 style of hashing. $other_passwords[] = sha1($user_settings['password_salt'] . sha1($user_settings['password_salt'] . sha1($_POST['passwrd']))); // Perhaps we converted to UTF-8 and have a valid password being hashed differently. if ($context['character_set'] == 'utf8' && !empty($modSettings['previousCharacterSet']) && $modSettings['previousCharacterSet'] != 'utf8') { // Try iconv first, for no particular reason. if (function_exists('iconv')) { $other_passwords['iconv'] = sha1(strtolower(iconv('UTF-8', $modSettings['previousCharacterSet'], $user_settings['member_name'])) . un_htmlspecialchars(iconv('UTF-8', $modSettings['previousCharacterSet'], $_POST['passwrd']))); } // Say it aint so, iconv failed! if (empty($other_passwords['iconv']) && function_exists('mb_convert_encoding')) { $other_passwords[] = sha1(strtolower(mb_convert_encoding($user_settings['member_name'], 'UTF-8', $modSettings['previousCharacterSet'])) . un_htmlspecialchars(mb_convert_encoding($_POST['passwrd'], 'UTF-8', $modSettings['previousCharacterSet']))); } } } // SMF's sha1 function can give a funny result on Linux (Not our fault!). If we've now got the real one let the old one be valid! if (strpos(strtolower(PHP_OS), 'win') !== 0) { require_once $sourcedir . '/lib/Subs-Compat.php'; $other_passwords[] = sha1_smf(strtolower($user_settings['member_name']) . un_htmlspecialchars($_POST['passwrd'])); } // Whichever encryption it was using, let's make it use SMF's now ;). if (in_array($user_settings['passwd'], $other_passwords)) { $user_settings['passwd'] = $sha_passwd; $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4); // Update the password and set up the hash. updateMemberData($user_settings['id_member'], array('passwd' => $user_settings['passwd'], 'password_salt' => $user_settings['password_salt'], 'passwd_flood' => '')); } else { // They've messed up again - keep a count to see if they need a hand. $_SESSION['failed_login'] = @$_SESSION['failed_login'] + 1; // Hmm... don't remember it, do you? Here, try the password reminder ;). if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold']) { redirectexit('action=reminder'); } else { // Log an error so we know that it didn't go well in the error log. log_error($txt['incorrect_password'] . ' - <span class="remove">' . $user_settings['member_name'] . '</span>', 'user'); $context['login_errors'] = array($txt['incorrect_password']); return; } } } elseif (!empty($user_settings['passwd_flood'])) { // Let's be sure they weren't a little hacker. validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood'], true); // If we got here then we can reset the flood counter. updateMemberData($user_settings['id_member'], array('passwd_flood' => '')); } // Correct password, but they've got no salt; fix it! if ($user_settings['password_salt'] == '') { $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4); updateMemberData($user_settings['id_member'], array('password_salt' => $user_settings['password_salt'])); } // Check their activation status. if (!checkActivation()) { return; } DoLogin(); }
function GroupRequests() { global $txt, $context, $scripturl, $user_info, $sourcedir, $smcFunc, $modSettings, $language; //if(isset($_REQUEST['action']) && $_REQUEST['action'] === 'moderate') EoS_Smarty::loadTemplate('modcenter/modcenter_base'); EoS_Smarty::getConfigInstance()->registerHookTemplate('modcenter_content_area', 'modcenter/list_groups'); // Set up the template stuff... $context['page_title'] = $txt['mc_group_requests']; //$context['sub_template'] = 'show_list'; // Verify we can be here. if ($user_info['mod_cache']['gq'] == '0=1') { isAllowedTo('manage_membergroups'); } // Normally, we act normally... $where = $user_info['mod_cache']['gq'] == '1=1' || $user_info['mod_cache']['gq'] == '0=1' ? $user_info['mod_cache']['gq'] : 'lgr.' . $user_info['mod_cache']['gq']; $where_parameters = array(); // We've submitted? if (isset($_POST[$context['session_var']]) && !empty($_POST['groupr']) && !empty($_POST['req_action'])) { checkSession('post'); // Clean the values. foreach ($_POST['groupr'] as $k => $request) { $_POST['groupr'][$k] = (int) $request; } // If we are giving a reason (And why shouldn't we?), then we don't actually do much. if ($_POST['req_action'] == 'reason') { // Different sub template... $context['sub_template'] = 'group_request_reason'; // And a limitation. We don't care that the page number bit makes no sense, as we don't need it! $where .= ' AND lgr.id_request IN ({array_int:request_ids})'; $where_parameters['request_ids'] = $_POST['groupr']; $context['group_requests'] = list_getGroupRequests(0, $modSettings['defaultMaxMessages'], 'lgr.id_request', $where, $where_parameters); // Let obExit etc sort things out. obExit(); } else { // Get the details of all the members concerned... $request = smf_db_query(' SELECT lgr.id_request, lgr.id_member, lgr.id_group, mem.email_address, mem.id_group AS primary_group, mem.additional_groups AS additional_groups, mem.lngfile, mem.member_name, mem.notify_types, mg.hidden, mg.group_name FROM {db_prefix}log_group_requests AS lgr INNER JOIN {db_prefix}members AS mem ON (mem.id_member = lgr.id_member) INNER JOIN {db_prefix}membergroups AS mg ON (mg.id_group = lgr.id_group) WHERE ' . $where . ' AND lgr.id_request IN ({array_int:request_list}) ORDER BY mem.lngfile', array('request_list' => $_POST['groupr'])); $email_details = array(); $group_changes = array(); while ($row = mysql_fetch_assoc($request)) { $row['lngfile'] = empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']; // If we are approving work out what their new group is. if ($_POST['req_action'] == 'approve') { // For people with more than one request at once. if (isset($group_changes[$row['id_member']])) { $row['additional_groups'] = $group_changes[$row['id_member']]['add']; $row['primary_group'] = $group_changes[$row['id_member']]['primary']; } else { $row['additional_groups'] = explode(',', $row['additional_groups']); } // Don't have it already? if ($row['primary_group'] == $row['id_group'] || in_array($row['id_group'], $row['additional_groups'])) { continue; } // Should it become their primary? if ($row['primary_group'] == 0 && $row['hidden'] == 0) { $row['primary_group'] = $row['id_group']; } else { $row['additional_groups'][] = $row['id_group']; } // Add them to the group master list. $group_changes[$row['id_member']] = array('primary' => $row['primary_group'], 'add' => $row['additional_groups']); } // Add required information to email them. if ($row['notify_types'] != 4) { $email_details[] = array('rid' => $row['id_request'], 'member_id' => $row['id_member'], 'member_name' => $row['member_name'], 'group_id' => $row['id_group'], 'group_name' => $row['group_name'], 'email' => $row['email_address'], 'language' => $row['lngfile']); } } mysql_free_result($request); // Remove the evidence... smf_db_query(' DELETE FROM {db_prefix}log_group_requests WHERE id_request IN ({array_int:request_list})', array('request_list' => $_POST['groupr'])); // Ensure everyone who is online gets their changes right away. updateSettings(array('settings_updated' => time())); if (!empty($email_details)) { require_once $sourcedir . '/lib/Subs-Post.php'; // They are being approved? if ($_POST['req_action'] == 'approve') { // Make the group changes. foreach ($group_changes as $id => $groups) { // Sanity check! foreach ($groups['add'] as $key => $value) { if ($value == 0 || trim($value) == '') { unset($groups['add'][$key]); } } smf_db_query(' UPDATE {db_prefix}members SET id_group = {int:primary_group}, additional_groups = {string:additional_groups} WHERE id_member = {int:selected_member}', array('primary_group' => $groups['primary'], 'selected_member' => $id, 'additional_groups' => implode(',', $groups['add']))); } $lastLng = $user_info['language']; foreach ($email_details as $email) { $replacements = array('USERNAME' => $email['member_name'], 'GROUPNAME' => $email['group_name']); $emaildata = loadEmailTemplate('mc_group_approve', $replacements, $email['language']); sendmail($email['email'], $emaildata['subject'], $emaildata['body'], null, null, false, 2); } } else { // Same as for approving, kind of. $lastLng = $user_info['language']; foreach ($email_details as $email) { $custom_reason = isset($_POST['groupreason']) && isset($_POST['groupreason'][$email['rid']]) ? $_POST['groupreason'][$email['rid']] : ''; $replacements = array('USERNAME' => $email['member_name'], 'GROUPNAME' => $email['group_name']); if (!empty($custom_reason)) { $replacements['REASON'] = $custom_reason; } $emaildata = loadEmailTemplate(empty($custom_reason) ? 'mc_group_reject' : 'mc_group_reject_reason', $replacements, $email['language']); sendmail($email['email'], $emaildata['subject'], $emaildata['body'], null, null, false, 2); } } } // Restore the current language. loadLanguage('ModerationCenter'); } } // We're going to want this for making our list. require_once $sourcedir . '/lib/Subs-List.php'; // This is all the information required for a group listing. $listOptions = array('id' => 'group_request_list', 'title' => $txt['mc_group_requests'], 'width' => '100%', 'items_per_page' => $modSettings['defaultMaxMessages'], 'no_items_label' => $txt['mc_groupr_none_found'], 'base_href' => $scripturl . '?action=groups;sa=requests', 'default_sort_col' => 'member', 'get_items' => array('function' => 'list_getGroupRequests', 'params' => array($where, $where_parameters)), 'get_count' => array('function' => 'list_getGroupRequestCount', 'params' => array($where, $where_parameters)), 'columns' => array('member' => array('header' => array('value' => $txt['mc_groupr_member']), 'data' => array('db' => 'member_link'), 'sort' => array('default' => 'mem.member_name', 'reverse' => 'mem.member_name DESC')), 'group' => array('header' => array('value' => $txt['mc_groupr_group']), 'data' => array('db' => 'group_link'), 'sort' => array('default' => 'mg.group_name', 'reverse' => 'mg.group_name DESC')), 'reason' => array('header' => array('value' => $txt['mc_groupr_reason']), 'data' => array('db' => 'reason')), 'action' => array('header' => array('value' => '<input type="checkbox" class="input_check" onclick="invertAll(this, this.form);" />', 'style' => 'width: 4%;'), 'data' => array('sprintf' => array('format' => '<input type="checkbox" name="groupr[]" value="%1$d" class="input_check" />', 'params' => array('id' => false)), 'style' => 'text-align: center;'))), 'form' => array('href' => $scripturl . '?action=groups;sa=requests', 'include_sort' => true, 'include_start' => true, 'hidden_fields' => array($context['session_var'] => $context['session_id'])), 'additional_rows' => array(array('position' => 'bottom_of_list', 'value' => ' <select name="req_action" onchange="if (this.value != 0 && (this.value == \'reason\' || confirm(\'' . $txt['mc_groupr_warning'] . '\'))) this.form.submit();"> <option value="0">' . $txt['with_selected'] . ':</option> <option value="0">---------------------</option> <option value="approve">' . $txt['mc_groupr_approve'] . '</option> <option value="reject">' . $txt['mc_groupr_reject'] . '</option> <option value="reason">' . $txt['mc_groupr_reject_w_reason'] . '</option> </select> <input type="submit" name="go" value="' . $txt['go'] . '" onclick="var sel = document.getElementById(\'req_action\'); if (sel.value != 0 && sel.value != \'reason\' && !confirm(\'' . $txt['mc_groupr_warning'] . '\')) return false;" class="button_submit" />', 'align' => 'right'))); // Create the request list. createList($listOptions); $context['default_list'] = 'group_request_list'; }
function VerificationCode() { global $sourcedir, $context, $scripturl; $verification_id = isset($_GET['vid']) ? $_GET['vid'] : ''; $code = $verification_id && isset($_SESSION[$verification_id . '_vv']) ? $_SESSION[$verification_id . '_vv']['code'] : (isset($_SESSION['visual_verification_code']) ? $_SESSION['visual_verification_code'] : ''); // Somehow no code was generated or the session was lost. if (empty($code)) { header('Content-Type: image/gif'); die("GIF89a€!ù,D;"); } elseif (isset($_REQUEST['sound'])) { loadLanguage('Login'); EoS_Smarty::loadTemplate('generics/verification_sound'); $context['verification_sound_href'] = $scripturl . '?action=verificationcode;rand=' . md5(mt_rand()) . ($verification_id ? ';vid=' . $verification_id : '') . ';format=.wav'; $context['template_layers'] = array(); obExit(); } elseif (empty($_REQUEST['format'])) { require_once $sourcedir . '/lib/Subs-Graphics.php'; if (in_array('gd', get_loaded_extensions()) && !showCodeImage($code)) { header('HTTP/1.1 400 Bad Request'); } elseif (isset($_REQUEST['letter'])) { $_REQUEST['letter'] = (int) $_REQUEST['letter']; if ($_REQUEST['letter'] > 0 && $_REQUEST['letter'] <= strlen($code) && !showLetterImage(strtolower($code[$_REQUEST['letter'] - 1]))) { header('Content-Type: image/gif'); die("GIF89a€!ù,D;"); } } else { header('Content-Type: image/gif'); die("GIF89a€!ù,D;"); } } elseif ($_REQUEST['format'] === '.wav') { require_once $sourcedir . '/lib/Subs-Sound.php'; if (!createWaveFile($code)) { header('HTTP/1.1 400 Bad Request'); } } // We all die one day... die; }
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']) . ' ' : ''; $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'] .= ' <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('&' => '&'))), '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); }
function setup_fatal_error_context($error_message) { global $context, $txt, $ssi_on_error_method; static $level = 0; // Attempt to prevent a recursive loop. ++$level; if ($level > 1) { return false; } // Maybe they came from dlattach or similar? if (SMF != 'SSI' && empty($context['theme_loaded'])) { loadTheme(); } // Don't bother indexing errors mate... $context['robot_no_index'] = true; if (!isset($context['error_title'])) { $context['error_title'] = $txt['error_occured']; } $context['error_message'] = isset($context['error_message']) ? $context['error_message'] : $error_message; if (empty($context['page_title'])) { $context['page_title'] = $context['error_title']; } EoS_Smarty::resetTemplates(); // discard all templates loaded so far. We don't need them any longer EoS_Smarty::loadTemplate('errors'); // If this is SSI, what do they want us to do? if (SMF == 'SSI') { if (!empty($ssi_on_error_method) && $ssi_on_error_method !== true && is_callable($ssi_on_error_method)) { call_user_func($ssi_on_error_method); } elseif (empty($ssi_on_error_method) || $ssi_on_error_method !== true) { loadSubTemplate('fatal_error'); } // No layers? if (empty($ssi_on_error_method) || $ssi_on_error_method !== true) { exit; } } // We want whatever for the header, and a footer. (footer includes sub template!) obExit(null, true, false, true); /* DO NOT IGNORE: If you are creating a bridge to SMF or modifying this function, you MUST make ABSOLUTELY SURE that this function quits and DOES NOT RETURN TO NORMAL PROGRAM FLOW. Otherwise, security error messages will not be shown, and your forum will be in a very easily hackable state. */ trigger_error('Hacking attempt...', E_USER_ERROR); }
/** * @param $mid = int message (or content) id * * handle the ajax request for rating a post. Also handles deletion of * * TODO: remove likes from the database when a user is deleted * TODO: make it work without AJAX and JavaScript */ public static function rateIt($mid) { global $context, $user_info, $sourcedir, $txt, $modSettings; $total = array(); $content_type = 1; // > post content type, we should define them elsewhere later when we have more than just this one if ((int) $mid > 0) { $uid = $user_info['id']; $remove_it = isset($_REQUEST['remove']) ? true : false; $repair = isset($_REQUEST['repair']) && $user_info['is_admin'] ? true : false; $is_xmlreq = $_REQUEST['action'] == 'xmlhttp' ? true : false; $update_mode = false; $like_type = isset($_REQUEST['r']) && (int) $_REQUEST['r'] > 0 ? $_REQUEST['r'] : '1'; $comment = isset($_REQUEST['comment']) ? strip_tags($_REQUEST['comment']) : ''; $rtypes = explode(',', $like_type); foreach ($rtypes as $rtype) { if (!isset($modSettings['ratings'][$rtype])) { AjaxErrorMsg($txt['unknown_rating_type']); } } if ($user_info['is_guest']) { AjaxErrorMsg($txt['no_like_for_guests']); } $request = smf_db_query('SELECT m.id_msg, m.id_member, m.id_board, m.id_topic, m.subject, l.id_msg AS like_message, l.rtype, l.id_user FROM {db_prefix}messages AS m LEFT JOIN {db_prefix}likes AS l ON (l.id_msg = m.id_msg AND l.ctype = {int:content_type} AND l.id_user = {int:id_user}) WHERE m.id_msg = {int:id_msg} LIMIT 1', array('content_type' => $content_type, 'id_msg' => $mid, 'id_user' => $uid)); $row = mysql_fetch_assoc($request); mysql_free_result($request); $like_owner = $row['id_user']; if ($row['id_user'] > 0 && !$remove_it && !$repair) { // duplicate like (but not when removing it) AjaxErrorMsg($txt['like_verify_error']); } $like_receiver = $row['id_member']; EoS_Smarty::loadTemplate('xml_blocks'); $context['template_functions'] = 'rating_response'; $context['ratings_output']['mid'] = $mid; /* * this is a debugging feature and allows the admin to repair * the likes for a post. * it may go away at a later time. */ if ($repair) { if (!$user_info['is_admin']) { obExit(false); } $total = self::updateForContent($mid); $output = ''; self::generateOutput($total['status'], $output, $mid, $row['id_user'] > 0 ? $row['rtype'] : 0); // fix like stats for the like_giver and like_receiver. This might be a very slow query, but // since this feature will most likely go away, right now I do not care. /* smf_db_query('UPDATE {db_prefix}members AS m SET m.likes_given = (SELECT COUNT(l.id_user) FROM {db_prefix}likes AS l WHERE l.id_user = m.id_member), m.likes_received = (SELECT COUNT(l1.id_receiver) FROM {db_prefix}likes AS l1 WHERE l1.id_receiver = m.id_member) WHERE m.id_member = {int:owner} OR m.id_member = {int:receiver}', array('owner' => $like_owner, 'receiver' => $like_receiver)); */ invalidateMemberData(array($like_owner, $like_receiver)); if ($is_xmlreq) { $context['ratings_output']['output'] = $output; $context['ratings_output']['likebar'] = ''; $context['postratings'] = json_encode($context['ratings_output']); return; } else { redirectexit(); } } if ($like_receiver == $uid) { AjaxErrorMsg($txt['cannot_like_own']); } if (!allowedTo('like_give', $row['id_board'])) { // no permission to give likes in this board AjaxErrorMsg($txt['like_no_permission']); } if ($remove_it && $row['id_user'] > 0) { // remove a rating if ($like_owner == $uid) { smf_db_query('DELETE FROM {db_prefix}likes WHERE id_msg = {int:id_msg} AND id_user = {int:id_user} AND ctype = {int:ctype}', array('id_msg' => $mid, 'id_user' => $uid, 'ctype' => $content_type)); if ($like_receiver) { smf_db_query('UPDATE {db_prefix}members SET likes_received = likes_received - 1 WHERE id_member = {int:id_member}', array('id_member' => $like_receiver)); } smf_db_query('UPDATE {db_prefix}members SET likes_given = likes_given - 1 WHERE id_member = {int:id_member}', array('id_member' => $uid)); // if we remove a like (unlike) a post, also delete the corresponding activity smf_db_query('DELETE a.*, n.* FROM {db_prefix}log_activities AS a LEFT JOIN {db_prefix}log_notifications AS n ON(n.id_act = a.id_act) WHERE a.id_member = {int:id_member} AND a.id_type = 1 AND a.id_content = {int:id_content}', array('id_member' => $uid, 'id_content' => $mid)); $context['ratings_output']['likebar'] = self::$rate_bar; } } else { /* store the rating */ global $memberContext; if ($like_receiver) { // we do have a member, but still allow to like posts made by guests loadMemberData($like_receiver); // but banned users shall not receive likes loadMemberContext($like_receiver); } if ($like_receiver && !$memberContext[$like_receiver]['is_banned'] || $like_receiver == 0) { // posts by guests can be liked smf_db_query('INSERT INTO {db_prefix}likes(id_msg, id_user, id_receiver, updated, ctype, rtype, comment) VALUES({int:id_message}, {int:id_user}, {int:id_receiver}, {int:updated}, {int:ctype}, {string:rtype}, {string:comment})', array('id_message' => $mid, 'id_user' => $uid, 'id_receiver' => $like_receiver, 'updated' => time(), 'ctype' => $content_type, 'rtype' => $like_type, 'comment' => $comment)); if ($like_receiver) { smf_db_query('UPDATE {db_prefix}members SET likes_received = likes_received + 1 WHERE id_member = {int:id_member}', array('id_member' => $like_receiver)); } smf_db_query('UPDATE {db_prefix}members SET likes_given = likes_given + 1 WHERE id_member = {int:uid}', array('uid' => $uid)); $update_mode = $like_type; if ($modSettings['astream_active']) { @(require_once $sourcedir . '/lib/Subs-Activities.php'); aStreamAdd($uid, ACT_LIKE, array('member_name' => $context['user']['name'], 'topic_title' => $row['subject'], 'rtype' => $like_type), $row['id_board'], $row['id_topic'], $mid, $like_receiver); } } else { AjaxErrorMsg($txt['like_cannot_like']); } $context['ratings_output']['likebar'] = '<a rel="nofollow" class="givelike" data-fn="remove" href="#" data-id="' . $mid . '">' . $txt['unlike_label'] . '</a>'; } if ($user_info['is_admin'] && self::$show_repair_link) { $context['ratings_output']['likebar'] .= ' <a rel="nofollow" class="givelike" data-fn="repair" href="#" data-id="' . $mid . '">Repair ratings</a>'; } $total = self::updateForContent($mid); $output = ''; self::generateOutput($total['status'], $output, $mid, $update_mode); $context['ratings_output']['output'] = $output; $context['postratings'] = json_encode($context['ratings_output']); } }
/** * generate the rating widget */ function GetRatingWidget() { global $modSettings, $user_info, $context, $txt; if ($user_info['is_guest']) { AjaxErrorMsg($txt['no_like_for_guests']); } $xml = isset($_REQUEST['xml']); $content_id = isset($_REQUEST['id']) ? (int) $_REQUEST['id'] : 0; $ctype = isset($_REQUEST['c']) ? (int) $_REQUEST['c'] : 0; if (0 == $ctype || 0 == $content_id) { AjaxErrorMsg($txt['rating_invalid_params']); } if ($xml) { EoS_Smarty::loadTemplate('xml_blocks'); $context['template_functions'] = 'ratingwidget'; } else { EoS_Smarty::loadTemplate('ratings/widget'); } // todo: allow rating without ajax / js $request = smf_db_query('SELECT m.id_msg, m.id_topic, m.id_board FROM {db_prefix}messages AS m WHERE m.id_msg = {int:id} LIMIT 1', array('id' => $content_id)); list($id_msg, $id_topic, $id_board) = mysql_fetch_row($request); mysql_free_result($request); $context['result_count'] = 0; $uniques = array(true, false); foreach ($uniques as $uniqueness) { foreach ($modSettings['ratings'] as $key => $rating) { if ($rating['unique'] != $uniqueness) { continue; } if (Ratings::isAllowed($key, $id_board)) { $context['result_count']++; $context['ratings'][] = array('rtype' => (int) $key, 'label' => $rating['text'], 'unique' => $rating['unique']); } } } $context['content_id'] = $content_id; $context['json_data'] = htmlspecialchars(json_encode(array('id' => $content_id, 'error_text' => $txt['ratingwidget_error']))); }
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 = ' '; // 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'] .= ' '; } } 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('&' => '&'))), '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)); }