/** * Get a list of boards and categories used for the jumpto dropdown. */ public function action_jumpto() { global $context; // Find the boards/categories they can see. require_once SUBSDIR . '/Boards.subs.php'; $boardListOptions = array('selected_board' => isset($context['current_board']) ? $context['current_board'] : 0); $context += getBoardList($boardListOptions); // Make the board safe for display. foreach ($context['categories'] as $id_cat => $cat) { $context['categories'][$id_cat]['name'] = un_htmlspecialchars(strip_tags($cat['name'])); foreach ($cat['boards'] as $id_board => $board) { $context['categories'][$id_cat]['boards'][$id_board]['name'] = un_htmlspecialchars(strip_tags($board['name'])); } } $context['sub_template'] = 'jump_to'; }
function GetJumpTo() { global $user_info, $context, $smcFunc, $sourcedir; // Find the boards/cateogories they can see. require_once $sourcedir . '/Subs-MessageIndex.php'; $boardListOptions = array('use_permissions' => true, 'selected_board' => isset($context['current_board']) ? $context['current_board'] : 0); $context['jump_to'] = getBoardList($boardListOptions); // Make the board safe for display. foreach ($context['jump_to'] as $id_cat => $cat) { $context['jump_to'][$id_cat]['name'] = un_htmlspecialchars(strip_tags($cat['name'])); foreach ($cat['boards'] as $id_board => $board) { $context['jump_to'][$id_cat]['boards'][$id_board]['name'] = un_htmlspecialchars(strip_tags($board['name'])); } } $context['sub_template'] = 'jump_to'; }
public static function integrate_general_mod_settings(&$config_vars) { global $txt, $modSettings; loadLanguage('TwitterPoster'); if (empty($modSettings['twitter_new_topic'])) { $modSettings['twitter_new_topic'] = $txt['twitter_new_topic_default']; } $config_vars[] = array('title', 'twitter_configs'); $config_vars[] = array('text', 'consumer_key'); $config_vars[] = array('text', 'consumer_secret'); $config_vars[] = array('text', 'oauth_token'); $config_vars[] = array('text', 'oauth_token_secret'); $config_vars[] = array('large_text', 'twitter_new_topic', 'subtext' => $txt['twitter_new_topic_desc']); require_once SUBSDIR . '/Boards.subs.php'; $boardListOpt = array('access' => '-1', 'override_permissions' => true, 'not_redirection' => true, 'ignore' => !empty($modSettings['recycle_enable']) ? array($modSettings['recycle_board']) : null); $boards_structure = getBoardList($boardListOpt); $select = array(); foreach ($boards_structure['categories'] as $category) { if (empty($category['boards'])) { continue; } $select_tmp = array(); foreach ($category['boards'] as $board) { if ($board['allow']) { $select_tmp['b_' . $board['id']] = ($board['child_level'] > 0 ? str_repeat('=', $board['child_level']) . '> ' : '') . $board['name']; } } if (!empty($select_tmp)) { $select['c1_' . $category['id']] = '----------'; $select['c2_' . $category['id']] = $category['name']; $select['c3_' . $category['id']] = '----------'; $select += $select_tmp; } } if (empty($modSettings['twitter_select_boards'])) { $modSettings['twitter_select_boards'] = serialize(array()); } elseif (!is_array($modSettings['twitter_select_boards'])) { $tmp = unserialize($modSettings['twitter_select_boards']); $tmpr = array(); foreach ($tmp as $b) { $tmpr[] = 'b_' . $b; } $modSettings['twitter_select_boards'] = serialize($tmpr); } $config_vars[] = array('select', 'twitter_select_boards', $select, 'multiple' => true); }
/** * Browse all the reported posts... * @todo this needs to be given its own file? */ public function action_reportedPosts() { global $txt, $context, $scripturl, $user_info; loadTemplate('ModerationCenter'); require_once SUBSDIR . '/Moderation.subs.php'; // Put the open and closed options into tabs, because we can... $context[$context['moderation_menu_name']]['tab_data'] = array('title' => $txt['mc_reported_posts'], 'help' => '', 'description' => $txt['mc_reported_posts_desc']); // This comes under the umbrella of moderating posts. if ($user_info['mod_cache']['bq'] == '0=1') { isAllowedTo('moderate_forum'); } // Are they wanting to view a particular report? if (!empty($_REQUEST['report'])) { return $this->action_modReport(); } // Set up the comforting bits... $context['page_title'] = $txt['mc_reported_posts']; $context['sub_template'] = 'reported_posts'; // Are we viewing open or closed reports? $context['view_closed'] = isset($_GET['sa']) && $_GET['sa'] == 'closed' ? 1 : 0; // Are we doing any work? if ((isset($_GET['ignore']) || isset($_GET['close'])) && isset($_GET['rid'])) { checkSession('get'); $_GET['rid'] = (int) $_GET['rid']; // Update the report... if (isset($_GET['ignore'])) { updateReportsStatus((int) $_GET['rid'], 'ignore', (int) $_GET['ignore']); } elseif (isset($_GET['close'])) { updateReportsStatus((int) $_GET['rid'], 'close', (int) $_GET['close']); } // Time to update. updateSettings(array('last_mod_report_action' => time())); recountOpenReports(); } elseif (isset($_POST['close']) && isset($_POST['close_selected'])) { checkSession('post'); // All the ones to update... $toClose = array(); foreach ($_POST['close'] as $rid) { $toClose[] = (int) $rid; } if (!empty($toClose)) { updateReportsStatus($toClose, 'close', 1); // Time to update. updateSettings(array('last_mod_report_action' => time())); recountOpenReports(); } } // How many entries are we viewing? $context['total_reports'] = totalReports($context['view_closed']); // So, that means we can page index, yes? $context['page_index'] = constructPageIndex($scripturl . '?action=moderate;area=reports' . ($context['view_closed'] ? ';sa=closed' : ''), $_GET['start'], $context['total_reports'], 10); $context['start'] = $_GET['start']; // By George, that means we in a position to get the reports, golly good. $context['reports'] = getModReports($context['view_closed'], $context['start'], 10); $report_ids = array_keys($context['reports']); $report_boards_ids = array(); foreach ($context['reports'] as $row) { $context['reports'][$row['id_report']] = array('board' => $row['id_board'], 'id' => $row['id_report'], 'topic_href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'], 'report_href' => $scripturl . '?action=moderate;area=reports;report=' . $row['id_report'], 'author' => array('id' => $row['id_author'], 'name' => $row['author_name'], 'link' => $row['id_author'] ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_author'] . '">' . $row['author_name'] . '</a>' : $row['author_name'], 'href' => $scripturl . '?action=profile;u=' . $row['id_author']), 'comments' => array(), 'time_started' => standardTime($row['time_started']), 'last_updated' => standardTime($row['time_updated']), 'subject' => $row['subject'], 'body' => parse_bbc($row['body']), 'num_reports' => $row['num_reports'], 'closed' => $row['closed'], 'ignore' => $row['ignore_all'], 'buttons' => array('quickmod_check' => array('checkbox' => !$context['view_closed'], 'name' => 'close', 'value' => $row['id_report']), 'details' => array('href' => $scripturl . '?action=moderate;area=reports;report=' . $row['id_report'], 'text' => $txt['mc_reportedp_details']), 'ignore' => array('href' => $scripturl . '?action=moderate;area=reports' . ($context['view_closed'] ? ';sa=closed' : '') . ';ignore=' . (int) (!$row['ignore_all']) . ';rid=' . $row['id_report'] . ';start=' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'text' => $row['ignore_all'] ? $txt['mc_reportedp_unignore'] : $txt['mc_reportedp_ignore'], 'custom' => $row['ignore_all'] ? '' : 'onclick="return confirm(' . JavaScriptEscape($txt['mc_reportedp_ignore_confirm']) . ');"'), 'close' => array('href' => $scripturl . '?action=moderate;area=reports' . ($context['view_closed'] ? ';sa=closed' : '') . ';close=' . (int) (!$row['closed']) . ';rid=' . $row['id_report'] . ';start=' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'text' => $context['view_closed'] ? $txt['mc_reportedp_open'] : $txt['mc_reportedp_close']))); $report_boards_ids[] = $row['id_board']; } // Get the names of boards these topics are in. if (!empty($report_ids)) { require_once SUBSDIR . '/Boards.subs.php'; $board_names = getBoardList(array('included_boards' => $report_boards_ids), true); // Add the board name to the report array foreach ($context['reports'] as $id_report => $report) { if (!empty($board_names[$report['board']])) { $context['reports'][$id_report]['board_name'] = $board_names[$report['board']]['board_name']; } } } // Now get all the people who reported it. if (!empty($report_ids)) { $comments = getReportsUserComments($report_ids); foreach ($comments as $id_rep => $rows) { foreach ($rows as $row) { $context['reports'][$id_rep]['comments'][] = array('id' => $row['id_comment'], 'message' => $row['comment'], 'raw_time' => $row['time_sent'], 'time' => standardTime($row['time_sent']), 'html_time' => htmlTime($row['time_sent']), 'timestamp' => forum_time(true, $row['time_sent']), 'member' => array('id' => $row['id_member'], 'name' => empty($row['reporter']) ? $txt['guest'] : $row['reporter'], 'link' => $row['id_member'] ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['reporter'] . '</a>' : (empty($row['reporter']) ? $txt['guest'] : $row['reporter']), 'href' => $row['id_member'] ? $scripturl . '?action=profile;u=' . $row['id_member'] : '')); } } } }
function prepareSearchContext($reset = false) { global $txt, $modSettings, $scripturl, $user_info, $sourcedir; global $memberContext, $context, $settings, $options, $messages_request; global $boards_can, $participants, $smcFunc; // Remember which message this is. (ie. reply #83) static $counter = null; if ($counter == null || $reset) { $counter = $_REQUEST['start'] + 1; } // If the query returned false, bail. if ($messages_request == false) { return false; } // Start from the beginning... if ($reset) { return @$smcFunc['db_data_seek']($messages_request, 0); } // Attempt to get the next message. $message = $smcFunc['db_fetch_assoc']($messages_request); if (!$message) { return false; } // Can't have an empty subject can we? $message['subject'] = $message['subject'] != '' ? $message['subject'] : $txt['no_subject']; $message['first_subject'] = $message['first_subject'] != '' ? $message['first_subject'] : $txt['no_subject']; $message['last_subject'] = $message['last_subject'] != '' ? $message['last_subject'] : $txt['no_subject']; // If it couldn't load, or the user was a guest.... someday may be done with a guest table. if (!loadMemberContext($message['id_member'])) { // Notice this information isn't used anywhere else.... *cough guest table cough*. $memberContext[$message['id_member']]['name'] = $message['poster_name']; $memberContext[$message['id_member']]['id'] = 0; $memberContext[$message['id_member']]['group'] = $txt['guest_title']; $memberContext[$message['id_member']]['link'] = $message['poster_name']; $memberContext[$message['id_member']]['email'] = $message['poster_email']; } $memberContext[$message['id_member']]['ip'] = $message['poster_ip']; // Do the censor thang... censorText($message['body']); censorText($message['subject']); censorText($message['first_subject']); censorText($message['last_subject']); // Shorten this message if necessary. if ($context['compact']) { // Set the number of characters before and after the searched keyword. $charLimit = 50; $message['body'] = strtr($message['body'], array("\n" => ' ', '<br />' => "\n")); $message['body'] = parse_bbc($message['body'], $message['smileys_enabled'], $message['id_msg']); $message['body'] = strip_tags(strtr($message['body'], array('</div>' => '<br />', '</li>' => '<br />')), '<br>'); if ($smcFunc['strlen']($message['body']) > $charLimit) { if (empty($context['key_words'])) { $message['body'] = $smcFunc['substr']($message['body'], 0, $charLimit) . '<strong>...</strong>'; } else { $matchString = ''; $force_partial_word = false; foreach ($context['key_words'] as $keyword) { $keyword = preg_replace_callback('~(&#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~', 'entity_fix__callback', strtr($keyword, array('\\\'' => '\'', '&' => '&'))); if (preg_match('~[\'\\.,/@%&;:(){}\\[\\]_\\-+\\\\]$~', $keyword) != 0 || preg_match('~^[\'\\.,/@%&;:(){}\\[\\]_\\-+\\\\]~', $keyword) != 0) { $force_partial_word = true; } $matchString .= strtr(preg_quote($keyword, '/'), array('\\*' => '.+?')) . '|'; } $matchString = substr($matchString, 0, -1); $message['body'] = un_htmlspecialchars(strtr($message['body'], array(' ' => ' ', '<br />' => "\n", '[' => '[', ']' => ']', ':' => ':', '@' => '@'))); if (empty($modSettings['search_method']) || $force_partial_word) { preg_match_all('/([^\\s\\W]{' . $charLimit . '}[\\s\\W]|[\\s\\W].{0,' . $charLimit . '}?|^)(' . $matchString . ')(.{0,' . $charLimit . '}[\\s\\W]|[^\\s\\W]{' . $charLimit . '})/is' . ($context['utf8'] ? 'u' : ''), $message['body'], $matches); } else { preg_match_all('/([^\\s\\W]{' . $charLimit . '}[\\s\\W]|[\\s\\W].{0,' . $charLimit . '}?[\\s\\W]|^)(' . $matchString . ')([\\s\\W].{0,' . $charLimit . '}[\\s\\W]|[\\s\\W][^\\s\\W]{' . $charLimit . '})/is' . ($context['utf8'] ? 'u' : ''), $message['body'], $matches); } $message['body'] = ''; foreach ($matches[0] as $index => $match) { $match = strtr($smcFunc['htmlspecialchars']($match, ENT_QUOTES), array("\n" => ' ')); $message['body'] .= '<strong>......</strong> ' . $match . ' <strong>......</strong>'; } } // Re-fix the international characters. $message['body'] = preg_replace_callback('~(&#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~', 'entity_fix__callback', $message['body']); } } else { // Run BBC interpreter on the message. $message['body'] = parse_bbc($message['body'], $message['smileys_enabled'], $message['id_msg']); } // Make sure we don't end up with a practically empty message body. $message['body'] = preg_replace('~^(?: )+$~', '', $message['body']); // Sadly, we need to check the icon ain't broke. if (empty($modSettings['messageIconChecks_disable'])) { if (!isset($context['icon_sources'][$message['first_icon']])) { $context['icon_sources'][$message['first_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $message['first_icon'] . '.gif') ? 'images_url' : 'default_images_url'; } if (!isset($context['icon_sources'][$message['last_icon']])) { $context['icon_sources'][$message['last_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $message['last_icon'] . '.gif') ? 'images_url' : 'default_images_url'; } if (!isset($context['icon_sources'][$message['icon']])) { $context['icon_sources'][$message['icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $message['icon'] . '.gif') ? 'images_url' : 'default_images_url'; } } else { if (!isset($context['icon_sources'][$message['first_icon']])) { $context['icon_sources'][$message['first_icon']] = 'images_url'; } if (!isset($context['icon_sources'][$message['last_icon']])) { $context['icon_sources'][$message['last_icon']] = 'images_url'; } if (!isset($context['icon_sources'][$message['icon']])) { $context['icon_sources'][$message['icon']] = 'images_url'; } } // Do we have quote tag enabled? $quote_enabled = empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC'])); $output = array_merge($context['topics'][$message['id_msg']], array('id' => $message['id_topic'], 'is_sticky' => !empty($modSettings['enableStickyTopics']) && !empty($message['is_sticky']), 'is_locked' => !empty($message['locked']), 'is_poll' => $modSettings['pollMode'] == '1' && $message['id_poll'] > 0, 'is_hot' => $message['num_replies'] >= $modSettings['hotTopicPosts'], 'is_very_hot' => $message['num_replies'] >= $modSettings['hotTopicVeryPosts'], 'posted_in' => !empty($participants[$message['id_topic']]), 'views' => $message['num_views'], 'replies' => $message['num_replies'], 'can_reply' => in_array($message['id_board'], $boards_can['post_reply_any']) || in_array(0, $boards_can['post_reply_any']), 'can_quote' => (in_array($message['id_board'], $boards_can['post_reply_any']) || in_array(0, $boards_can['post_reply_any'])) && $quote_enabled, 'can_mark_notify' => in_array($message['id_board'], $boards_can['mark_any_notify']) || in_array(0, $boards_can['mark_any_notify']) && !$context['user']['is_guest'], 'first_post' => array('id' => $message['first_msg'], 'time' => timeformat($message['first_poster_time']), 'timestamp' => forum_time(true, $message['first_poster_time']), 'subject' => $message['first_subject'], 'href' => $scripturl . '?topic=' . $message['id_topic'] . '.0', 'link' => '<a href="' . $scripturl . '?topic=' . $message['id_topic'] . '.0">' . $message['first_subject'] . '</a>', 'icon' => $message['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$message['first_icon']]] . '/post/' . $message['first_icon'] . '.gif', 'member' => array('id' => $message['first_member_id'], 'name' => $message['first_member_name'], 'href' => !empty($message['first_member_id']) ? $scripturl . '?action=profile;u=' . $message['first_member_id'] : '', 'link' => !empty($message['first_member_id']) ? '<a href="' . $scripturl . '?action=profile;u=' . $message['first_member_id'] . '" title="' . $txt['profile_of'] . ' ' . $message['first_member_name'] . '">' . $message['first_member_name'] . '</a>' : $message['first_member_name'])), 'last_post' => array('id' => $message['last_msg'], 'time' => timeformat($message['last_poster_time']), 'timestamp' => forum_time(true, $message['last_poster_time']), 'subject' => $message['last_subject'], 'href' => $scripturl . '?topic=' . $message['id_topic'] . ($message['num_replies'] == 0 ? '.0' : '.msg' . $message['last_msg']) . '#msg' . $message['last_msg'], 'link' => '<a href="' . $scripturl . '?topic=' . $message['id_topic'] . ($message['num_replies'] == 0 ? '.0' : '.msg' . $message['last_msg']) . '#msg' . $message['last_msg'] . '">' . $message['last_subject'] . '</a>', 'icon' => $message['last_icon'], 'icon_url' => $settings[$context['icon_sources'][$message['last_icon']]] . '/post/' . $message['last_icon'] . '.gif', 'member' => array('id' => $message['last_member_id'], 'name' => $message['last_member_name'], 'href' => !empty($message['last_member_id']) ? $scripturl . '?action=profile;u=' . $message['last_member_id'] : '', 'link' => !empty($message['last_member_id']) ? '<a href="' . $scripturl . '?action=profile;u=' . $message['last_member_id'] . '" title="' . $txt['profile_of'] . ' ' . $message['last_member_name'] . '">' . $message['last_member_name'] . '</a>' : $message['last_member_name'])), 'board' => array('id' => $message['id_board'], 'name' => $message['board_name'], 'href' => $scripturl . '?board=' . $message['id_board'] . '.0', 'link' => '<a href="' . $scripturl . '?board=' . $message['id_board'] . '.0">' . $message['board_name'] . '</a>'), 'category' => array('id' => $message['id_cat'], 'name' => $message['cat_name'], 'href' => $scripturl . '#c' . $message['id_cat'], 'link' => '<a href="' . $scripturl . '#c' . $message['id_cat'] . '">' . $message['cat_name'] . '</a>'))); determineTopicClass($output); if ($output['posted_in']) { $output['class'] = 'my_' . $output['class']; } $body_highlighted = $message['body']; $subject_highlighted = $message['subject']; if (!empty($options['display_quick_mod'])) { $started = $output['first_post']['member']['id'] == $user_info['id']; $output['quick_mod'] = array('lock' => in_array(0, $boards_can['lock_any']) || in_array($output['board']['id'], $boards_can['lock_any']) || $started && (in_array(0, $boards_can['lock_own']) || in_array($output['board']['id'], $boards_can['lock_own'])), 'sticky' => (in_array(0, $boards_can['make_sticky']) || in_array($output['board']['id'], $boards_can['make_sticky'])) && !empty($modSettings['enableStickyTopics']), 'move' => in_array(0, $boards_can['move_any']) || in_array($output['board']['id'], $boards_can['move_any']) || $started && (in_array(0, $boards_can['move_own']) || in_array($output['board']['id'], $boards_can['move_own'])), 'remove' => in_array(0, $boards_can['remove_any']) || in_array($output['board']['id'], $boards_can['remove_any']) || $started && (in_array(0, $boards_can['remove_own']) || in_array($output['board']['id'], $boards_can['remove_own']))); $context['can_lock'] |= $output['quick_mod']['lock']; $context['can_sticky'] |= $output['quick_mod']['sticky']; $context['can_move'] |= $output['quick_mod']['move']; $context['can_remove'] |= $output['quick_mod']['remove']; $context['can_merge'] |= in_array($output['board']['id'], $boards_can['merge_any']); // If we've found a message we can move, and we don't already have it, load the destinations. if ($options['display_quick_mod'] == 1 && !isset($context['move_to_boards']) && $context['can_move']) { require_once $sourcedir . '/Subs-MessageIndex.php'; $boardListOptions = array('use_permissions' => true, 'not_redirection' => true, 'selected_board' => empty($_SESSION['move_to_topic']) ? null : $_SESSION['move_to_topic']); $context['move_to_boards'] = getBoardList($boardListOptions); } } foreach ($context['key_words'] as $query) { // Fix the international characters in the keyword too. $query = strtr($smcFunc['htmlspecialchars']($query), array('\\\'' => '\'')); $body_highlighted = preg_replace_callback('/((<[^>]*)|' . preg_quote(strtr($query, array('\'' => ''')), '/') . ')/i' . ($context['utf8'] ? 'u' : ''), 'search_highlight__preg_callback', $body_highlighted); $subject_highlighted = preg_replace('/(' . preg_quote($query, '/') . ')/i' . ($context['utf8'] ? 'u' : ''), '<strong class="highlight">$1</strong>', $subject_highlighted); } $output['matches'][] = array('id' => $message['id_msg'], 'attachment' => loadAttachmentContext($message['id_msg']), 'alternate' => $counter % 2, 'member' => &$memberContext[$message['id_member']], 'icon' => $message['icon'], 'icon_url' => $settings[$context['icon_sources'][$message['icon']]] . '/post/' . $message['icon'] . '.gif', 'subject' => $message['subject'], 'subject_highlighted' => $subject_highlighted, 'time' => timeformat($message['poster_time']), 'timestamp' => forum_time(true, $message['poster_time']), 'counter' => $counter, 'modified' => array('time' => timeformat($message['modified_time']), 'timestamp' => forum_time(true, $message['modified_time']), 'name' => $message['modified_name']), 'body' => $message['body'], 'body_highlighted' => $body_highlighted, 'start' => 'msg' . $message['id_msg']); $counter++; return $output; }
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)); }
include_once "include/db_mysql.php"; include_once "include/common.php"; $conn = db_connect($h, $p, $u, $db); $bid = $_GET['bid']; $tid = $_GET['tid']; if (!is_numeric($bid) || !is_numeric($tid)) { $error = $ERR['NO_PARAM']; showerrpage($error); exit; } $show_info = ""; $sql = "select board_name,content,DATE_FORMAT(post_time,'%Y-%m-%d %H:%i') "; $sql .= "as post_time from topics,boards where bid=boards.id and bid={$bid} and topics.id={$tid}"; $result = mysql_query($sql) or die("ERROR: " . mysql_error() . " <br/>SQL=" . $sql); if ($num = mysql_num_rows($result)) { $row = mysql_fetch_array($result); $board_name = $row['board_name']; $content = $row['content']; $content = str_replace("<br> ", "\r\n", $content); $post_time = $row['post_time']; } else { $error = $ERR['NO_PARAM']; showerrpage($error); exit; } $html_title = $HTML_TITLE['mod']; $board_name_list = getBoardList(); $user_rank_list = userRank($bid); close_db($conn); include_once "template/mod_topic.htm";
function MessageIndex() { global $txt, $scripturl, $board, $modSettings, $context; global $options, $settings, $board_info, $user_info, $smcFunc, $sourcedir; // If this is a redirection board head off. if ($board_info['redirect']) { $smcFunc['db_query']('', ' UPDATE {db_prefix}boards SET num_posts = num_posts + 1 WHERE id_board = {int:current_board}', array('current_board' => $board)); redirectexit($board_info['redirect']); } if (WIRELESS) { $context['sub_template'] = WIRELESS_PROTOCOL . '_messageindex'; } else { loadTemplate('MessageIndex'); } $context['name'] = $board_info['name']; $context['description'] = $board_info['description']; // How many topics do we have in total? $board_info['total_topics'] = allowedTo('approve_posts') ? $board_info['num_topics'] + $board_info['unapproved_topics'] : $board_info['num_topics'] + $board_info['unapproved_user_topics']; // View all the topics, or just a few? $context['topics_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['topics_per_page']) && !WIRELESS ? $options['topics_per_page'] : $modSettings['defaultMaxTopics']; $context['messages_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) && !WIRELESS ? $options['messages_per_page'] : $modSettings['defaultMaxMessages']; $maxindex = isset($_REQUEST['all']) && !empty($modSettings['enableAllMessages']) ? $board_info['total_topics'] : $context['topics_per_page']; // Right, let's only index normal stuff! if (count($_GET) > 1) { $session_name = session_name(); foreach ($_GET as $k => $v) { if (!in_array($k, array('board', 'start', $session_name))) { $context['robot_no_index'] = true; } } } if (!empty($_REQUEST['start']) && (!is_numeric($_REQUEST['start']) || $_REQUEST['start'] % $context['messages_per_page'] != 0)) { $context['robot_no_index'] = true; } // If we can view unapproved messages and there are some build up a list. if (allowedTo('approve_posts') && ($board_info['unapproved_topics'] || $board_info['unapproved_posts'])) { $untopics = $board_info['unapproved_topics'] ? '<a href="' . $scripturl . '?action=moderate;area=postmod;sa=topics;brd=' . $board . '">' . $board_info['unapproved_topics'] . '</a>' : 0; $unposts = $board_info['unapproved_posts'] ? '<a href="' . $scripturl . '?action=moderate;area=postmod;sa=posts;brd=' . $board . '">' . ($board_info['unapproved_posts'] - $board_info['unapproved_topics']) . '</a>' : 0; $context['unapproved_posts_message'] = sprintf($txt['there_are_unapproved_topics'], $untopics, $unposts, $scripturl . '?action=moderate;area=postmod;sa=' . ($board_info['unapproved_topics'] ? 'topics' : 'posts') . ';brd=' . $board); } // We only know these. if (isset($_REQUEST['sort']) && !in_array($_REQUEST['sort'], array('subject', 'starter', 'last_poster', 'replies', 'views', 'first_post', 'last_post'))) { $_REQUEST['sort'] = 'last_post'; } // Make sure the starting place makes sense and construct the page index. if (isset($_REQUEST['sort'])) { $context['page_index'] = constructPageIndex($scripturl . '?board=' . $board . '.%1$d;sort=' . $_REQUEST['sort'] . (isset($_REQUEST['desc']) ? ';desc' : ''), $_REQUEST['start'], $board_info['total_topics'], $maxindex, true); } else { $context['page_index'] = constructPageIndex($scripturl . '?board=' . $board . '.%1$d', $_REQUEST['start'], $board_info['total_topics'], $maxindex, true); } $context['start'] =& $_REQUEST['start']; // Set a canonical URL for this page. $context['canonical_url'] = $scripturl . '?board=' . $board . '.' . $context['start']; $context['links'] = array('first' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?board=' . $board . '.0' : '', 'prev' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?board=' . $board . '.' . ($_REQUEST['start'] - $context['topics_per_page']) : '', 'next' => $_REQUEST['start'] + $context['topics_per_page'] < $board_info['total_topics'] ? $scripturl . '?board=' . $board . '.' . ($_REQUEST['start'] + $context['topics_per_page']) : '', 'last' => $_REQUEST['start'] + $context['topics_per_page'] < $board_info['total_topics'] ? $scripturl . '?board=' . $board . '.' . floor(($board_info['total_topics'] - 1) / $context['topics_per_page']) * $context['topics_per_page'] : '', 'up' => $board_info['parent'] == 0 ? $scripturl . '?' : $scripturl . '?board=' . $board_info['parent'] . '.0'); $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['topics_per_page'] + 1, 'num_pages' => floor(($board_info['total_topics'] - 1) / $context['topics_per_page']) + 1); if (isset($_REQUEST['all']) && !empty($modSettings['enableAllMessages']) && $maxindex > $modSettings['enableAllMessages']) { $maxindex = $modSettings['enableAllMessages']; $_REQUEST['start'] = 0; } // Build a list of the board's moderators. $context['moderators'] =& $board_info['moderators']; $context['link_moderators'] = array(); if (!empty($board_info['moderators'])) { foreach ($board_info['moderators'] as $mod) { $context['link_moderators'][] = '<a href="' . $scripturl . '?action=profile;u=' . $mod['id'] . '" title="' . $txt['board_moderator'] . '">' . $mod['name'] . '</a>'; } $context['linktree'][count($context['linktree']) - 1]['extra_after'] = ' (' . (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; } $smcFunc['db_insert']('replace', '{db_prefix}log_boards', array('id_msg' => 'int', 'id_member' => 'int', 'id_board' => 'int'), array($modSettings['maxMsgID'], $user_info['id'], $board), array('id_member', 'id_board')); if (!empty($board_info['parent_boards'])) { $smcFunc['db_query']('', ' UPDATE {db_prefix}log_boards SET id_msg = {int:id_msg} WHERE id_member = {int:current_member} AND id_board IN ({array_int:board_list})', array('current_member' => $user_info['id'], 'board_list' => array_keys($board_info['parent_boards']), 'id_msg' => $modSettings['maxMsgID'])); // We've seen all these boards now! foreach ($board_info['parent_boards'] as $k => $dummy) { if (isset($_SESSION['topicseen_cache'][$k])) { unset($_SESSION['topicseen_cache'][$k]); } } } if (isset($_SESSION['topicseen_cache'][$board])) { unset($_SESSION['topicseen_cache'][$board]); } $request = $smcFunc['db_query']('', ' SELECT sent FROM {db_prefix}log_notify WHERE id_board = {int:current_board} AND id_member = {int:current_member} LIMIT 1', array('current_board' => $board, 'current_member' => $user_info['id'])); $context['is_marked_notify'] = $smcFunc['db_num_rows']($request) != 0; if ($context['is_marked_notify']) { list($sent) = $smcFunc['db_fetch_row']($request); if (!empty($sent)) { $smcFunc['db_query']('', ' UPDATE {db_prefix}log_notify SET sent = {int:is_sent} WHERE id_board = {int:current_board} AND id_member = {int:current_member}', array('current_board' => $board, 'current_member' => $user_info['id'], 'is_sent' => 0)); } } $smcFunc['db_free_result']($request); } else { $context['is_marked_notify'] = false; } // 'Print' the header and board info. $context['page_title'] = strip_tags($board_info['name']); // Set the variables up for the template. $context['can_mark_notify'] = allowedTo('mark_notify') && !$user_info['is_guest']; $context['can_post_new'] = allowedTo('post_new') || $modSettings['postmod_active'] && allowedTo('post_unapproved_topics'); $context['can_post_poll'] = $modSettings['pollMode'] == '1' && allowedTo('poll_post') && $context['can_post_new']; $context['can_moderate_forum'] = allowedTo('moderate_forum'); $context['can_approve_posts'] = allowedTo('approve_posts'); require_once $sourcedir . '/Subs-BoardIndex.php'; $boardIndexOptions = array('include_categories' => false, 'base_level' => $board_info['child_level'] + 1, 'parent_id' => $board_info['id'], 'set_latest_post' => false, 'countChildPosts' => !empty($modSettings['countChildPosts'])); $context['boards'] = getBoardIndex($boardIndexOptions); // Nosey, nosey - who's viewing this topic? if (!empty($settings['display_who_viewing'])) { $context['view_members'] = array(); $context['view_members_list'] = array(); $context['view_num_hidden'] = 0; $request = $smcFunc['db_query']('', ' SELECT lo.id_member, lo.log_time, mem.real_name, mem.member_name, mem.show_online, mg.online_color, mg.id_group, mg.group_name FROM {db_prefix}log_online AS lo LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lo.id_member) LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = CASE WHEN mem.id_group = {int:reg_member_group} THEN mem.id_post_group ELSE mem.id_group END) WHERE INSTR(lo.url, {string:in_url_string}) > 0 OR lo.session = {string:session}', array('reg_member_group' => 0, 'in_url_string' => 's:5:"board";i:' . $board . ';', 'session' => $user_info['is_guest'] ? 'ip' . $user_info['ip'] : session_id())); while ($row = $smcFunc['db_fetch_assoc']($request)) { if (empty($row['id_member'])) { continue; } if (!empty($row['online_color'])) { $link = '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '" style="color: ' . $row['online_color'] . ';">' . $row['real_name'] . '</a>'; } else { $link = '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>'; } $is_buddy = in_array($row['id_member'], $user_info['buddies']); if ($is_buddy) { $link = '<strong>' . $link . '</strong>'; } if (!empty($row['show_online']) || allowedTo('moderate_forum')) { $context['view_members_list'][$row['log_time'] . $row['member_name']] = empty($row['show_online']) ? '<em>' . $link . '</em>' : $link; } $context['view_members'][$row['log_time'] . $row['member_name']] = array('id' => $row['id_member'], 'username' => $row['member_name'], 'name' => $row['real_name'], 'group' => $row['id_group'], 'href' => $scripturl . '?action=profile;u=' . $row['id_member'], 'link' => $link, 'is_buddy' => $is_buddy, 'hidden' => empty($row['show_online'])); if (empty($row['show_online'])) { $context['view_num_hidden']++; } } $context['view_num_guests'] = $smcFunc['db_num_rows']($request) - count($context['view_members']); $smcFunc['db_free_result']($request); // Put them in "last clicked" order. krsort($context['view_members_list']); krsort($context['view_members']); } // Default sort methods. $sort_methods = array('subject' => 'mf.subject', 'starter' => 'IFNULL(memf.real_name, mf.poster_name)', 'last_poster' => 'IFNULL(meml.real_name, ml.poster_name)', 'replies' => 't.num_replies', 'views' => 't.num_views', 'first_post' => 't.id_topic', 'last_post' => 't.id_last_msg'); // They didn't pick one, default to by last post descending. if (!isset($_REQUEST['sort']) || !isset($sort_methods[$_REQUEST['sort']])) { $context['sort_by'] = 'last_post'; $_REQUEST['sort'] = 'id_last_msg'; $ascending = isset($_REQUEST['asc']); } else { $context['sort_by'] = $_REQUEST['sort']; $_REQUEST['sort'] = $sort_methods[$_REQUEST['sort']]; $ascending = !isset($_REQUEST['desc']); } $context['sort_direction'] = $ascending ? 'up' : 'down'; // Calculate the fastest way to get the topics. $start = (int) $_REQUEST['start']; if ($start > ($board_info['total_topics'] - 1) / 2) { $ascending = !$ascending; $fake_ascending = true; $maxindex = $board_info['total_topics'] < $start + $maxindex + 1 ? $board_info['total_topics'] - $start : $maxindex; $start = $board_info['total_topics'] < $start + $maxindex + 1 ? 0 : $board_info['total_topics'] - $start - $maxindex; } else { $fake_ascending = false; } // Setup the default topic icons... $stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'moved', 'recycled', 'wireless', 'clip'); $context['icon_sources'] = array(); foreach ($stable_icons as $icon) { $context['icon_sources'][$icon] = 'images_url'; } $topic_ids = array(); $context['topics'] = array(); // Sequential pages are often not optimized, so we add an additional query. $pre_query = $start > 0; if ($pre_query && $maxindex > 0) { $request = $smcFunc['db_query']('', ' SELECT t.id_topic FROM {db_prefix}topics AS t' . ($context['sort_by'] === 'last_poster' ? ' INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)' : (in_array($context['sort_by'], array('starter', 'subject')) ? ' INNER JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg)' : '')) . ($context['sort_by'] === 'starter' ? ' LEFT JOIN {db_prefix}members AS memf ON (memf.id_member = mf.id_member)' : '') . ($context['sort_by'] === 'last_poster' ? ' LEFT JOIN {db_prefix}members AS meml ON (meml.id_member = ml.id_member)' : '') . ' WHERE t.id_board = {int:current_board}' . (!$modSettings['postmod_active'] || $context['can_approve_posts'] ? '' : ' AND (t.approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR t.id_member_started = {int:current_member}') . ')') . ' ORDER BY ' . (!empty($modSettings['enableStickyTopics']) ? 'is_sticky' . ($fake_ascending ? '' : ' DESC') . ', ' : '') . $_REQUEST['sort'] . ($ascending ? '' : ' DESC') . ' LIMIT {int:start}, {int:maxindex}', array('current_board' => $board, 'current_member' => $user_info['id'], 'is_approved' => 1, 'id_member_guest' => 0, 'start' => $start, 'maxindex' => $maxindex)); $topic_ids = array(); while ($row = $smcFunc['db_fetch_assoc']($request)) { $topic_ids[] = $row['id_topic']; } } // Grab the appropriate topic information... if (!$pre_query || !empty($topic_ids)) { // For search engine effectiveness we'll link guests differently. $context['pageindex_multiplier'] = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) && !WIRELESS ? $options['messages_per_page'] : $modSettings['defaultMaxMessages']; $result = $smcFunc['db_query']('substring', ' SELECT t.id_topic, t.num_replies, t.locked, t.num_views, t.is_sticky, t.id_poll, t.id_previous_board, ' . ($user_info['is_guest'] ? '0' : 'IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1') . ' AS new_from, t.id_last_msg, t.approved, t.unapproved_posts, ml.poster_time AS last_poster_time, ml.id_msg_modified, ml.subject AS last_subject, ml.icon AS last_icon, ml.poster_name AS last_member_name, ml.id_member AS last_id_member, IFNULL(meml.real_name, ml.poster_name) AS last_display_name, t.id_first_msg, mf.poster_time AS first_poster_time, mf.subject AS first_subject, mf.icon AS first_icon, mf.poster_name AS first_member_name, mf.id_member AS first_id_member, IFNULL(memf.real_name, mf.poster_name) AS first_display_name, SUBSTRING(ml.body, 1, 385) AS last_body, SUBSTRING(mf.body, 1, 385) AS first_body, ml.smileys_enabled AS last_smileys, mf.smileys_enabled AS first_smileys 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})') . ' WHERE ' . ($pre_query ? 't.id_topic IN ({array_int:topic_list})' : 't.id_board = {int:current_board}') . (!$modSettings['postmod_active'] || $context['can_approve_posts'] ? '' : ' AND (t.approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR t.id_member_started = {int:current_member}') . ')') . ' ORDER BY ' . ($pre_query ? 'FIND_IN_SET(t.id_topic, {string:find_set_topics})' : (!empty($modSettings['enableStickyTopics']) ? 'is_sticky' . ($fake_ascending ? '' : ' DESC') . ', ' : '') . $_REQUEST['sort'] . ($ascending ? '' : ' DESC')) . ' LIMIT ' . ($pre_query ? '' : '{int:start}, ') . '{int:maxindex}', array('current_board' => $board, 'current_member' => $user_info['id'], 'topic_list' => $topic_ids, 'is_approved' => 1, 'find_set_topics' => implode(',', $topic_ids), 'start' => $start, 'maxindex' => $maxindex)); // Begin 'printing' the message index for current board. while ($row = $smcFunc['db_fetch_assoc']($result)) { if ($row['id_poll'] > 0 && $modSettings['pollMode'] == '0') { continue; } if (!$pre_query) { $topic_ids[] = $row['id_topic']; } if (!empty($settings['message_index_preview'])) { // Limit them to 128 characters - do this FIRST because it's a lot of wasted censoring otherwise. $row['first_body'] = strip_tags(strtr(parse_bbc($row['first_body'], $row['first_smileys'], $row['id_first_msg']), array('<br />' => ' '))); if ($smcFunc['strlen']($row['first_body']) > 128) { $row['first_body'] = $smcFunc['substr']($row['first_body'], 0, 128) . '...'; } $row['last_body'] = strip_tags(strtr(parse_bbc($row['last_body'], $row['last_smileys'], $row['id_last_msg']), array('<br />' => ' '))); if ($smcFunc['strlen']($row['last_body']) > 128) { $row['last_body'] = $smcFunc['substr']($row['last_body'], 0, 128) . '...'; } // Censor the subject and message preview. censorText($row['first_subject']); censorText($row['first_body']); // Don't censor them twice! if ($row['id_first_msg'] == $row['id_last_msg']) { $row['last_subject'] = $row['first_subject']; $row['last_body'] = $row['first_body']; } else { censorText($row['last_subject']); censorText($row['last_body']); } } else { $row['first_body'] = ''; $row['last_body'] = ''; censorText($row['first_subject']); if ($row['id_first_msg'] == $row['id_last_msg']) { $row['last_subject'] = $row['first_subject']; } else { censorText($row['last_subject']); } } // Decide how many pages the topic should have. if ($row['num_replies'] + 1 > $context['messages_per_page']) { $pages = '« '; // We can't pass start by reference. $start = -1; $pages .= constructPageIndex($scripturl . '?topic=' . $row['id_topic'] . '.%1$d', $start, $row['num_replies'] + 1, $context['messages_per_page'], true); // If we can use all, show all. if (!empty($modSettings['enableAllMessages']) && $row['num_replies'] + 1 < $modSettings['enableAllMessages']) { $pages .= ' <a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0;all">' . $txt['all'] . '</a>'; } $pages .= ' »'; } else { $pages = ''; } // We need to check the topic icons exist... if (empty($modSettings['messageIconChecks_disable'])) { if (!isset($context['icon_sources'][$row['first_icon']])) { $context['icon_sources'][$row['first_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['first_icon'] . '.gif') ? 'images_url' : 'default_images_url'; } if (!isset($context['icon_sources'][$row['last_icon']])) { $context['icon_sources'][$row['last_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['last_icon'] . '.gif') ? 'images_url' : 'default_images_url'; } } else { if (!isset($context['icon_sources'][$row['first_icon']])) { $context['icon_sources'][$row['first_icon']] = 'images_url'; } if (!isset($context['icon_sources'][$row['last_icon']])) { $context['icon_sources'][$row['last_icon']] = 'images_url'; } } // 'Print' the topic info. $context['topics'][$row['id_topic']] = array('id' => $row['id_topic'], 'first_post' => array('id' => $row['id_first_msg'], 'member' => array('username' => $row['first_member_name'], 'name' => $row['first_display_name'], 'id' => $row['first_id_member'], 'href' => !empty($row['first_id_member']) ? $scripturl . '?action=profile;u=' . $row['first_id_member'] : '', 'link' => !empty($row['first_id_member']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['first_id_member'] . '" title="' . $txt['profile_of'] . ' ' . $row['first_display_name'] . '">' . $row['first_display_name'] . '</a>' : $row['first_display_name']), 'time' => timeformat($row['first_poster_time']), 'timestamp' => forum_time(true, $row['first_poster_time']), 'subject' => $row['first_subject'], 'preview' => $row['first_body'], 'icon' => $row['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['first_icon']]] . '/post/' . $row['first_icon'] . '.gif', 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.0', 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0">' . $row['first_subject'] . '</a>'), 'last_post' => array('id' => $row['id_last_msg'], 'member' => array('username' => $row['last_member_name'], 'name' => $row['last_display_name'], 'id' => $row['last_id_member'], 'href' => !empty($row['last_id_member']) ? $scripturl . '?action=profile;u=' . $row['last_id_member'] : '', 'link' => !empty($row['last_id_member']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['last_id_member'] . '">' . $row['last_display_name'] . '</a>' : $row['last_display_name']), 'time' => timeformat($row['last_poster_time']), 'timestamp' => forum_time(true, $row['last_poster_time']), 'subject' => $row['last_subject'], 'preview' => $row['last_body'], 'icon' => $row['last_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['last_icon']]] . '/post/' . $row['last_icon'] . '.gif', 'href' => $scripturl . '?topic=' . $row['id_topic'] . ($user_info['is_guest'] ? '.' . (!empty($options['view_newest_first']) ? 0 : (int) ($row['num_replies'] / $context['pageindex_multiplier']) * $context['pageindex_multiplier']) . '#msg' . $row['id_last_msg'] : ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['id_last_msg']) . '#new'), 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . ($user_info['is_guest'] ? '.' . (!empty($options['view_newest_first']) ? 0 : (int) ($row['num_replies'] / $context['pageindex_multiplier']) * $context['pageindex_multiplier']) . '#msg' . $row['id_last_msg'] : ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['id_last_msg']) . '#new') . '" ' . ($row['num_replies'] == 0 ? '' : 'rel="nofollow"') . '>' . $row['last_subject'] . '</a>'), 'is_sticky' => !empty($modSettings['enableStickyTopics']) && !empty($row['is_sticky']), 'is_locked' => !empty($row['locked']), 'is_poll' => $modSettings['pollMode'] == '1' && $row['id_poll'] > 0, 'is_hot' => $row['num_replies'] >= $modSettings['hotTopicPosts'], 'is_very_hot' => $row['num_replies'] >= $modSettings['hotTopicVeryPosts'], 'is_posted_in' => false, 'icon' => $row['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['first_icon']]] . '/post/' . $row['first_icon'] . '.gif', 'subject' => $row['first_subject'], 'new' => $row['new_from'] <= $row['id_msg_modified'], 'new_from' => $row['new_from'], 'newtime' => $row['new_from'], 'new_href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['new_from'] . '#new', 'pages' => $pages, 'replies' => 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']]); } $smcFunc['db_free_result']($result); // Fix the sequence of topics if they were retrieved in the wrong order. (for speed reasons...) if ($fake_ascending) { $context['topics'] = array_reverse($context['topics'], true); } if (!empty($modSettings['enableParticipation']) && !$user_info['is_guest'] && !empty($topic_ids)) { $result = $smcFunc['db_query']('', ' SELECT id_topic FROM {db_prefix}messages WHERE id_topic IN ({array_int:topic_list}) AND id_member = {int:current_member} GROUP BY id_topic LIMIT ' . count($topic_ids), array('current_member' => $user_info['id'], 'topic_list' => $topic_ids)); while ($row = $smcFunc['db_fetch_assoc']($result)) { $context['topics'][$row['id_topic']]['is_posted_in'] = true; $context['topics'][$row['id_topic']]['class'] = 'my_' . $context['topics'][$row['id_topic']]['class']; } $smcFunc['db_free_result']($result); } } $context['jump_to'] = array('label' => addslashes(un_htmlspecialchars($txt['jump_to'])), 'board_name' => htmlspecialchars(strtr(strip_tags($board_info['name']), array('&' => '&'))), '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'] == 1 && $context['can_move'] && !empty($context['topics'])) { require_once $sourcedir . '/Subs-MessageIndex.php'; $boardListOptions = array('excluded_boards' => array($board), 'not_redirection' => true, 'use_permissions' => true, 'selected_board' => empty($_SESSION['move_to_topic']) ? null : $_SESSION['move_to_topic']); $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'] == 1) { $context['can_quick_mod'] = $context['user']['is_logged'] || $context['can_approve'] || $context['can_remove'] || $context['can_lock'] || $context['can_sticky'] || $context['can_move'] || $context['can_merge'] || $context['can_restore']; } else { $context['can_quick_mod'] = $context['can_remove'] || $context['can_lock'] || $context['can_sticky'] || $context['can_move']; } } // If 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']; }
function CalendarPost() { global $context, $txt, $user_info, $sourcedir, $scripturl; global $modSettings, $topic, $smcFunc; // Well - can they? isAllowedTo('calendar_post'); // We need this for all kinds of useful functions. require_once $sourcedir . '/Subs-Calendar.php'; // Cast this for safety... if (isset($_REQUEST['eventid'])) { $_REQUEST['eventid'] = (int) $_REQUEST['eventid']; } // Submitting? if (isset($_POST[$context['session_var']], $_REQUEST['eventid'])) { checkSession(); // Validate the post... if (!isset($_POST['link_to_board'])) { validateEventPost(); } // If you're not allowed to edit any events, you have to be the poster. if ($_REQUEST['eventid'] > 0 && !allowedTo('calendar_edit_any')) { isAllowedTo('calendar_edit_' . (!empty($user_info['id']) && getEventPoster($_REQUEST['eventid']) == $user_info['id'] ? 'own' : 'any')); } // New - and directing? if ($_REQUEST['eventid'] == -1 && isset($_POST['link_to_board'])) { $_REQUEST['calendar'] = 1; require_once $sourcedir . '/Post.php'; return Post(); } elseif ($_REQUEST['eventid'] == -1) { $eventOptions = array('board' => 0, 'topic' => 0, 'title' => substr($_REQUEST['evtitle'], 0, 60), 'member' => $user_info['id'], 'start_date' => sprintf('%04d-%02d-%02d', $_POST['year'], $_POST['month'], $_POST['day']), 'span' => isset($_POST['span']) && $_POST['span'] > 0 ? min((int) $modSettings['cal_maxspan'], (int) $_POST['span'] - 1) : 0); insertEvent($eventOptions); } elseif (isset($_REQUEST['deleteevent'])) { removeEvent($_REQUEST['eventid']); } else { $eventOptions = array('title' => substr($_REQUEST['evtitle'], 0, 60), 'span' => empty($modSettings['cal_allowspan']) || empty($_POST['span']) || $_POST['span'] == 1 || empty($modSettings['cal_maxspan']) || $_POST['span'] > $modSettings['cal_maxspan'] ? 0 : min((int) $modSettings['cal_maxspan'], (int) $_POST['span'] - 1), 'start_date' => strftime('%Y-%m-%d', mktime(0, 0, 0, (int) $_REQUEST['month'], (int) $_REQUEST['day'], (int) $_REQUEST['year']))); modifyEvent($_REQUEST['eventid'], $eventOptions); } updateSettings(array('calendar_updated' => time())); // No point hanging around here now... redirectexit($scripturl . '?action=calendar;month=' . $_POST['month'] . ';year=' . $_POST['year']); } // If we are not enabled... we are not enabled. if (empty($modSettings['cal_allow_unlinked']) && empty($_REQUEST['eventid'])) { $_REQUEST['calendar'] = 1; require_once $sourcedir . '/Post.php'; return Post(); } // New? if (!isset($_REQUEST['eventid'])) { $today = getdate(); $context['event'] = array('boards' => array(), 'board' => 0, 'new' => 1, 'eventid' => -1, 'year' => isset($_REQUEST['year']) ? $_REQUEST['year'] : $today['year'], 'month' => isset($_REQUEST['month']) ? $_REQUEST['month'] : $today['mon'], 'day' => isset($_REQUEST['day']) ? $_REQUEST['day'] : $today['mday'], 'title' => '', 'span' => 1); $context['event']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['event']['month'] == 12 ? 1 : $context['event']['month'] + 1, 0, $context['event']['month'] == 12 ? $context['event']['year'] + 1 : $context['event']['year'])); // Get list of boards that can be posted in. $boards = boardsAllowedTo('post_new'); if (empty($boards)) { fatal_lang_error('cannot_post_new', 'permission'); } // Load the list of boards and categories in the context. require_once $sourcedir . '/Subs-MessageIndex.php'; $boardListOptions = array('included_boards' => in_array(0, $boards) ? null : $boards, 'not_redirection' => true, 'use_permissions' => true, 'selected_board' => $modSettings['cal_defaultboard']); $context['event']['categories'] = getBoardList($boardListOptions); } else { $context['event'] = getEventProperties($_REQUEST['eventid']); if ($context['event'] === false) { fatal_lang_error('no_access', false); } // If it has a board, then they should be editing it within the topic. if (!empty($context['event']['topic']['id']) && !empty($context['event']['topic']['first_msg'])) { // We load the board up, for a check on the board access rights... $topic = $context['event']['topic']['id']; loadBoard(); } // Make sure the user is allowed to edit this event. if ($context['event']['member'] != $user_info['id']) { isAllowedTo('calendar_edit_any'); } elseif (!allowedTo('calendar_edit_any')) { isAllowedTo('calendar_edit_own'); } } // Template, sub template, etc. loadTemplate('Calendar'); $context['sub_template'] = 'event_post'; $context['page_title'] = isset($_REQUEST['eventid']) ? $txt['calendar_edit'] : $txt['calendar_post_event']; $context['linktree'][] = array('name' => $context['page_title']); }
function Post() { global $txt, $scripturl, $topic, $modSettings, $board; global $user_info, $sc, $board_info, $context, $settings; global $sourcedir, $options, $smcFunc, $language; loadLanguage('Post'); // You can't reply with a poll... hacker. if (isset($_REQUEST['poll']) && !empty($topic) && !isset($_REQUEST['msg'])) { unset($_REQUEST['poll']); } // Posting an event? $context['make_event'] = isset($_REQUEST['calendar']); $context['robot_no_index'] = true; // You must be posting to *some* board. if (empty($board) && !$context['make_event']) { fatal_lang_error('no_board', false); } require_once $sourcedir . '/Subs-Post.php'; if (isset($_REQUEST['xml'])) { $context['sub_template'] = 'post'; // Just in case of an earlier error... $context['preview_message'] = ''; $context['preview_subject'] = ''; } // No message is complete without a topic. if (empty($topic) && !empty($_REQUEST['msg'])) { $request = $smcFunc['db_query']('', ' SELECT id_topic FROM {db_prefix}messages WHERE id_msg = {int:msg}', array('msg' => (int) $_REQUEST['msg'])); if ($smcFunc['db_num_rows']($request) != 1) { unset($_REQUEST['msg'], $_POST['msg'], $_GET['msg']); } else { list($topic) = $smcFunc['db_fetch_row']($request); } $smcFunc['db_free_result']($request); } // Check if it's locked. It isn't locked if no topic is specified. if (!empty($topic)) { $request = $smcFunc['db_query']('', ' SELECT t.locked, IFNULL(ln.id_topic, 0) AS notify, t.is_sticky, t.id_poll, t.id_last_msg, mf.id_member, t.id_first_msg, mf.subject, CASE WHEN ml.poster_time > ml.modified_time THEN ml.poster_time ELSE ml.modified_time END AS last_post_time FROM {db_prefix}topics AS t LEFT JOIN {db_prefix}log_notify AS ln ON (ln.id_topic = t.id_topic AND ln.id_member = {int:current_member}) LEFT JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg) LEFT JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg) WHERE t.id_topic = {int:current_topic} LIMIT 1', array('current_member' => $user_info['id'], 'current_topic' => $topic)); list($locked, $context['notify'], $sticky, $pollID, $context['topic_last_message'], $id_member_poster, $id_first_msg, $first_subject, $lastPostTime) = $smcFunc['db_fetch_row']($request); $smcFunc['db_free_result']($request); // If this topic already has a poll, they sure can't add another. if (isset($_REQUEST['poll']) && $pollID > 0) { unset($_REQUEST['poll']); } if (empty($_REQUEST['msg'])) { if ($user_info['is_guest'] && !allowedTo('post_reply_any') && (!$modSettings['postmod_active'] || !allowedTo('post_unapproved_replies_any'))) { is_not_guest(); } // By default the reply will be approved... $context['becomes_approved'] = true; if ($id_member_poster != $user_info['id']) { if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_any') && !allowedTo('post_reply_any')) { $context['becomes_approved'] = false; } else { isAllowedTo('post_reply_any'); } } elseif (!allowedTo('post_reply_any')) { if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_own') && !allowedTo('post_reply_own')) { $context['becomes_approved'] = false; } else { isAllowedTo('post_reply_own'); } } } else { $context['becomes_approved'] = true; } $context['can_lock'] = allowedTo('lock_any') || $user_info['id'] == $id_member_poster && allowedTo('lock_own'); $context['can_sticky'] = allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']); $context['notify'] = !empty($context['notify']); $context['sticky'] = isset($_REQUEST['sticky']) ? !empty($_REQUEST['sticky']) : $sticky; } else { $context['becomes_approved'] = true; if (!$context['make_event'] || !empty($board)) { if ($modSettings['postmod_active'] && !allowedTo('post_new') && allowedTo('post_unapproved_topics')) { $context['becomes_approved'] = false; } else { isAllowedTo('post_new'); } } $locked = 0; // !!! These won't work if you're making an event. $context['can_lock'] = allowedTo(array('lock_any', 'lock_own')); $context['can_sticky'] = allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']); $context['notify'] = !empty($context['notify']); $context['sticky'] = !empty($_REQUEST['sticky']); } // !!! These won't work if you're posting an event! $context['can_notify'] = allowedTo('mark_any_notify'); $context['can_move'] = allowedTo('move_any'); $context['move'] = !empty($_REQUEST['move']); $context['announce'] = !empty($_REQUEST['announce']); // You can only announce topics that will get approved... $context['can_announce'] = allowedTo('announce_topic') && $context['becomes_approved']; $context['locked'] = !empty($locked) || !empty($_REQUEST['lock']); $context['can_quote'] = empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC'])); // Generally don't show the approval box... (Assume we want things approved) $context['show_approval'] = false; // An array to hold all the attachments for this topic. $context['current_attachments'] = array(); // Don't allow a post if it's locked and you aren't all powerful. if ($locked && !allowedTo('moderate_board')) { fatal_lang_error('topic_locked', false); } // Check the users permissions - is the user allowed to add or post a poll? if (isset($_REQUEST['poll']) && $modSettings['pollMode'] == '1') { // New topic, new poll. if (empty($topic)) { isAllowedTo('poll_post'); } elseif ($user_info['id'] == $id_member_poster && !allowedTo('poll_add_any')) { isAllowedTo('poll_add_own'); } else { isAllowedTo('poll_add_any'); } require_once $sourcedir . '/Subs-Members.php'; $allowedVoteGroups = groupsAllowedTo('poll_vote', $board); // Set up the poll options. $context['poll_options'] = array('max_votes' => empty($_POST['poll_max_votes']) ? '1' : max(1, $_POST['poll_max_votes']), 'hide' => empty($_POST['poll_hide']) ? 0 : $_POST['poll_hide'], 'expire' => !isset($_POST['poll_expire']) ? '' : $_POST['poll_expire'], 'change_vote' => isset($_POST['poll_change_vote']), 'guest_vote' => isset($_POST['poll_guest_vote']), 'guest_vote_enabled' => in_array(-1, $allowedVoteGroups['allowed'])); // Make all five poll choices empty. $context['choices'] = array(array('id' => 0, 'number' => 1, 'label' => '', 'is_last' => false), array('id' => 1, 'number' => 2, 'label' => '', 'is_last' => false), array('id' => 2, 'number' => 3, 'label' => '', 'is_last' => false), array('id' => 3, 'number' => 4, 'label' => '', 'is_last' => false), array('id' => 4, 'number' => 5, 'label' => '', 'is_last' => true)); } if ($context['make_event']) { // They might want to pick a board. if (!isset($context['current_board'])) { $context['current_board'] = 0; } // Start loading up the event info. $context['event'] = array(); $context['event']['title'] = isset($_REQUEST['evtitle']) ? htmlspecialchars(stripslashes($_REQUEST['evtitle'])) : ''; $context['event']['id'] = isset($_REQUEST['eventid']) ? (int) $_REQUEST['eventid'] : -1; $context['event']['new'] = $context['event']['id'] == -1; // Permissions check! isAllowedTo('calendar_post'); // Editing an event? (but NOT previewing!?) if (!$context['event']['new'] && !isset($_REQUEST['subject'])) { // If the user doesn't have permission to edit the post in this topic, redirect them. if ((empty($id_member_poster) || $id_member_poster != $user_info['id'] || !allowedTo('modify_own')) && !allowedTo('modify_any')) { require_once $sourcedir . '/Calendar.php'; return CalendarPost(); } // Get the current event information. $request = $smcFunc['db_query']('', ' SELECT id_member, title, MONTH(start_date) AS month, DAYOFMONTH(start_date) AS day, YEAR(start_date) AS year, (TO_DAYS(end_date) - TO_DAYS(start_date)) AS span FROM {db_prefix}calendar WHERE id_event = {int:id_event} LIMIT 1', array('id_event' => $context['event']['id'])); $row = $smcFunc['db_fetch_assoc']($request); $smcFunc['db_free_result']($request); // Make sure the user is allowed to edit this event. if ($row['id_member'] != $user_info['id']) { isAllowedTo('calendar_edit_any'); } elseif (!allowedTo('calendar_edit_any')) { isAllowedTo('calendar_edit_own'); } $context['event']['month'] = $row['month']; $context['event']['day'] = $row['day']; $context['event']['year'] = $row['year']; $context['event']['title'] = $row['title']; $context['event']['span'] = $row['span'] + 1; } else { $today = getdate(); // You must have a month and year specified! if (!isset($_REQUEST['month'])) { $_REQUEST['month'] = $today['mon']; } if (!isset($_REQUEST['year'])) { $_REQUEST['year'] = $today['year']; } $context['event']['month'] = (int) $_REQUEST['month']; $context['event']['year'] = (int) $_REQUEST['year']; $context['event']['day'] = isset($_REQUEST['day']) ? $_REQUEST['day'] : ($_REQUEST['month'] == $today['mon'] ? $today['mday'] : 0); $context['event']['span'] = isset($_REQUEST['span']) ? $_REQUEST['span'] : 1; // Make sure the year and month are in the valid range. if ($context['event']['month'] < 1 || $context['event']['month'] > 12) { fatal_lang_error('invalid_month', false); } if ($context['event']['year'] < $modSettings['cal_minyear'] || $context['event']['year'] > $modSettings['cal_maxyear']) { fatal_lang_error('invalid_year', false); } // Get a list of boards they can post in. $boards = boardsAllowedTo('post_new'); if (empty($boards)) { fatal_lang_error('cannot_post_new', 'user'); } // Load a list of boards for this event in the context. require_once $sourcedir . '/Subs-MessageIndex.php'; $boardListOptions = array('included_boards' => in_array(0, $boards) ? null : $boards, 'not_redirection' => true, 'use_permissions' => true, 'selected_board' => empty($context['current_board']) ? $modSettings['cal_defaultboard'] : $context['current_board']); $context['event']['categories'] = getBoardList($boardListOptions); } // Find the last day of the month. $context['event']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['event']['month'] == 12 ? 1 : $context['event']['month'] + 1, 0, $context['event']['month'] == 12 ? $context['event']['year'] + 1 : $context['event']['year'])); $context['event']['board'] = !empty($board) ? $board : $modSettings['cal_defaultboard']; } if (empty($context['post_errors'])) { $context['post_errors'] = array(); } // See if any new replies have come along. if (empty($_REQUEST['msg']) && !empty($topic)) { if (empty($options['no_new_reply_warning']) && isset($_REQUEST['last_msg']) && $context['topic_last_message'] > $_REQUEST['last_msg']) { $request = $smcFunc['db_query']('', ' SELECT COUNT(*) FROM {db_prefix}messages WHERE id_topic = {int:current_topic} AND id_msg > {int:last_msg}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : ' AND approved = {int:approved}') . ' LIMIT 1', array('current_topic' => $topic, 'last_msg' => (int) $_REQUEST['last_msg'], 'approved' => 1)); list($context['new_replies']) = $smcFunc['db_fetch_row']($request); $smcFunc['db_free_result']($request); if (!empty($context['new_replies'])) { if ($context['new_replies'] == 1) { $txt['error_new_reply'] = isset($_GET['last_msg']) ? $txt['error_new_reply_reading'] : $txt['error_new_reply']; } else { $txt['error_new_replies'] = sprintf(isset($_GET['last_msg']) ? $txt['error_new_replies_reading'] : $txt['error_new_replies'], $context['new_replies']); } // If they've come from the display page then we treat the error differently.... if (isset($_GET['last_msg'])) { $newRepliesError = $context['new_replies']; } else { $context['post_error'][$context['new_replies'] == 1 ? 'new_reply' : 'new_replies'] = true; } $modSettings['topicSummaryPosts'] = $context['new_replies'] > $modSettings['topicSummaryPosts'] ? max($modSettings['topicSummaryPosts'], 5) : $modSettings['topicSummaryPosts']; } } // Check whether this is a really old post being bumped... if (!empty($modSettings['oldTopicDays']) && $lastPostTime + $modSettings['oldTopicDays'] * 86400 < time() && empty($sticky) && !isset($_REQUEST['subject'])) { $oldTopicError = true; } } // Get a response prefix (like 'Re:') in the default forum language. if (!isset($context['response_prefix']) && !($context['response_prefix'] = cache_get_data('response_prefix'))) { if ($language === $user_info['language']) { $context['response_prefix'] = $txt['response_prefix']; } else { loadLanguage('index', $language, false); $context['response_prefix'] = $txt['response_prefix']; loadLanguage('index'); } cache_put_data('response_prefix', $context['response_prefix'], 600); } // Previewing, modifying, or posting? if (isset($_REQUEST['message']) || !empty($context['post_error'])) { // Validate inputs. if (empty($context['post_error'])) { if (htmltrim__recursive(htmlspecialchars__recursive($_REQUEST['subject'])) == '') { $context['post_error']['no_subject'] = true; } if (htmltrim__recursive(htmlspecialchars__recursive($_REQUEST['message'])) == '') { $context['post_error']['no_message'] = true; } if (!empty($modSettings['max_messageLength']) && $smcFunc['strlen']($_REQUEST['message']) > $modSettings['max_messageLength']) { $context['post_error']['long_message'] = true; } // Are you... a guest? if ($user_info['is_guest']) { $_REQUEST['guestname'] = !isset($_REQUEST['guestname']) ? '' : trim($_REQUEST['guestname']); $_REQUEST['email'] = !isset($_REQUEST['email']) ? '' : trim($_REQUEST['email']); // Validate the name and email. if (!isset($_REQUEST['guestname']) || trim(strtr($_REQUEST['guestname'], '_', ' ')) == '') { $context['post_error']['no_name'] = true; } elseif ($smcFunc['strlen']($_REQUEST['guestname']) > 25) { $context['post_error']['long_name'] = true; } else { require_once $sourcedir . '/Subs-Members.php'; if (isReservedName(htmlspecialchars($_REQUEST['guestname']), 0, true, false)) { $context['post_error']['bad_name'] = true; } } if (empty($modSettings['guest_post_no_email'])) { if (!isset($_REQUEST['email']) || $_REQUEST['email'] == '') { $context['post_error']['no_email'] = true; } elseif (preg_match('~^[0-9A-Za-z=_+\\-/][0-9A-Za-z=_\'+\\-/\\.]*@[\\w\\-]+(\\.[\\w\\-]+)*(\\.[\\w]{2,6})$~', $_REQUEST['email']) == 0) { $context['post_error']['bad_email'] = true; } } } // This is self explanatory - got any questions? if (isset($_REQUEST['question']) && trim($_REQUEST['question']) == '') { $context['post_error']['no_question'] = true; } // This means they didn't click Post and get an error. $really_previewing = true; } else { if (!isset($_REQUEST['subject'])) { $_REQUEST['subject'] = ''; } if (!isset($_REQUEST['message'])) { $_REQUEST['message'] = ''; } if (!isset($_REQUEST['icon'])) { $_REQUEST['icon'] = 'xx'; } // They are previewing if they asked to preview (i.e. came from quick reply). $really_previewing = !empty($_POST['preview']); } // In order to keep the approval status flowing through, we have to pass it through the form... $context['becomes_approved'] = empty($_REQUEST['not_approved']); $context['show_approval'] = isset($_REQUEST['approve']) ? $_REQUEST['approve'] ? 2 : 1 : 0; $context['can_announce'] &= $context['becomes_approved']; // Set up the inputs for the form. $form_subject = strtr($smcFunc['htmlspecialchars']($_REQUEST['subject']), array("\r" => '', "\n" => '', "\t" => '')); $form_message = $smcFunc['htmlspecialchars']($_REQUEST['message'], ENT_QUOTES); // Make sure the subject isn't too long - taking into account special characters. if ($smcFunc['strlen']($form_subject) > 100) { $form_subject = $smcFunc['substr']($form_subject, 0, 100); } // Have we inadvertently trimmed off the subject of useful information? if ($smcFunc['htmltrim']($form_subject) === '') { $context['post_error']['no_subject'] = true; } // Any errors occurred? if (!empty($context['post_error'])) { loadLanguage('Errors'); $context['error_type'] = 'minor'; $context['post_error']['messages'] = array(); foreach ($context['post_error'] as $post_error => $dummy) { if ($post_error == 'messages') { continue; } if ($post_error == 'long_message') { $txt['error_' . $post_error] = sprintf($txt['error_' . $post_error], $modSettings['max_messageLength']); } $context['post_error']['messages'][] = $txt['error_' . $post_error]; // If it's not a minor error flag it as such. if (!in_array($post_error, array('new_reply', 'not_approved', 'new_replies', 'old_topic', 'need_qr_verification'))) { $context['error_type'] = 'serious'; } } } if (isset($_REQUEST['poll'])) { $context['question'] = isset($_REQUEST['question']) ? $smcFunc['htmlspecialchars'](trim($_REQUEST['question'])) : ''; $context['choices'] = array(); $choice_id = 0; $_POST['options'] = empty($_POST['options']) ? array() : htmlspecialchars__recursive($_POST['options']); foreach ($_POST['options'] as $option) { if (trim($option) == '') { continue; } $context['choices'][] = array('id' => $choice_id++, 'number' => $choice_id, 'label' => $option, 'is_last' => false); } if (count($context['choices']) < 2) { $context['choices'][] = array('id' => $choice_id++, 'number' => $choice_id, 'label' => '', 'is_last' => false); $context['choices'][] = array('id' => $choice_id++, 'number' => $choice_id, 'label' => '', 'is_last' => false); } $context['choices'][count($context['choices']) - 1]['is_last'] = true; } // Are you... a guest? if ($user_info['is_guest']) { $_REQUEST['guestname'] = !isset($_REQUEST['guestname']) ? '' : trim($_REQUEST['guestname']); $_REQUEST['email'] = !isset($_REQUEST['email']) ? '' : trim($_REQUEST['email']); $_REQUEST['guestname'] = htmlspecialchars($_REQUEST['guestname']); $context['name'] = $_REQUEST['guestname']; $_REQUEST['email'] = htmlspecialchars($_REQUEST['email']); $context['email'] = $_REQUEST['email']; $user_info['name'] = $_REQUEST['guestname']; } // Only show the preview stuff if they hit Preview. if ($really_previewing == true || isset($_REQUEST['xml'])) { // Set up the preview message and subject and censor them... $context['preview_message'] = $form_message; preparsecode($form_message, true); preparsecode($context['preview_message']); // Do all bulletin board code tags, with or without smileys. $context['preview_message'] = parse_bbc($context['preview_message'], isset($_REQUEST['ns']) ? 0 : 1); if ($form_subject != '') { $context['preview_subject'] = $form_subject; censorText($context['preview_subject']); censorText($context['preview_message']); } else { $context['preview_subject'] = '<em>' . $txt['no_subject'] . '</em>'; } // Protect any CDATA blocks. if (isset($_REQUEST['xml'])) { $context['preview_message'] = strtr($context['preview_message'], array(']]>' => ']]]]><![CDATA[>')); } } // Set up the checkboxes. $context['notify'] = !empty($_REQUEST['notify']); $context['use_smileys'] = !isset($_REQUEST['ns']); $context['icon'] = isset($_REQUEST['icon']) ? preg_replace('~[\\./\\\\*\':"<>]~', '', $_REQUEST['icon']) : 'xx'; // Set the destination action for submission. $context['destination'] = 'post2;start=' . $_REQUEST['start'] . (isset($_REQUEST['msg']) ? ';msg=' . $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id'] : '') . (isset($_REQUEST['poll']) ? ';poll' : ''); $context['submit_label'] = isset($_REQUEST['msg']) ? $txt['save'] : $txt['post']; // Previewing an edit? if (isset($_REQUEST['msg']) && !empty($topic)) { // Get the existing message. $request = $smcFunc['db_query']('', ' SELECT m.id_member, m.modified_time, m.smileys_enabled, m.body, m.poster_name, m.poster_email, m.subject, m.icon, m.approved, IFNULL(a.size, -1) AS filesize, a.filename, a.id_attach, a.approved AS attachment_approved, t.id_member_started AS id_member_poster, m.poster_time FROM {db_prefix}messages AS m INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic}) LEFT JOIN {db_prefix}attachments AS a ON (a.id_msg = m.id_msg AND a.attachment_type = {int:attachment_type}) WHERE m.id_msg = {int:id_msg} AND m.id_topic = {int:current_topic}', array('current_topic' => $topic, 'attachment_type' => 0, 'id_msg' => $_REQUEST['msg'])); // The message they were trying to edit was most likely deleted. // !!! Change this error message? if ($smcFunc['db_num_rows']($request) == 0) { fatal_lang_error('no_board', false); } $row = $smcFunc['db_fetch_assoc']($request); $attachment_stuff = array($row); while ($row2 = $smcFunc['db_fetch_assoc']($request)) { $attachment_stuff[] = $row2; } $smcFunc['db_free_result']($request); if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any')) { // Give an extra five minutes over the disable time threshold, so they can type - assuming the post is public. if ($row['approved'] && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time()) { fatal_lang_error('modify_post_time_passed', false); } elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_own')) { isAllowedTo('modify_replies'); } else { isAllowedTo('modify_own'); } } elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_any')) { isAllowedTo('modify_replies'); } else { isAllowedTo('modify_any'); } if (!empty($modSettings['attachmentEnable'])) { $request = $smcFunc['db_query']('', ' SELECT IFNULL(size, -1) AS filesize, filename, id_attach, approved FROM {db_prefix}attachments WHERE id_msg = {int:id_msg} AND attachment_type = {int:attachment_type}', array('id_msg' => (int) $_REQUEST['msg'], 'attachment_type' => 0)); while ($row = $smcFunc['db_fetch_assoc']($request)) { if ($row['filesize'] <= 0) { continue; } $context['current_attachments'][] = array('name' => htmlspecialchars($row['filename']), 'id' => $row['id_attach'], 'approved' => $row['approved']); } $smcFunc['db_free_result']($request); } // Allow moderators to change names.... if (allowedTo('moderate_forum') && !empty($topic)) { $request = $smcFunc['db_query']('', ' SELECT id_member, poster_name, poster_email FROM {db_prefix}messages WHERE id_msg = {int:id_msg} AND id_topic = {int:current_topic} LIMIT 1', array('current_topic' => $topic, 'id_msg' => (int) $_REQUEST['msg'])); $row = $smcFunc['db_fetch_assoc']($request); $smcFunc['db_free_result']($request); if (empty($row['id_member'])) { $context['name'] = htmlspecialchars($row['poster_name']); $context['email'] = htmlspecialchars($row['poster_email']); } } } // No check is needed, since nothing is really posted. checkSubmitOnce('free'); } elseif (isset($_REQUEST['msg']) && !empty($topic)) { $_REQUEST['msg'] = (int) $_REQUEST['msg']; // Get the existing message. $request = $smcFunc['db_query']('', ' SELECT m.id_member, m.modified_time, m.smileys_enabled, m.body, m.poster_name, m.poster_email, m.subject, m.icon, m.approved, IFNULL(a.size, -1) AS filesize, a.filename, a.id_attach, a.approved AS attachment_approved, t.id_member_started AS id_member_poster, m.poster_time FROM {db_prefix}messages AS m INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic}) LEFT JOIN {db_prefix}attachments AS a ON (a.id_msg = m.id_msg AND a.attachment_type = {int:attachment_type}) WHERE m.id_msg = {int:id_msg} AND m.id_topic = {int:current_topic}', array('current_topic' => $topic, 'attachment_type' => 0, 'id_msg' => $_REQUEST['msg'])); // The message they were trying to edit was most likely deleted. // !!! Change this error message? if ($smcFunc['db_num_rows']($request) == 0) { fatal_lang_error('no_board', false); } $row = $smcFunc['db_fetch_assoc']($request); $attachment_stuff = array($row); while ($row2 = $smcFunc['db_fetch_assoc']($request)) { $attachment_stuff[] = $row2; } $smcFunc['db_free_result']($request); if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any')) { // Give an extra five minutes over the disable time threshold, so they can type - assuming the post is public. if ($row['approved'] && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time()) { fatal_lang_error('modify_post_time_passed', false); } elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_own')) { isAllowedTo('modify_replies'); } else { isAllowedTo('modify_own'); } } elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_any')) { isAllowedTo('modify_replies'); } else { isAllowedTo('modify_any'); } // When was it last modified? if (!empty($row['modified_time'])) { $context['last_modified'] = timeformat($row['modified_time']); } // Get the stuff ready for the form. $form_subject = $row['subject']; $form_message = un_preparsecode($row['body']); censorText($form_message); censorText($form_subject); // Check the boxes that should be checked. $context['use_smileys'] = !empty($row['smileys_enabled']); $context['icon'] = $row['icon']; // Show an "approve" box if the user can approve it, and the message isn't approved. if (!$row['approved'] && !$context['show_approval']) { $context['show_approval'] = allowedTo('approve_posts'); } // Load up 'em attachments! foreach ($attachment_stuff as $attachment) { if ($attachment['filesize'] >= 0 && !empty($modSettings['attachmentEnable'])) { $context['current_attachments'][] = array('name' => htmlspecialchars($attachment['filename']), 'id' => $attachment['id_attach'], 'approved' => $attachment['attachment_approved']); } } // Allow moderators to change names.... if (allowedTo('moderate_forum') && empty($row['id_member'])) { $context['name'] = htmlspecialchars($row['poster_name']); $context['email'] = htmlspecialchars($row['poster_email']); } // Set the destinaton. $context['destination'] = 'post2;start=' . $_REQUEST['start'] . ';msg=' . $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id'] . (isset($_REQUEST['poll']) ? ';poll' : ''); $context['submit_label'] = $txt['save']; } else { // By default.... $context['use_smileys'] = true; $context['icon'] = 'xx'; if ($user_info['is_guest']) { $context['name'] = isset($_SESSION['guest_name']) ? $_SESSION['guest_name'] : ''; $context['email'] = isset($_SESSION['guest_email']) ? $_SESSION['guest_email'] : ''; } $context['destination'] = 'post2;start=' . $_REQUEST['start'] . (isset($_REQUEST['poll']) ? ';poll' : ''); $context['submit_label'] = $txt['post']; // Posting a quoted reply? if (!empty($topic) && !empty($_REQUEST['quote'])) { // Make sure they _can_ quote this post, and if so get it. $request = $smcFunc['db_query']('', ' SELECT m.subject, IFNULL(mem.real_name, m.poster_name) AS poster_name, m.poster_time, m.body FROM {db_prefix}messages AS m 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}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : ' AND m.approved = {int:is_approved}') . ' LIMIT 1', array('id_msg' => (int) $_REQUEST['quote'], 'is_approved' => 1)); if ($smcFunc['db_num_rows']($request) == 0) { fatal_lang_error('quoted_post_deleted', false); } list($form_subject, $mname, $mdate, $form_message) = $smcFunc['db_fetch_row']($request); $smcFunc['db_free_result']($request); // Add 'Re: ' to the front of the quoted subject. if (trim($context['response_prefix']) != '' && $smcFunc['strpos']($form_subject, trim($context['response_prefix'])) !== 0) { $form_subject = $context['response_prefix'] . $form_subject; } // Censor the message and subject. censorText($form_message); censorText($form_subject); // But if it's in HTML world, turn them into htmlspecialchar's so they can be edited! if (strpos($form_message, '[html]') !== false) { $parts = preg_split('~(\\[/code\\]|\\[code(?:=[^\\]]+)?\\])~i', $form_message, -1, PREG_SPLIT_DELIM_CAPTURE); for ($i = 0, $n = count($parts); $i < $n; $i++) { // It goes 0 = outside, 1 = begin tag, 2 = inside, 3 = close tag, repeat. if ($i % 4 == 0) { $parts[$i] = preg_replace('~\\[html\\](.+?)\\[/html\\]~ise', '\'[html]\' . preg_replace(\'~<br\\s?/?' . '>~i\', \'<br /><br />\', \'$1\') . \'[/html]\'', $parts[$i]); } } $form_message = implode('', $parts); } $form_message = preg_replace('~<br ?/?' . '>~i', "\n", $form_message); // Remove any nested quotes, if necessary. if (!empty($modSettings['removeNestedQuotes'])) { $form_message = preg_replace(array('~\\n?\\[quote.*?\\].+?\\[/quote\\]\\n?~is', '~^\\n~', '~\\[/quote\\]~'), '', $form_message); } // Add a quote string on the front and end. $form_message = '[quote author=' . $mname . ' link=topic=' . $topic . '.msg' . (int) $_REQUEST['quote'] . '#msg' . (int) $_REQUEST['quote'] . ' date=' . $mdate . ']' . "\n" . rtrim($form_message) . "\n" . '[/quote]'; } elseif (!empty($topic) && empty($_REQUEST['quote'])) { // Get the first message's subject. $form_subject = $first_subject; // Add 'Re: ' to the front of the subject. if (trim($context['response_prefix']) != '' && $form_subject != '' && $smcFunc['strpos']($form_subject, trim($context['response_prefix'])) !== 0) { $form_subject = $context['response_prefix'] . $form_subject; } // Censor the subject. censorText($form_subject); $form_message = ''; } else { $form_subject = isset($_GET['subject']) ? $_GET['subject'] : ''; $form_message = ''; } } // !!! This won't work if you're posting an event. if (allowedTo('post_attachment') || allowedTo('post_unapproved_attachments')) { if (empty($_SESSION['temp_attachments'])) { $_SESSION['temp_attachments'] = array(); } if (!empty($modSettings['currentAttachmentUploadDir'])) { if (!is_array($modSettings['attachmentUploadDir'])) { $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']); } // Just use the current path for temp files. $current_attach_dir = $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']]; } else { $current_attach_dir = $modSettings['attachmentUploadDir']; } // If this isn't a new post, check the current attachments. if (isset($_REQUEST['msg'])) { $request = $smcFunc['db_query']('', ' SELECT COUNT(*), SUM(size) FROM {db_prefix}attachments WHERE id_msg = {int:id_msg} AND attachment_type = {int:attachment_type}', array('id_msg' => (int) $_REQUEST['msg'], 'attachment_type' => 0)); list($quantity, $total_size) = $smcFunc['db_fetch_row']($request); $smcFunc['db_free_result']($request); } else { $quantity = 0; $total_size = 0; } $temp_start = 0; if (!empty($_SESSION['temp_attachments'])) { if ($context['current_action'] != 'post2' || !empty($_POST['from_qr'])) { $context['post_error']['messages'][] = $txt['error_temp_attachments']; $context['error_type'] = 'minor'; } foreach ($_SESSION['temp_attachments'] as $attachID => $name) { $temp_start++; if (preg_match('~^post_tmp_' . $user_info['id'] . '_\\d+$~', $attachID) == 0) { unset($_SESSION['temp_attachments'][$attachID]); continue; } if (!empty($_POST['attach_del']) && !in_array($attachID, $_POST['attach_del'])) { $deleted_attachments = true; unset($_SESSION['temp_attachments'][$attachID]); @unlink($current_attach_dir . '/' . $attachID); continue; } $quantity++; $total_size += filesize($current_attach_dir . '/' . $attachID); $context['current_attachments'][] = array('name' => htmlspecialchars($name), 'id' => $attachID, 'approved' => 1); } } if (!empty($_POST['attach_del'])) { $del_temp = array(); foreach ($_POST['attach_del'] as $i => $dummy) { $del_temp[$i] = (int) $dummy; } foreach ($context['current_attachments'] as $k => $dummy) { if (!in_array($dummy['id'], $del_temp)) { $context['current_attachments'][$k]['unchecked'] = true; $deleted_attachments = !isset($deleted_attachments) || is_bool($deleted_attachments) ? 1 : $deleted_attachments + 1; $quantity--; } } } if (!empty($_FILES['attachment'])) { foreach ($_FILES['attachment']['tmp_name'] as $n => $dummy) { if ($_FILES['attachment']['name'][$n] == '') { continue; } if (!is_uploaded_file($_FILES['attachment']['tmp_name'][$n]) || @ini_get('open_basedir') == '' && !file_exists($_FILES['attachment']['tmp_name'][$n])) { fatal_lang_error('attach_timeout', 'critical'); } if (!empty($modSettings['attachmentSizeLimit']) && $_FILES['attachment']['size'][$n] > $modSettings['attachmentSizeLimit'] * 1024) { fatal_lang_error('file_too_big', false, array($modSettings['attachmentSizeLimit'])); } $quantity++; if (!empty($modSettings['attachmentNumPerPostLimit']) && $quantity > $modSettings['attachmentNumPerPostLimit']) { fatal_lang_error('attachments_limit_per_post', false, array($modSettings['attachmentNumPerPostLimit'])); } $total_size += $_FILES['attachment']['size'][$n]; if (!empty($modSettings['attachmentPostLimit']) && $total_size > $modSettings['attachmentPostLimit'] * 1024) { fatal_lang_error('file_too_big', false, array($modSettings['attachmentPostLimit'])); } if (!empty($modSettings['attachmentCheckExtensions'])) { if (!in_array(strtolower(substr(strrchr($_FILES['attachment']['name'][$n], '.'), 1)), explode(',', strtolower($modSettings['attachmentExtensions'])))) { fatal_error($_FILES['attachment']['name'][$n] . '.<br />' . $txt['cant_upload_type'] . ' ' . $modSettings['attachmentExtensions'] . '.', false); } } if (!empty($modSettings['attachmentDirSizeLimit'])) { // Make sure the directory isn't full. $dirSize = 0; $dir = @opendir($current_attach_dir) or fatal_lang_error('cant_access_upload_path', 'critical'); while ($file = readdir($dir)) { if ($file == '.' || $file == '..') { continue; } if (preg_match('~^post_tmp_\\d+_\\d+$~', $file) != 0) { // Temp file is more than 5 hours old! if (filemtime($current_attach_dir . '/' . $file) < time() - 18000) { @unlink($current_attach_dir . '/' . $file); } continue; } $dirSize += filesize($current_attach_dir . '/' . $file); } closedir($dir); // Too big! Maybe you could zip it or something... if ($_FILES['attachment']['size'][$n] + $dirSize > $modSettings['attachmentDirSizeLimit'] * 1024) { fatal_lang_error('ran_out_of_space'); } } if (!is_writable($current_attach_dir)) { fatal_lang_error('attachments_no_write', 'critical'); } $attachID = 'post_tmp_' . $user_info['id'] . '_' . $temp_start++; $_SESSION['temp_attachments'][$attachID] = basename($_FILES['attachment']['name'][$n]); $context['current_attachments'][] = array('name' => htmlspecialchars(basename($_FILES['attachment']['name'][$n])), 'id' => $attachID, 'approved' => 1); $destName = $current_attach_dir . '/' . $attachID; if (!move_uploaded_file($_FILES['attachment']['tmp_name'][$n], $destName)) { fatal_lang_error('attach_timeout', 'critical'); } @chmod($destName, 0644); } } } // If we are coming here to make a reply, and someone has already replied... make a special warning message. if (isset($newRepliesError)) { $context['post_error']['messages'][] = $newRepliesError == 1 ? $txt['error_new_reply'] : $txt['error_new_replies']; $context['error_type'] = 'minor'; } if (isset($oldTopicError)) { $context['post_error']['messages'][] = sprintf($txt['error_old_topic'], $modSettings['oldTopicDays']); $context['error_type'] = 'minor'; } // What are you doing? Posting a poll, modifying, previewing, new post, or reply... if (isset($_REQUEST['poll'])) { $context['page_title'] = $txt['new_poll']; } elseif ($context['make_event']) { $context['page_title'] = $context['event']['id'] == -1 ? $txt['calendar_post_event'] : $txt['calendar_edit']; } elseif (isset($_REQUEST['msg'])) { $context['page_title'] = $txt['modify_msg']; } elseif (isset($_REQUEST['subject'], $context['preview_subject'])) { $context['page_title'] = $txt['preview'] . ' - ' . strip_tags($context['preview_subject']); } elseif (empty($topic)) { $context['page_title'] = $txt['start_new_topic']; } else { $context['page_title'] = $txt['post_reply']; } // Build the link tree. if (empty($topic)) { $context['linktree'][] = array('name' => '<em>' . $txt['start_new_topic'] . '</em>'); } else { $context['linktree'][] = array('url' => $scripturl . '?topic=' . $topic . '.' . $_REQUEST['start'], 'name' => $form_subject, 'extra_before' => '<span' . ($settings['linktree_inline'] ? ' class="smalltext"' : '') . '><strong class="nav">' . $context['page_title'] . ' ( </strong></span>', 'extra_after' => '<span' . ($settings['linktree_inline'] ? ' class="smalltext"' : '') . '><strong class="nav"> )</strong></span>'); } // Give wireless a linktree url to the post screen, so that they can switch to full version. if (WIRELESS) { $context['linktree'][count($context['linktree']) - 1]['url'] = $scripturl . '?action=post;' . (!empty($topic) ? 'topic=' . $topic : 'board=' . $board) . '.' . $_REQUEST['start'] . (isset($_REQUEST['msg']) ? ';msg=' . (int) $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id'] : ''); } // If they've unchecked an attachment, they may still want to attach that many more files, but don't allow more than num_allowed_attachments. // !!! This won't work if you're posting an event. $context['num_allowed_attachments'] = empty($modSettings['attachmentNumPerPostLimit']) ? 50 : min($modSettings['attachmentNumPerPostLimit'] - count($context['current_attachments']) + (isset($deleted_attachments) ? $deleted_attachments : 0), $modSettings['attachmentNumPerPostLimit']); $context['can_post_attachment'] = !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1 && (allowedTo('post_attachment') || $modSettings['postmod_active'] && allowedTo('post_unapproved_attachments')) && $context['num_allowed_attachments'] > 0; $context['can_post_attachment_unapproved'] = allowedTo('post_attachment'); $context['subject'] = addcslashes($form_subject, '"'); $context['message'] = str_replace(array('"', '<', '>', ' '), array('"', '<', '>', ' '), $form_message); // Needed for the editor and message icons. require_once $sourcedir . '/Subs-Editor.php'; // Now create the editor. $editorOptions = array('id' => 'message', 'value' => $context['message'], 'labels' => array('post_button' => $context['submit_label']), 'height' => '175px', 'width' => '100%', 'preview_type' => 2); create_control_richedit($editorOptions); // Store the ID. $context['post_box_name'] = $editorOptions['id']; $context['attached'] = ''; $context['make_poll'] = isset($_REQUEST['poll']); // Message icons - customized icons are off? $context['icons'] = getMessageIcons($board); if (!empty($context['icons'])) { $context['icons'][count($context['icons']) - 1]['is_last'] = true; } $context['icon_url'] = ''; for ($i = 0, $n = count($context['icons']); $i < $n; $i++) { $context['icons'][$i]['selected'] = $context['icon'] == $context['icons'][$i]['value']; if ($context['icons'][$i]['selected']) { $context['icon_url'] = $context['icons'][$i]['url']; } } if (empty($context['icon_url'])) { $context['icon_url'] = $settings[file_exists($settings['theme_dir'] . '/images/post/' . $context['icon'] . '.gif') ? 'images_url' : 'default_images_url'] . '/post/' . $context['icon'] . '.gif'; array_unshift($context['icons'], array('value' => $context['icon'], 'name' => $txt['current_icon'], 'url' => $context['icon_url'], 'is_last' => empty($context['icons']), 'selected' => true)); } if (!empty($topic) && !empty($modSettings['topicSummaryPosts'])) { getTopic(); } // If the user can post attachments prepare the warning labels. if ($context['can_post_attachment']) { $context['allowed_extensions'] = strtr($modSettings['attachmentExtensions'], array(',' => ', ')); $context['attachment_restrictions'] = array(); $attachmentRestrictionTypes = array('attachmentNumPerPostLimit', 'attachmentPostLimit', 'attachmentSizeLimit'); foreach ($attachmentRestrictionTypes as $type) { if (!empty($modSettings[$type])) { $context['attachment_restrictions'][] = sprintf($txt['attach_restrict_' . $type], $modSettings[$type]); } } } $context['back_to_topic'] = isset($_REQUEST['goback']) || isset($_REQUEST['msg']) && !isset($_REQUEST['subject']); $context['show_additional_options'] = !empty($_POST['additional_options']) || !empty($_SESSION['temp_attachments']) || !empty($deleted_attachments); $context['is_new_topic'] = empty($topic); $context['is_new_post'] = !isset($_REQUEST['msg']); $context['is_first_post'] = $context['is_new_topic'] || isset($_REQUEST['msg']) && $_REQUEST['msg'] == $id_first_msg; // Do we need to show the visual verification image? $context['require_verification'] = !$user_info['is_mod'] && !$user_info['is_admin'] && !empty($modSettings['posts_require_captcha']) && ($user_info['posts'] < $modSettings['posts_require_captcha'] || $user_info['is_guest'] && $modSettings['posts_require_captcha'] == -1); if ($context['require_verification']) { require_once $sourcedir . '/Subs-Editor.php'; $verificationOptions = array('id' => 'post'); $context['require_verification'] = create_control_verification($verificationOptions); $context['visual_verification_id'] = $verificationOptions['id']; } // If they came from quick reply, and have to enter verification details, give them some notice. if (!empty($_REQUEST['from_qr']) && !empty($context['require_verification'])) { $context['post_error']['messages'][] = $txt['enter_verification_details']; $context['error_type'] = 'minor'; } // WYSIWYG only works if BBC is enabled $modSettings['disable_wysiwyg'] = !empty($modSettings['disable_wysiwyg']) || empty($modSettings['enableBBC']); // Register this form in the session variables. checkSubmitOnce('register'); // Finally, load the template. if (WIRELESS && WIRELESS_PROTOCOL != 'wap') { $context['sub_template'] = WIRELESS_PROTOCOL . '_post'; } elseif (!isset($_REQUEST['xml'])) { loadTemplate('Post'); } }
/** * Handles showing the post screen, loading the post to be modified, and loading any post quoted. * * - additionally handles previews of posts. * - requires different permissions depending on the actions, but most notably post_new, post_reply_own, and post_reply_any. * - shows options for the editing and posting of calendar events and attachments, as well as the posting of polls. * - accessed from ?action=post. * * @uses the Post template and language file, main sub template. */ public function action_post() { global $txt, $scripturl, $topic, $modSettings, $board, $user_info, $context, $options; loadLanguage('Post'); loadLanguage('Errors'); require_once SOURCEDIR . '/AttachmentErrorContext.class.php'; // You can't reply with a poll... hacker. if (isset($_REQUEST['poll']) && !empty($topic) && !isset($_REQUEST['msg'])) { unset($_REQUEST['poll']); } $post_errors = Error_Context::context('post', 1); $attach_errors = Attachment_Error_Context::context(); $attach_errors->activate(); $first_subject = ''; // Posting an event? $context['make_event'] = isset($_REQUEST['calendar']); $context['robot_no_index'] = true; $template_layers = Template_Layers::getInstance(); $template_layers->add('postarea'); // You must be posting to *some* board. if (empty($board) && !$context['make_event']) { fatal_lang_error('no_board', false); } if ($context['make_event']) { $template_layers->add('make_event'); } // All those wonderful modifiers and attachments $template_layers->add('additional_options', 200); require_once SUBSDIR . '/Post.subs.php'; require_once SUBSDIR . '/Messages.subs.php'; require_once SUBSDIR . '/Topic.subs.php'; if (isset($_REQUEST['xml'])) { $context['sub_template'] = 'post'; // Just in case of an earlier error... $context['preview_message'] = ''; $context['preview_subject'] = ''; } if (!empty($modSettings['mentions_enabled']) && !empty($_REQUEST['uid'])) { $context['member_ids'] = array_unique(array_map('intval', $_REQUEST['uid'])); } // No message is complete without a topic. if (empty($topic) && !empty($_REQUEST['msg'])) { $topic = associatedTopic((int) $_REQUEST['msg']); if (empty($topic)) { unset($_REQUEST['msg'], $_POST['msg'], $_GET['msg']); } } // Check if it's locked. It isn't locked if no topic is specified. if (!empty($topic)) { list($locked, $context['notify'], $sticky, $pollID, $context['topic_last_message'], $id_member_poster, $id_first_msg, $first_subject, $lastPostTime) = array_values(topicUserAttributes($topic, $user_info['id'])); // If this topic already has a poll, they sure can't add another. if (isset($_REQUEST['poll']) && $pollID > 0) { unset($_REQUEST['poll']); } if (empty($_REQUEST['msg'])) { if ($user_info['is_guest'] && !allowedTo('post_reply_any') && (!$modSettings['postmod_active'] || !allowedTo('post_unapproved_replies_any'))) { is_not_guest(); } // By default the reply will be approved... $context['becomes_approved'] = true; if ($id_member_poster != $user_info['id']) { if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_any') && !allowedTo('post_reply_any')) { $context['becomes_approved'] = false; } else { isAllowedTo('post_reply_any'); } } elseif (!allowedTo('post_reply_any')) { if ($modSettings['postmod_active']) { if (allowedTo('post_unapproved_replies_own') && !allowedTo('post_reply_own')) { $context['becomes_approved'] = false; } elseif ($user_info['is_guest'] && allowedTo('post_unapproved_replies_any')) { $context['becomes_approved'] = false; } else { isAllowedTo('post_reply_own'); } } else { isAllowedTo('post_reply_own'); } } } else { $context['becomes_approved'] = true; } $context['can_lock'] = allowedTo('lock_any') || $user_info['id'] == $id_member_poster && allowedTo('lock_own'); $context['can_sticky'] = allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']); $context['notify'] = !empty($context['notify']); $context['sticky'] = isset($_REQUEST['sticky']) ? !empty($_REQUEST['sticky']) : $sticky; // It's a new reply if (empty($_REQUEST['msg'])) { $context['can_add_poll'] = false; } else { $context['can_add_poll'] = (allowedTo('poll_add_any') || !empty($_REQUEST['msg']) && $id_first_msg == $_REQUEST['msg'] && allowedTo('poll_add_own')) && !empty($modSettings['pollMode']) && $pollID <= 0; } } else { $context['becomes_approved'] = true; if (!$context['make_event'] || !empty($board)) { if ($modSettings['postmod_active'] && !allowedTo('post_new') && allowedTo('post_unapproved_topics')) { $context['becomes_approved'] = false; } else { isAllowedTo('post_new'); } } $locked = 0; // @todo These won't work if you're making an event. $context['can_lock'] = allowedTo(array('lock_any', 'lock_own')); $context['can_sticky'] = allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']); $context['notify'] = !empty($context['notify']); $context['sticky'] = !empty($_REQUEST['sticky']); $context['can_add_poll'] = (allowedTo('poll_add_any') || allowedTo('poll_add_own')) && !empty($modSettings['pollMode']); } // @todo These won't work if you're posting an event! $context['can_notify'] = allowedTo('mark_any_notify'); $context['can_move'] = allowedTo('move_any'); $context['move'] = !empty($_REQUEST['move']); $context['announce'] = !empty($_REQUEST['announce']); if ($context['can_add_poll']) { addJavascriptVar(array('poll_remove' => $txt['poll_remove'], 'poll_add' => $txt['add_poll']), true); } // You can only announce topics that will get approved... $context['can_announce'] = allowedTo('announce_topic') && $context['becomes_approved']; $context['locked'] = !empty($locked) || !empty($_REQUEST['lock']); $context['can_quote'] = empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC'])); // Generally don't show the approval box... (Assume we want things approved) $context['show_approval'] = allowedTo('approve_posts') && $context['becomes_approved'] ? 2 : (allowedTo('approve_posts') ? 1 : 0); // An array to hold all the attachments for this topic. $context['attachments']['current'] = array(); // Don't allow a post if it's locked and you aren't all powerful. if ($locked && !allowedTo('moderate_board')) { fatal_lang_error('topic_locked', false); } // Check the users permissions - is the user allowed to add or post a poll? if (isset($_REQUEST['poll']) && !empty($modSettings['pollMode'])) { // New topic, new poll. if (empty($topic)) { isAllowedTo('poll_post'); } elseif ($user_info['id'] == $id_member_poster && !allowedTo('poll_add_any')) { isAllowedTo('poll_add_own'); } else { isAllowedTo('poll_add_any'); } $context['can_moderate_poll'] = true; require_once SUBSDIR . '/Members.subs.php'; $allowedVoteGroups = groupsAllowedTo('poll_vote', $board); // Set up the poll options. $context['poll'] = array('max_votes' => empty($_POST['poll_max_votes']) ? '1' : max(1, $_POST['poll_max_votes']), 'hide_results' => empty($_POST['poll_hide']) ? 0 : $_POST['poll_hide'], 'expiration' => !isset($_POST['poll_expire']) ? '' : $_POST['poll_expire'], 'change_vote' => isset($_POST['poll_change_vote']), 'guest_vote' => isset($_POST['poll_guest_vote']), 'guest_vote_allowed' => in_array(-1, $allowedVoteGroups['allowed'])); // Make all five poll choices empty. $context['choices'] = array(array('id' => 0, 'number' => 1, 'label' => '', 'is_last' => false), array('id' => 1, 'number' => 2, 'label' => '', 'is_last' => false), array('id' => 2, 'number' => 3, 'label' => '', 'is_last' => false), array('id' => 3, 'number' => 4, 'label' => '', 'is_last' => false), array('id' => 4, 'number' => 5, 'label' => '', 'is_last' => true)); $context['last_choice_id'] = 4; } if ($context['make_event']) { // They might want to pick a board. if (!isset($context['current_board'])) { $context['current_board'] = 0; } // Start loading up the event info. $context['event'] = array(); $context['event']['title'] = isset($_REQUEST['evtitle']) ? htmlspecialchars(stripslashes($_REQUEST['evtitle']), ENT_COMPAT, 'UTF-8') : ''; $context['event']['id'] = isset($_REQUEST['eventid']) ? (int) $_REQUEST['eventid'] : -1; $context['event']['new'] = $context['event']['id'] == -1; // Permissions check! isAllowedTo('calendar_post'); // Editing an event? (but NOT previewing!?) if (empty($context['event']['new']) && !isset($_REQUEST['subject'])) { // If the user doesn't have permission to edit the post in this topic, redirect them. if ((empty($id_member_poster) || $id_member_poster != $user_info['id'] || !allowedTo('modify_own')) && !allowedTo('modify_any')) { require_once CONTROLLERDIR . '/Calendar.controller.php'; $controller = new Calendar_Controller(); return $controller->action_post(); } // Get the current event information. require_once SUBSDIR . '/Calendar.subs.php'; $event_info = getEventProperties($context['event']['id']); // Make sure the user is allowed to edit this event. if ($event_info['member'] != $user_info['id']) { isAllowedTo('calendar_edit_any'); } elseif (!allowedTo('calendar_edit_any')) { isAllowedTo('calendar_edit_own'); } $context['event']['month'] = $event_info['month']; $context['event']['day'] = $event_info['day']; $context['event']['year'] = $event_info['year']; $context['event']['title'] = $event_info['title']; $context['event']['span'] = $event_info['span']; } else { // Posting a new event? (or preview...) $today = getdate(); // You must have a month and year specified! if (!isset($_REQUEST['month'])) { $_REQUEST['month'] = $today['mon']; } if (!isset($_REQUEST['year'])) { $_REQUEST['year'] = $today['year']; } $context['event']['month'] = (int) $_REQUEST['month']; $context['event']['year'] = (int) $_REQUEST['year']; $context['event']['day'] = isset($_REQUEST['day']) ? $_REQUEST['day'] : ($_REQUEST['month'] == $today['mon'] ? $today['mday'] : 0); $context['event']['span'] = isset($_REQUEST['span']) ? $_REQUEST['span'] : 1; // Make sure the year and month are in the valid range. if ($context['event']['month'] < 1 || $context['event']['month'] > 12) { fatal_lang_error('invalid_month', false); } if ($context['event']['year'] < $modSettings['cal_minyear'] || $context['event']['year'] > $modSettings['cal_maxyear']) { fatal_lang_error('invalid_year', false); } // Get a list of boards they can post in. require_once SUBSDIR . '/Boards.subs.php'; $boards = boardsAllowedTo('post_new'); if (empty($boards)) { fatal_lang_error('cannot_post_new', 'user'); } // Load a list of boards for this event in the context. $boardListOptions = array('included_boards' => in_array(0, $boards) ? null : $boards, 'not_redirection' => true, 'selected_board' => empty($context['current_board']) ? $modSettings['cal_defaultboard'] : $context['current_board']); $context += getBoardList($boardListOptions); } // Find the last day of the month. $context['event']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['event']['month'] == 12 ? 1 : $context['event']['month'] + 1, 0, $context['event']['month'] == 12 ? $context['event']['year'] + 1 : $context['event']['year'])); $context['event']['board'] = !empty($board) ? $board : $modSettings['cal_defaultboard']; } // See if any new replies have come along. if (empty($_REQUEST['msg']) && !empty($topic)) { if (empty($options['no_new_reply_warning']) && isset($_REQUEST['last_msg']) && $context['topic_last_message'] > $_REQUEST['last_msg']) { $context['new_replies'] = countMessagesSince($topic, (int) $_REQUEST['last_msg'], false, $modSettings['postmod_active'] && !allowedTo('approve_posts')); if (!empty($context['new_replies'])) { if ($context['new_replies'] == 1) { $txt['error_new_replies'] = isset($_GET['last_msg']) ? $txt['error_new_reply_reading'] : $txt['error_new_reply']; } else { $txt['error_new_replies'] = sprintf(isset($_GET['last_msg']) ? $txt['error_new_replies_reading'] : $txt['error_new_replies'], $context['new_replies']); } $post_errors->addError('new_replies', 0); $modSettings['topicSummaryPosts'] = $context['new_replies'] > $modSettings['topicSummaryPosts'] ? max($modSettings['topicSummaryPosts'], 5) : $modSettings['topicSummaryPosts']; } } } // Get a response prefix (like 'Re:') in the default forum language. $context['response_prefix'] = response_prefix(); // Previewing, modifying, or posting? // Do we have a body, but an error happened. if (isset($_REQUEST['message']) || $post_errors->hasErrors() || $attach_errors->hasErrors()) { // Validate inputs. if (!$post_errors->hasErrors() && !$attach_errors->hasErrors()) { // This means they didn't click Post and get an error. $really_previewing = true; } else { if (!isset($_REQUEST['subject'])) { $_REQUEST['subject'] = ''; } if (!isset($_REQUEST['message'])) { $_REQUEST['message'] = ''; } if (!isset($_REQUEST['icon'])) { $_REQUEST['icon'] = 'xx'; } // They are previewing if they asked to preview (i.e. came from quick reply). $really_previewing = !empty($_REQUEST['preview']); } // In order to keep the approval status flowing through, we have to pass it through the form... $context['becomes_approved'] = empty($_REQUEST['not_approved']); $context['show_approval'] = isset($_REQUEST['approve']) ? $_REQUEST['approve'] ? 2 : 1 : 0; $context['can_announce'] &= $context['becomes_approved']; // Set up the inputs for the form. $form_subject = strtr(Util::htmlspecialchars($_REQUEST['subject']), array("\r" => '', "\n" => '', "\t" => '')); $form_message = Util::htmlspecialchars($_REQUEST['message'], ENT_QUOTES); // Make sure the subject isn't too long - taking into account special characters. if (Util::strlen($form_subject) > 100) { $form_subject = Util::substr($form_subject, 0, 100); } if (isset($_REQUEST['poll'])) { $context['poll']['question'] = isset($_REQUEST['question']) ? Util::htmlspecialchars(trim($_REQUEST['question'])) : ''; $context['choices'] = array(); $choice_id = 0; $_POST['options'] = empty($_POST['options']) ? array() : htmlspecialchars__recursive($_POST['options']); foreach ($_POST['options'] as $option) { if (trim($option) == '') { continue; } $context['choices'][] = array('id' => $choice_id++, 'number' => $choice_id, 'label' => $option, 'is_last' => false); } // One empty option for those with js disabled...I know are few... :P $context['choices'][] = array('id' => $choice_id++, 'number' => $choice_id, 'label' => '', 'is_last' => false); if (count($context['choices']) < 2) { $context['choices'][] = array('id' => $choice_id++, 'number' => $choice_id, 'label' => '', 'is_last' => false); } $context['last_choice_id'] = $choice_id; $context['choices'][count($context['choices']) - 1]['is_last'] = true; } // Are you... a guest? if ($user_info['is_guest']) { $context['name'] = !isset($_REQUEST['guestname']) ? '' : Util::htmlspecialchars(trim($_REQUEST['guestname'])); $context['email'] = !isset($_REQUEST['email']) ? '' : Util::htmlspecialchars(trim($_REQUEST['email'])); $user_info['name'] = $context['name']; } // Only show the preview stuff if they hit Preview. if (($really_previewing === true || isset($_REQUEST['xml'])) && !isset($_REQUEST['save_draft'])) { // Set up the preview message and subject $context['preview_message'] = $form_message; preparsecode($form_message, true); // Do all bulletin board code thing on the message preparsecode($context['preview_message']); $context['preview_message'] = parse_bbc($context['preview_message'], isset($_REQUEST['ns']) ? 0 : 1); censorText($context['preview_message']); // Don't forget the subject $context['preview_subject'] = $form_subject; censorText($context['preview_subject']); // Any errors we should tell them about? if ($form_subject === '') { $post_errors->addError('no_subject'); $context['preview_subject'] = '<em>' . $txt['no_subject'] . '</em>'; } if ($context['preview_message'] === '') { $post_errors->addError('no_message'); } elseif (!empty($modSettings['max_messageLength']) && Util::strlen($form_message) > $modSettings['max_messageLength']) { $post_errors->addError(array('long_message', array($modSettings['max_messageLength']))); } // Protect any CDATA blocks. if (isset($_REQUEST['xml'])) { $context['preview_message'] = strtr($context['preview_message'], array(']]>' => ']]]]><![CDATA[>')); } } // Set up the checkboxes. $context['notify'] = !empty($_REQUEST['notify']); $context['use_smileys'] = !isset($_REQUEST['ns']); $context['icon'] = isset($_REQUEST['icon']) ? preg_replace('~[\\./\\\\*\':"<>]~', '', $_REQUEST['icon']) : 'xx'; // Set the destination action for submission. $context['destination'] = 'post2;start=' . $_REQUEST['start'] . (isset($_REQUEST['msg']) ? ';msg=' . $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id'] : '') . (isset($_REQUEST['poll']) ? ';poll' : ''); $context['submit_label'] = isset($_REQUEST['msg']) ? $txt['save'] : $txt['post']; // Previewing an edit? if (isset($_REQUEST['msg']) && !empty($topic)) { require_once SUBSDIR . '/Messages.subs.php'; // Get the existing message. $message = messageDetails((int) $_REQUEST['msg'], $topic); // The message they were trying to edit was most likely deleted. // @todo Change this error message? if ($message === false) { fatal_lang_error('no_board', false); } $errors = checkMessagePermissions($message['message']); if (!empty($errors)) { foreach ($errors as $error) { $post_errors->addError($error); } } prepareMessageContext($message); } elseif (isset($_REQUEST['last_msg'])) { list($form_subject, ) = getFormMsgSubject(false, $topic, $first_subject); } // No check is needed, since nothing is really posted. checkSubmitOnce('free'); } elseif (isset($_REQUEST['msg']) && !empty($topic)) { $_REQUEST['msg'] = (int) $_REQUEST['msg']; $message = getFormMsgSubject(true, $topic); if (!empty($message['errors'])) { foreach ($errors as $error) { $post_errors->addError($error); } } // Get the stuff ready for the form. $form_subject = $message['message']['subject']; $form_message = un_preparsecode($message['message']['body']); censorText($form_message); censorText($form_subject); // Check the boxes that should be checked. $context['use_smileys'] = !empty($message['message']['smileys_enabled']); $context['icon'] = $message['message']['icon']; // Set the destination. $context['destination'] = 'post2;start=' . $_REQUEST['start'] . ';msg=' . $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id'] . (isset($_REQUEST['poll']) ? ';poll' : ''); $context['submit_label'] = $txt['save']; } else { // By default.... $context['use_smileys'] = true; $context['icon'] = 'xx'; if ($user_info['is_guest']) { $context['name'] = isset($_SESSION['guest_name']) ? $_SESSION['guest_name'] : ''; $context['email'] = isset($_SESSION['guest_email']) ? $_SESSION['guest_email'] : ''; } $context['destination'] = 'post2;start=' . $_REQUEST['start'] . (isset($_REQUEST['poll']) ? ';poll' : ''); $context['submit_label'] = $txt['post']; list($form_subject, $form_message) = getFormMsgSubject(false, $topic, $first_subject); } // Check whether this is a really old post being bumped... if (!empty($topic) && !empty($modSettings['oldTopicDays']) && $lastPostTime + $modSettings['oldTopicDays'] * 86400 < time() && empty($sticky) && !isset($_REQUEST['subject'])) { $post_errors->addError(array('old_topic', array($modSettings['oldTopicDays'])), 0); } // Are we moving a discussion to its own topic? if (!empty($modSettings['enableFollowup']) && !empty($_REQUEST['followup'])) { $context['original_post'] = isset($_REQUEST['quote']) ? (int) $_REQUEST['quote'] : (int) $_REQUEST['followup']; $context['show_boards_dropdown'] = true; require_once SUBSDIR . '/Boards.subs.php'; $context += getBoardList(array('not_redirection' => true, 'allowed_to' => 'post_new')); $context['boards_current_disabled'] = false; if (!empty($board)) { foreach ($context['categories'] as $id => $values) { if (isset($values['boards'][$board])) { $context['categories'][$id]['boards'][$board]['selected'] = true; break; } } } } $context['attachments']['can']['post'] = !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1 && (allowedTo('post_attachment') || $modSettings['postmod_active'] && allowedTo('post_unapproved_attachments')); if ($context['attachments']['can']['post']) { // If there are attachments, calculate the total size and how many. $attachments = array(); $attachments['total_size'] = 0; $attachments['quantity'] = 0; // If this isn't a new post, check the current attachments. if (isset($_REQUEST['msg'])) { $attachments['quantity'] = count($context['attachments']['current']); foreach ($context['attachments']['current'] as $attachment) { $attachments['total_size'] += $attachment['size']; } } // A bit of house keeping first. if (!empty($_SESSION['temp_attachments']) && count($_SESSION['temp_attachments']) == 1) { unset($_SESSION['temp_attachments']); } if (!empty($_SESSION['temp_attachments'])) { // Is this a request to delete them? if (isset($_GET['delete_temp'])) { foreach ($_SESSION['temp_attachments'] as $attachID => $attachment) { if (strpos($attachID, 'post_tmp_' . $user_info['id']) !== false) { @unlink($attachment['tmp_name']); } } $attach_errors->addError('temp_attachments_gone'); $_SESSION['temp_attachments'] = array(); } elseif ($context['current_action'] != 'post2' || !empty($_POST['from_qr'])) { // Let's be nice and see if they belong here first. if (empty($_REQUEST['msg']) && empty($_SESSION['temp_attachments']['post']['msg']) && $_SESSION['temp_attachments']['post']['board'] == $board || !empty($_REQUEST['msg']) && $_SESSION['temp_attachments']['post']['msg'] == $_REQUEST['msg']) { // See if any files still exist before showing the warning message and the files attached. foreach ($_SESSION['temp_attachments'] as $attachID => $attachment) { if (strpos($attachID, 'post_tmp_' . $user_info['id']) === false) { continue; } if (file_exists($attachment['tmp_name'])) { $attach_errors->addError('temp_attachments_new'); $context['files_in_session_warning'] = $txt['attached_files_in_session']; unset($_SESSION['temp_attachments']['post']['files']); break; } } } else { // Since, they don't belong here. Let's inform the user that they exist.. if (!empty($topic)) { $delete_url = $scripturl . '?action=post' . (!empty($_REQUEST['msg']) ? ';msg=' . $_REQUEST['msg'] : '') . (!empty($_REQUEST['last_msg']) ? ';last_msg=' . $_REQUEST['last_msg'] : '') . ';topic=' . $topic . ';delete_temp'; } else { $delete_url = $scripturl . '?action=post;board=' . $board . ';delete_temp'; } // Compile a list of the files to show the user. $file_list = array(); foreach ($_SESSION['temp_attachments'] as $attachID => $attachment) { if (strpos($attachID, 'post_tmp_' . $user_info['id']) !== false) { $file_list[] = $attachment['name']; } } $_SESSION['temp_attachments']['post']['files'] = $file_list; $file_list = '<div class="attachments">' . implode('<br />', $file_list) . '</div>'; if (!empty($_SESSION['temp_attachments']['post']['msg'])) { // We have a message id, so we can link back to the old topic they were trying to edit.. $goback_link = '<a href="' . $scripturl . '?action=post' . (!empty($_SESSION['temp_attachments']['post']['msg']) ? ';msg=' . $_SESSION['temp_attachments']['post']['msg'] : '') . (!empty($_SESSION['temp_attachments']['post']['last_msg']) ? ';last_msg=' . $_SESSION['temp_attachments']['post']['last_msg'] : '') . ';topic=' . $_SESSION['temp_attachments']['post']['topic'] . ';additionalOptions">' . $txt['here'] . '</a>'; $attach_errors->addError(array('temp_attachments_found', array($delete_url, $goback_link, $file_list))); $context['ignore_temp_attachments'] = true; } else { $attach_errors->addError(array('temp_attachments_lost', array($delete_url, $file_list))); $context['ignore_temp_attachments'] = true; } } } foreach ($_SESSION['temp_attachments'] as $attachID => $attachment) { // Skipping over these if (isset($context['ignore_temp_attachments']) || isset($_SESSION['temp_attachments']['post']['files'])) { break; } // Initial errors (such as missing directory), we can recover if ($attachID != 'initial_error' && strpos($attachID, 'post_tmp_' . $user_info['id']) === false) { continue; } if ($attachID == 'initial_error') { if ($context['current_action'] != 'post2') { $txt['error_attach_initial_error'] = $txt['attach_no_upload'] . '<div class="attachmenterrors">' . (is_array($attachment) ? vsprintf($txt[$attachment[0]], $attachment[1]) : $txt[$attachment]) . '</div>'; $attach_errors->addError('attach_initial_error'); } unset($_SESSION['temp_attachments']); break; } // Show any errors which might have occurred. if (!empty($attachment['errors'])) { if ($context['current_action'] != 'post2') { $txt['error_attach_errors'] = empty($txt['error_attach_errors']) ? '<br />' : ''; $txt['error_attach_errors'] .= vsprintf($txt['attach_warning'], $attachment['name']) . '<div class="attachmenterrors">'; foreach ($attachment['errors'] as $error) { $txt['error_attach_errors'] .= (is_array($error) ? vsprintf($txt[$error[0]], $error[1]) : $txt[$error]) . '<br />'; } $txt['error_attach_errors'] .= '</div>'; $attach_errors->addError('attach_errors'); } // Take out the trash. unset($_SESSION['temp_attachments'][$attachID]); @unlink($attachment['tmp_name']); continue; } // More house keeping. if (!file_exists($attachment['tmp_name'])) { unset($_SESSION['temp_attachments'][$attachID]); continue; } $attachments['quantity']++; $attachments['total_size'] += $attachment['size']; if (!isset($context['files_in_session_warning'])) { $context['files_in_session_warning'] = $txt['attached_files_in_session']; } $context['attachments']['current'][] = array('name' => '<u>' . htmlspecialchars($attachment['name'], ENT_COMPAT, 'UTF-8') . '</u>', 'size' => $attachment['size'], 'id' => $attachID, 'unchecked' => false, 'approved' => 1); } } } // Do we need to show the visual verification image? $context['require_verification'] = !$user_info['is_mod'] && !$user_info['is_admin'] && !empty($modSettings['posts_require_captcha']) && ($user_info['posts'] < $modSettings['posts_require_captcha'] || $user_info['is_guest'] && $modSettings['posts_require_captcha'] == -1); if ($context['require_verification']) { require_once SUBSDIR . '/VerificationControls.class.php'; $verificationOptions = array('id' => 'post'); $context['require_verification'] = create_control_verification($verificationOptions); $context['visual_verification_id'] = $verificationOptions['id']; } // If they came from quick reply, and have to enter verification details, give them some notice. if (!empty($_REQUEST['from_qr']) && !empty($context['require_verification'])) { $post_errors->addError('need_qr_verification'); } // Any errors occurred? $context['post_error'] = array('errors' => $post_errors->prepareErrors(), 'type' => $post_errors->getErrorType() == 0 ? 'minor' : 'serious', 'title' => $post_errors->getErrorType() == 0 ? $txt['warning_while_submitting'] : $txt['error_while_submitting']); // If there are attachment errors. Let's show a list to the user. if ($attach_errors->hasErrors()) { loadTemplate('Errors'); $errors = $attach_errors->prepareErrors(); foreach ($errors as $key => $error) { $context['attachment_error_keys'][] = $key . '_error'; $context[$key . '_error'] = $error; } } // What are you doing? Posting a poll, modifying, previewing, new post, or reply... if (isset($_REQUEST['poll'])) { $context['page_title'] = $txt['new_poll']; } elseif ($context['make_event']) { $context['page_title'] = $context['event']['id'] == -1 ? $txt['calendar_post_event'] : $txt['calendar_edit']; } elseif (isset($_REQUEST['msg'])) { $context['page_title'] = $txt['modify_msg']; } elseif (isset($_REQUEST['subject'], $context['preview_subject'])) { $context['page_title'] = $txt['post_reply']; } elseif (empty($topic)) { $context['page_title'] = $txt['start_new_topic']; } else { $context['page_title'] = $txt['post_reply']; } // Update the topic summary, needed to show new posts in a preview if (!empty($topic) && !empty($modSettings['topicSummaryPosts'])) { $only_approved = $modSettings['postmod_active'] && !allowedTo('approve_posts'); if (isset($_REQUEST['xml'])) { $limit = empty($context['new_replies']) ? 0 : (int) $context['new_replies']; } else { $limit = $modSettings['topicSummaryPosts']; } $before = isset($_REQUEST['msg']) ? array('before' => (int) $_REQUEST['msg']) : array(); $counter = 0; $context['previous_posts'] = empty($limit) ? array() : selectMessages($topic, 0, $limit, $before, $only_approved); foreach ($context['previous_posts'] as &$post) { $post['is_new'] = !empty($context['new_replies']); $post['counter'] = $counter++; $post['is_ignored'] = !empty($modSettings['enable_buddylist']) && in_array($post['id_poster'], $user_info['ignoreusers']); if (!empty($context['new_replies'])) { $context['new_replies']--; } } } // Just ajax previewing then lets stop now if (isset($_REQUEST['xml'])) { obExit(); } // Build the link tree. if (empty($topic)) { $context['linktree'][] = array('name' => '<em>' . $txt['start_new_topic'] . '</em>'); } else { $context['linktree'][] = array('url' => $scripturl . '?topic=' . $topic . '.' . $_REQUEST['start'], 'name' => $form_subject, 'extra_before' => '<span><strong class="nav">' . $context['page_title'] . ' ( </strong></span>', 'extra_after' => '<span><strong class="nav"> )</strong></span>'); } $context['subject'] = addcslashes($form_subject, '"'); $context['message'] = str_replace(array('"', '<', '>', ' '), array('"', '<', '>', ' '), $form_message); // Are post drafts enabled? $context['drafts_save'] = !empty($modSettings['drafts_enabled']) && !empty($modSettings['drafts_post_enabled']) && allowedTo('post_draft'); $context['drafts_autosave'] = !empty($context['drafts_save']) && !empty($modSettings['drafts_autosave_enabled']) && allowedTo('post_autosave_draft'); if (!empty($modSettings['mentions_enabled'])) { $context['mentions_enabled'] = true; loadCSSFile('jquery.atwho.css'); addInlineJavascript(' $(document).ready(function () { for (var i = 0, count = all_elk_mentions.length; i < count; i++) all_elk_mentions[i].oMention = new elk_mentions(all_elk_mentions[i].oOptions); });'); } // Build a list of drafts that they can load into the editor if (!empty($context['drafts_save'])) { $this->_prepareDraftsContext($user_info['id'], $topic); if (!empty($context['drafts'])) { $template_layers->add('load_drafts', 100); } } // Needed for the editor and message icons. require_once SUBSDIR . '/Editor.subs.php'; // Now create the editor. $editorOptions = array('id' => 'message', 'value' => $context['message'], 'labels' => array('post_button' => $context['submit_label']), 'height' => '275px', 'width' => '100%', 'preview_type' => 2); create_control_richedit($editorOptions); $context['attached'] = ''; $context['make_poll'] = isset($_REQUEST['poll']); if ($context['make_poll']) { loadTemplate('Poll'); $template_layers->add('poll_edit'); } // Message icons - customized or not, retrieve them... $context['icons'] = getMessageIcons($board); $context['icon_url'] = ''; if (!empty($context['icons'])) { $context['icons'][count($context['icons']) - 1]['is_last'] = true; $context['icons'][0]['selected'] = true; // $context['icon'] is set when editing a message if (!isset($context['icon'])) { $context['icon'] = $context['icons'][0]['value']; } $found = false; foreach ($context['icons'] as $icon) { if ($icon['value'] === $context['icon']) { $found = true; $context['icon_url'] = $icon['url']; break; } } // Failsafe if (!$found) { $context['icon'] = $context['icons'][0]['value']; $context['icon_url'] = $context['icons'][0]['url']; } } // Are we starting a poll? if set the poll icon as selected if its available if (isset($_REQUEST['poll'])) { for ($i = 0, $n = count($context['icons']); $i < $n; $i++) { if ($context['icons'][$i]['value'] == 'poll') { $context['icons'][$i]['selected'] = true; $context['icon'] = 'poll'; $context['icon_url'] = $context['icons'][$i]['url']; break; } } } // If the user can post attachments prepare the warning labels. if ($context['attachments']['can']['post']) { // If they've unchecked an attachment, they may still want to attach that many more files, but don't allow more than num_allowed_attachments. $context['attachments']['num_allowed'] = empty($modSettings['attachmentNumPerPostLimit']) ? 50 : min($modSettings['attachmentNumPerPostLimit'] - count($context['attachments']['current']), $modSettings['attachmentNumPerPostLimit']); $context['attachments']['can']['post_unapproved'] = allowedTo('post_attachment'); $context['attachments']['restrictions'] = array(); if (!empty($modSettings['attachmentCheckExtensions'])) { $context['attachments']['allowed_extensions'] = strtr(strtolower($modSettings['attachmentExtensions']), array(',' => ', ')); } else { $context['attachments']['allowed_extensions'] = ''; } $context['attachments']['templates'] = array('add_new' => 'template_add_new_attachments', 'existing' => 'template_show_existing_attachments'); $attachmentRestrictionTypes = array('attachmentNumPerPostLimit', 'attachmentPostLimit', 'attachmentSizeLimit'); foreach ($attachmentRestrictionTypes as $type) { if (!empty($modSettings[$type])) { $context['attachments']['restrictions'][] = sprintf($txt['attach_restrict_' . $type], comma_format($modSettings[$type], 0)); // Show some numbers. If they exist. if ($type == 'attachmentNumPerPostLimit' && $attachments['quantity'] > 0) { $context['attachments']['restrictions'][] = sprintf($txt['attach_remaining'], $modSettings['attachmentNumPerPostLimit'] - $attachments['quantity']); } elseif ($type == 'attachmentPostLimit' && $attachments['total_size'] > 0) { $context['attachments']['restrictions'][] = sprintf($txt['attach_available'], comma_format(round(max($modSettings['attachmentPostLimit'] - $attachments['total_size'] / 1028, 0)), 0)); } } } // Load up the drag and drop attachment magic addInlineJavascript(' var dropAttach = dragDropAttachment.prototype.init({ board: ' . $board . ', allowedExtensions: ' . JavaScriptEscape($context['attachments']['allowed_extensions']) . ', totalSizeAllowed: ' . JavaScriptEscape(empty($modSettings['attachmentPostLimit']) ? '' : $modSettings['attachmentPostLimit']) . ', individualSizeAllowed: ' . JavaScriptEscape(empty($modSettings['attachmentSizeLimit']) ? '' : $modSettings['attachmentSizeLimit']) . ', numOfAttachmentAllowed: ' . $context['attachments']['num_allowed'] . ', totalAttachSizeUploaded: ' . (isset($context['attachments']['total_size']) && !empty($context['attachments']['total_size']) ? $context['attachments']['total_size'] : 0) . ', numAttachUploaded: ' . (isset($context['attachments']['quantity']) && !empty($context['attachments']['quantity']) ? $context['attachments']['quantity'] : 0) . ', oTxt: ({ allowedExtensions : ' . JavaScriptEscape(sprintf($txt['cant_upload_type'], $context['attachments']['allowed_extensions'])) . ', totalSizeAllowed : ' . JavaScriptEscape($txt['attach_max_total_file_size']) . ', individualSizeAllowed : ' . JavaScriptEscape(sprintf($txt['file_too_big'], comma_format($modSettings['attachmentSizeLimit'], 0))) . ', numOfAttachmentAllowed : ' . JavaScriptEscape(sprintf($txt['attachments_limit_per_post'], $modSettings['attachmentNumPerPostLimit'])) . ', postUploadError : ' . JavaScriptEscape($txt['post_upload_error']) . ', }), });', true); } $context['back_to_topic'] = isset($_REQUEST['goback']) || isset($_REQUEST['msg']) && !isset($_REQUEST['subject']); $context['show_additional_options'] = !empty($_POST['additional_options']) || isset($_SESSION['temp_attachments']['post']) || isset($_GET['additionalOptions']); $context['is_new_topic'] = empty($topic); $context['is_new_post'] = !isset($_REQUEST['msg']); $context['is_first_post'] = $context['is_new_topic'] || isset($_REQUEST['msg']) && $_REQUEST['msg'] == $id_first_msg; $context['current_action'] = 'post'; // Register this form in the session variables. checkSubmitOnce('register'); // Finally, load the template. if (!isset($_REQUEST['xml'])) { loadTemplate('Post'); $context['sub_template'] = 'post_page'; } }
/** * Editing a membergroup. * * What it does: * - Screen to edit a specific membergroup. * - Called by ?action=admin;area=membergroups;sa=edit;group=x. * - It requires the manage_membergroups permission. * - Also handles the delete button of the edit form. * - Redirects to ?action=admin;area=membergroups. * * @uses the edit_group sub template of ManageMembergroups. */ public function action_edit() { global $context, $txt, $modSettings; $current_group_id = isset($_REQUEST['group']) ? (int) $_REQUEST['group'] : 0; if (!empty($modSettings['deny_boards_access'])) { loadLanguage('ManagePermissions'); } require_once SUBSDIR . '/Membergroups.subs.php'; // Make sure this group is editable. if (!empty($current_group_id)) { $current_group = membergroupById($current_group_id); } // Now, do we have a valid id? if (!allowedTo('admin_forum') && !empty($current_group_id) && $current_group['group_type'] == 1) { fatal_lang_error('membergroup_does_not_exist', false); } // The delete this membergroup button was pressed. if (isset($_POST['delete'])) { checkSession(); validateToken('admin-mmg'); if (empty($current_group_id)) { fatal_lang_error('membergroup_does_not_exist', false); } // Let's delete the group deleteMembergroups($current_group['id_group']); redirectexit('action=admin;area=membergroups;'); } elseif (isset($_POST['save'])) { // Validate the session. checkSession(); validateToken('admin-mmg'); if (empty($current_group_id)) { fatal_lang_error('membergroup_does_not_exist', false); } require_once SUBSDIR . '/DataValidator.class.php'; $validator = new Data_Validator(); // Cleanup the inputs! :D $validator->sanitation_rules(array('max_messages' => 'intval', 'min_posts' => 'intval|abs', 'group_type' => 'intval', 'group_desc' => 'trim|Util::htmlspecialchars', 'group_name' => 'trim|Util::htmlspecialchars', 'group_hidden' => 'intval', 'group_inherit' => 'intval', 'icon_count' => 'intval', 'icon_image' => 'trim|Util::htmlspecialchars', 'online_color' => 'trim|valid_color')); $validator->input_processing(array('boardaccess' => 'array')); $validator->validation_rules(array('boardaccess' => 'contains[allow,ignore,deny]')); $validator->validate($_POST); // Can they really inherit from this group? if ($validator->group_inherit != -2 && !allowedTo('admin_forum')) { $inherit_type = membergroupById($validator->group_inherit); } $min_posts = $validator->group_type == -1 && $validator->min_posts >= 0 && $current_group['id_group'] > 3 ? $validator->min_posts : ($current_group['id_group'] == 4 ? 0 : -1); $group_inherit = $current_group['id_group'] > 1 && $current_group['id_group'] != 3 && (empty($inherit_type['group_type']) || $inherit_type['group_type'] != 1) ? $validator->group_inherit : -2; //@todo Don't set online_color for the Moderators group? // Do the update of the membergroup settings. $properties = array('max_messages' => $validator->max_messages, 'min_posts' => $min_posts, 'group_type' => $validator->group_type < 0 || $validator->group_type > 3 || $validator->group_type == 1 && !allowedTo('admin_forum') ? 0 : $validator->group_type, 'hidden' => !$validator->group_hidden || $min_posts != -1 || $current_group['id_group'] == 3 ? 0 : $validator->group_hidden, 'id_parent' => $group_inherit, 'current_group' => $current_group['id_group'], 'group_name' => $validator->group_name, 'online_color' => $validator->online_color, 'icons' => $validator->icon_count <= 0 ? '' : min($validator->icon_count, 10) . '#' . $validator->icon_image, 'description' => $current_group['id_group'] == 1 || $validator->group_type != -1 ? $validator->group_desc : ''); updateMembergroupProperties($properties); call_integration_hook('integrate_save_membergroup', array($current_group['id_group'])); // Time to update the boards this membergroup has access to. if ($current_group['id_group'] == 2 || $current_group['id_group'] > 3) { $changed_boards = array(); $changed_boards['allow'] = array(); $changed_boards['deny'] = array(); $changed_boards['ignore'] = array(); if ($validator->boardaccess) { foreach ($validator->boardaccess as $group_id => $action) { $changed_boards[$action][] = (int) $group_id; } } foreach (array('allow', 'deny') as $board_action) { // Find all board this group is in, but shouldn't be in. detachGroupFromBoards($current_group['id_group'], $changed_boards, $board_action); // Add the membergroup to all boards that hadn't been set yet. if (!empty($changed_boards[$board_action])) { assignGroupToBoards($current_group['id_group'], $changed_boards, $board_action); } } } // Remove everyone from this group! if ($min_posts != -1) { detachDeletedGroupFromMembers($current_group['id_group']); } elseif ($current_group['id_group'] != 3) { // Making it a hidden group? If so remove everyone with it as primary group (Actually, just make them additional). if ($validator->group_hidden == 2) { setGroupToHidden($current_group['id_group']); } // Either way, let's check our "show group membership" setting is correct. validateShowGroupMembership(); } // Do we need to set inherited permissions? if ($group_inherit != -2 && $group_inherit != $_POST['old_inherit']) { require_once SUBSDIR . '/Permission.subs.php'; updateChildPermissions($group_inherit); } // Finally, moderators! $moderator_string = isset($_POST['group_moderators']) ? trim($_POST['group_moderators']) : ''; detachGroupModerators($current_group['id_group']); if ((!empty($moderator_string) || !empty($_POST['moderator_list'])) && $min_posts == -1 && $current_group['id_group'] != 3) { // Get all the usernames from the string if (!empty($moderator_string)) { $moderator_string = strtr(preg_replace('~&#(\\d{4,5}|[2-9]\\d{2,4}|1[2-9]\\d);~', '&#$1;', htmlspecialchars($moderator_string, ENT_QUOTES, 'UTF-8')), array('"' => '"')); preg_match_all('~"([^"]+)"~', $moderator_string, $matches); $moderators = array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $moderator_string))); for ($k = 0, $n = count($moderators); $k < $n; $k++) { $moderators[$k] = trim($moderators[$k]); if (strlen($moderators[$k]) == 0) { unset($moderators[$k]); } } // Find all the id_member's for the member_name's in the list. if (!empty($moderators)) { $group_moderators = getIDMemberFromGroupModerators($moderators); } } else { $moderators = array(); foreach ($_POST['moderator_list'] as $moderator) { $moderators[] = (int) $moderator; } $group_moderators = array(); if (!empty($moderators)) { require_once SUBSDIR . '/Members.subs.php'; $members = getBasicMemberData($moderators); foreach ($members as $member) { $group_moderators[] = $member['id_member']; } } } // Found some? if (!empty($group_moderators)) { assignGroupModerators($current_group['id_group'], $group_moderators); } } // There might have been some post group changes. updateStats('postgroups'); // We've definitely changed some group stuff. updateSettings(array('settings_updated' => time())); // Log the edit. logAction('edited_group', array('group' => $validator->group_name), 'admin'); redirectexit('action=admin;area=membergroups'); } // Fetch the current group information. $row = membergroupById($current_group['id_group'], true); if (empty($row) || !allowedTo('admin_forum') && $row['group_type'] == 1) { fatal_lang_error('membergroup_does_not_exist', false); } $row['icons'] = explode('#', $row['icons']); $context['group'] = array('id' => $row['id_group'], 'name' => $row['group_name'], 'description' => htmlspecialchars($row['description'], ENT_COMPAT, 'UTF-8'), 'editable_name' => $row['group_name'], 'color' => $row['online_color'], 'min_posts' => $row['min_posts'], 'max_messages' => $row['max_messages'], 'icon_count' => (int) $row['icons'][0], 'icon_image' => isset($row['icons'][1]) ? $row['icons'][1] : '', 'is_post_group' => $row['min_posts'] != -1, 'type' => $row['min_posts'] != -1 ? 0 : $row['group_type'], 'hidden' => $row['min_posts'] == -1 ? $row['hidden'] : 0, 'inherited_from' => $row['id_parent'], 'allow_post_group' => $row['id_group'] == 2 || $row['id_group'] > 4, 'allow_delete' => $row['id_group'] == 2 || $row['id_group'] > 4, 'allow_protected' => allowedTo('admin_forum')); // Get any moderators for this group $context['group']['moderators'] = getGroupModerators($row['id_group']); $context['group']['moderator_list'] = empty($context['group']['moderators']) ? '' : '"' . implode('", "', $context['group']['moderators']) . '"'; if (!empty($context['group']['moderators'])) { list($context['group']['last_moderator_id']) = array_slice(array_keys($context['group']['moderators']), -1); } // Get a list of boards this membergroup is allowed to see. $context['boards'] = array(); if ($row['id_group'] == 2 || $row['id_group'] > 3) { require_once SUBSDIR . '/Boards.subs.php'; $context += getBoardList(array('override_permissions' => true, 'access' => $row['id_group'], 'not_redirection' => true)); // Include a list of boards per category for easy toggling. foreach ($context['categories'] as $category) { $context['categories'][$category['id']]['child_ids'] = array_keys($category['boards']); } } // Finally, get all the groups this could be inherited off. $context['inheritable_groups'] = getInheritableGroups($row['id_group']); call_integration_hook('integrate_view_membergroup'); $context['sub_template'] = 'edit_group'; $context['page_title'] = $txt['membergroups_edit_group']; // Use the autosuggest script when needed if ($context['group']['id'] != 3 && $context['group']['id'] != 4) { loadJavascriptFile('suggest.js', array('defer' => true)); } createToken('admin-mmg'); }
/** * Retrieve and return all admin settings for boards management. */ private function _settings() { global $txt; // We need to borrow a string from here loadLanguage('ManagePermissions'); // Load the boards list - for the recycle bin! require_once SUBSDIR . '/Boards.subs.php'; $boards = getBoardList(array('override_permissions' => true, 'not_redirection' => true), true); $recycle_boards = array(''); foreach ($boards as $board) { $recycle_boards[$board['id_board']] = $board['cat_name'] . ' - ' . $board['board_name']; } // Here and the board settings... $config_vars = array(array('title', 'settings'), array('permissions', 'manage_boards', 'helptext' => $txt['permissionhelp_manage_boards']), '', array('check', 'countChildPosts'), array('check', 'recycle_enable', 'onclick' => 'document.getElementById(\'recycle_board\').disabled = !this.checked;'), array('select', 'recycle_board', $recycle_boards), array('check', 'allow_ignore_boards'), array('check', 'deny_boards_access')); // Add new settings with a nice hook, makes them available for admin settings search as well call_integration_hook('integrate_modify_board_settings', array(&$config_vars)); return $config_vars; }
/** * Supporting function for the topics maintenance area. */ public function action_topics() { global $context, $txt; require_once SUBSDIR . '/Boards.subs.php'; // Let's load up the boards in case they are useful. $context += getBoardList(array('not_redirection' => true)); if (isset($_GET['done']) && $_GET['done'] == 'purgeold') { $context['maintenance_finished'] = array('errors' => array(sprintf($txt['maintain_done'], $txt['maintain_old']))); } elseif (isset($_GET['done']) && $_GET['done'] == 'massmove') { $context['maintenance_finished'] = array('errors' => array(sprintf($txt['maintain_done'], $txt['move_topics_maintenance']))); } // Set up the sub-template $context['sub_template'] = 'maintain_topics'; }
/** * Allows the user to see the list of their ignored boards. * (and un-ignore them) * */ public function action_ignoreboards() { global $context, $modSettings, $cur_profile; $memID = currentMemberID(); // Have the admins enabled this option? if (empty($modSettings['allow_ignore_boards'])) { fatal_lang_error('ignoreboards_disallowed', 'user'); } loadTemplate('ProfileOptions'); $context['sub_template'] = 'ignoreboards'; require_once SUBSDIR . '/Boards.subs.php'; $context += getBoardList(array('not_redirection' => true, 'ignore' => !empty($cur_profile['ignore_boards']) ? explode(',', $cur_profile['ignore_boards']) : array())); // Include a list of boards per category for easy toggling. foreach ($context['categories'] as $cat => &$category) { $context['boards_in_category'][$cat] = count($category['boards']); $category['child_ids'] = array_keys($category['boards']); } loadThemeOptions($memID); }
/** * Allows to pick a topic to merge the current topic with. * is accessed with ?action=mergetopics;sa=index * default sub action for ?action=mergetopics. * uses 'merge' sub template of the MergeTopics template. * allows to set a different target board. */ public function action_mergeIndex() { global $txt, $board, $context, $scripturl, $user_info, $modSettings; if (!isset($_GET['from'])) { fatal_lang_error('no_access', false); } $_GET['from'] = (int) $_GET['from']; $_REQUEST['targetboard'] = isset($_REQUEST['targetboard']) ? (int) $_REQUEST['targetboard'] : $board; $context['target_board'] = $_REQUEST['targetboard']; // Prepare a handy query bit for approval... if ($modSettings['postmod_active']) { $can_approve_boards = !empty($user_info['mod_cache']['ap']) ? $user_info['mod_cache']['ap'] : boardsAllowedTo('approve_posts'); $onlyApproved = $can_approve_boards !== array(0) && !in_array($_REQUEST['targetboard'], $can_approve_boards); } else { $onlyApproved = false; } // How many topics are on this board? (used for paging.) require_once SUBSDIR . '/Topic.subs.php'; $topiccount = countTopicsByBoard($_REQUEST['targetboard'], $onlyApproved); // Make the page list. $context['page_index'] = constructPageIndex($scripturl . '?action=mergetopics;from=' . $_GET['from'] . ';targetboard=' . $_REQUEST['targetboard'] . ';board=' . $board . '.%1$d', $_REQUEST['start'], $topiccount, $modSettings['defaultMaxTopics'], true); // Get the topic's subject. $topic_info = getTopicInfo($_GET['from'], 'message'); // @todo review: double check the logic if (empty($topic_info) || $topic_info['id_board'] != $board || $onlyApproved && empty($topic_info['approved'])) { fatal_lang_error('no_board'); } // Tell the template a few things.. $context['origin_topic'] = $_GET['from']; $context['origin_subject'] = $topic_info['subject']; $context['origin_js_subject'] = addcslashes(addslashes($topic_info['subject']), '/'); $context['page_title'] = $txt['merge']; // Check which boards you have merge permissions on. $merge_boards = boardsAllowedTo('merge_any'); if (empty($merge_boards)) { fatal_lang_error('cannot_merge_any', 'user'); } // Get a list of boards they can navigate to to merge. require_once SUBSDIR . '/Boards.subs.php'; $boardListOptions = array('not_redirection' => true); if (!in_array(0, $merge_boards)) { $boardListOptions['included_boards'] = $merge_boards; } $boards_list = getBoardList($boardListOptions, true); $context['boards'] = array(); foreach ($boards_list as $board) { $context['boards'][] = array('id' => $board['id_board'], 'name' => $board['board_name'], 'category' => $board['cat_name']); } // Get some topics to merge it with. $context['topics'] = mergeableTopics($_REQUEST['targetboard'], $_GET['from'], $onlyApproved, $_REQUEST['start']); if (empty($context['topics']) && count($context['boards']) <= 1) { fatal_lang_error('merge_need_more_topics'); } $context['sub_template'] = 'merge'; }
/** * Retrieve and return all admin settings for the calendar. */ private function _settings() { global $txt; // Load the boards list. require_once SUBSDIR . '/Boards.subs.php'; $boards_list = getBoardList(array('override_permissions' => true, 'not_redirection' => true), true); $boards = array(''); foreach ($boards_list as $board) { $boards[$board['id_board']] = $board['cat_name'] . ' - ' . $board['board_name']; } // Look, all the calendar settings - of which there are many! $config_vars = array(array('title', 'calendar_settings'), array('permissions', 'calendar_view'), array('permissions', 'calendar_post'), array('permissions', 'calendar_edit_own'), array('permissions', 'calendar_edit_any'), '', array('int', 'cal_days_for_index', 6, 'postinput' => $txt['days_word']), array('select', 'cal_showholidays', array(0 => $txt['setting_cal_show_never'], 1 => $txt['setting_cal_show_cal'], 3 => $txt['setting_cal_show_index'], 2 => $txt['setting_cal_show_all'])), array('select', 'cal_showbdays', array(0 => $txt['setting_cal_show_never'], 1 => $txt['setting_cal_show_cal'], 3 => $txt['setting_cal_show_index'], 2 => $txt['setting_cal_show_all'])), array('select', 'cal_showevents', array(0 => $txt['setting_cal_show_never'], 1 => $txt['setting_cal_show_cal'], 3 => $txt['setting_cal_show_index'], 2 => $txt['setting_cal_show_all'])), array('check', 'cal_export'), '', array('select', 'cal_defaultboard', $boards), array('check', 'cal_daysaslink'), array('check', 'cal_allow_unlinked'), array('check', 'cal_showInTopic'), '', array('int', 'cal_minyear'), array('int', 'cal_maxyear'), '', array('check', 'cal_allowspan'), array('int', 'cal_maxspan', 6, 'postinput' => $txt['days_word'])); // Add new settings with a nice hook, makes them available for admin settings search as well call_integration_hook('integrate_modify_calendar_settings', array(&$config_vars)); return $config_vars; }
/** * Allows to edit the message icons. */ public function action_editicon() { global $context, $settings, $txt, $scripturl; require_once SUBSDIR . '/MessageIcons.subs.php'; // Get a list of icons. $context['icons'] = fetchMessageIconsDetails(); // Submitting a form? if (isset($_POST['icons_save'])) { checkSession(); // Deleting icons? if (isset($_POST['delete']) && !empty($_POST['checked_icons'])) { $deleteIcons = array(); foreach ($_POST['checked_icons'] as $icon) { $deleteIcons[] = (int) $icon; } // Do the actual delete! deleteMessageIcons($deleteIcons); } elseif ($context['sub_action'] == 'editicon' && isset($_GET['icon'])) { $_GET['icon'] = (int) $_GET['icon']; // Do some preperation with the data... like check the icon exists *somewhere* if (strpos($_POST['icon_filename'], '.png') !== false) { $_POST['icon_filename'] = substr($_POST['icon_filename'], 0, -4); } if (!file_exists($settings['default_theme_dir'] . '/images/post/' . $_POST['icon_filename'] . '.png')) { fatal_lang_error('icon_not_found'); } elseif (strlen($_POST['icon_filename']) > 16) { fatal_lang_error('icon_name_too_long'); } elseif ($_POST['icon_location'] == $_GET['icon'] && !empty($_GET['icon'])) { fatal_lang_error('icon_after_itself'); } // First do the sorting... if this is an edit reduce the order of everything after it by one ;) if ($_GET['icon'] != 0) { $oldOrder = $context['icons'][$_GET['icon']]['true_order']; foreach ($context['icons'] as $id => $data) { if ($data['true_order'] > $oldOrder) { $context['icons'][$id]['true_order']--; } } } // If there are no existing icons and this is a new one, set the id to 1 (mainly for non-mysql) if (empty($_GET['icon']) && empty($context['icons'])) { $_GET['icon'] = 1; } // Get the new order. $newOrder = $_POST['icon_location'] == 0 ? 0 : $context['icons'][$_POST['icon_location']]['true_order'] + 1; // Do the same, but with the one that used to be after this icon, done to avoid conflict. foreach ($context['icons'] as $id => $data) { if ($data['true_order'] >= $newOrder) { $context['icons'][$id]['true_order']++; } } // Finally set the current icon's position! $context['icons'][$_GET['icon']]['true_order'] = $newOrder; // Simply replace the existing data for the other bits. $context['icons'][$_GET['icon']]['title'] = $_POST['icon_description']; $context['icons'][$_GET['icon']]['filename'] = $_POST['icon_filename']; $context['icons'][$_GET['icon']]['board_id'] = (int) $_POST['icon_board']; // Do a huge replace ;) $iconInsert = array(); $iconInsert_new = array(); foreach ($context['icons'] as $id => $icon) { if ($id != 0) { $iconInsert[] = array($id, $icon['board_id'], $icon['title'], $icon['filename'], $icon['true_order']); } else { $iconInsert_new[] = array($icon['board_id'], $icon['title'], $icon['filename'], $icon['true_order']); } } updateMessageIcon($iconInsert); if (!empty($iconInsert_new)) { addMessageIcon($iconInsert_new); } } // Sort by order, so it is quicker :) sortMessageIconTable(); // Unless we're adding a new thing, we'll escape if (!isset($_POST['add'])) { redirectexit('action=admin;area=smileys;sa=editicons'); } } $context[$context['admin_menu_name']]['current_subsection'] = 'editicons'; $token = createToken('admin-sort'); $listOptions = array('id' => 'message_icon_list', 'title' => $txt['icons_edit_message_icons'], 'sortable' => true, 'base_href' => $scripturl . '?action=admin;area=smileys;sa=editicons', 'get_items' => array('function' => array($this, 'list_fetchMessageIconsDetails')), 'no_items_label' => $txt['icons_no_entries'], 'columns' => array('icon' => array('data' => array('sprintf' => array('format' => '<img src="%1$s" alt="%2$s" />', 'params' => array('image_url' => false, 'filename' => true)), 'class' => 'centertext')), 'filename' => array('header' => array('value' => $txt['smileys_filename']), 'data' => array('sprintf' => array('format' => '%1$s.png', 'params' => array('filename' => true)))), 'tooltip' => array('header' => array('value' => $txt['smileys_description']), 'data' => array('db_htmlsafe' => 'title')), 'board' => array('header' => array('value' => $txt['icons_board']), 'data' => array('db' => 'board')), 'modify' => array('header' => array('value' => $txt['smileys_modify']), 'data' => array('sprintf' => array('format' => '<a href="' . $scripturl . '?action=admin;area=smileys;sa=editicon;icon=%1$s">' . $txt['smileys_modify'] . '</a>', 'params' => array('id' => false)))), 'check' => array('header' => array('value' => '<input type="checkbox" onclick="invertAll(this, this.form);" class="input_check" />', 'class' => 'centertext'), 'data' => array('sprintf' => array('format' => '<input type="checkbox" name="checked_icons[]" value="%1$d" class="input_check" />', 'params' => array('id' => false)), 'class' => 'centertext'))), 'form' => array('href' => $scripturl . '?action=admin;area=smileys;sa=editicons', 'hidden_fields' => array('icons_save' => 1)), 'additional_rows' => array(array('position' => 'below_table_data', 'class' => 'submitbutton', 'value' => ' <input type="submit" name="delete" value="' . $txt['quickmod_delete_selected'] . '" onclick="return confirm(\'' . $txt['icons_confirm'] . '\');" class="right_submit" /> <a class="linkbutton" href="' . $scripturl . '?action=admin;area=smileys;sa=editicon">' . $txt['icons_add_new'] . '</a>'), array('position' => 'after_title', 'value' => $txt['icons_reorder_note'])), 'javascript' => ' $().elkSortable({ sa: "messageiconorder", error: "' . $txt['admin_order_error'] . '", title: "' . $txt['admin_order_title'] . '", placeholder: "ui-state-highlight", href: "?action=admin;area=smileys;sa=editicons", token: {token_var: "' . $token['admin-sort_token_var'] . '", token_id: "' . $token['admin-sort_token'] . '"} }); '); require_once SUBSDIR . '/GenericList.class.php'; createList($listOptions); // If we're adding/editing an icon we'll need a list of boards if ($context['sub_action'] == 'editicon' || isset($_POST['add'])) { // Force the sub_template just in case. $context['sub_template'] = 'editicon'; $context['new_icon'] = !isset($_GET['icon']); // Get the properties of the current icon from the icon list. if (!$context['new_icon']) { $context['icon'] = $context['icons'][$_GET['icon']]; } // Get a list of boards needed for assigning this icon to a specific board. $boardListOptions = array('selected_board' => isset($context['icon']['board_id']) ? $context['icon']['board_id'] : 0); require_once SUBSDIR . '/Boards.subs.php'; $context += getBoardList($boardListOptions); } }
/** * Screen shown before the actual split. * is accessed with ?action=splittopics;sa=index. * default sub action for ?action=splittopics. * uses 'ask' sub template of the SplitTopics template. * redirects to action_splitSelectTopics if the message given turns out to be * the first message of a topic. * shows the user three ways to split the current topic. */ public function action_splitIndex() { global $txt, $context, $modSettings; // Validate "at". if (empty($_GET['at'])) { fatal_lang_error('numbers_one_to_nine', false); } // Split at a specific topic $splitAt = (int) $_GET['at']; // We deal with topics here. require_once SUBSDIR . '/Boards.subs.php'; require_once SUBSDIR . '/Messages.subs.php'; // Let's load up the boards in case they are useful. $context += getBoardList(array('not_redirection' => true)); // Retrieve message info for the message at the split point. $messageInfo = basicMessageInfo($splitAt, false, true); if ($messageInfo === false) { fatal_lang_error('cant_find_messages'); } // If not approved validate they can approve it. if ($modSettings['postmod_active'] && !$messageInfo['topic_approved']) { isAllowedTo('approve_posts'); } // If this topic has unapproved posts, we need to count them too... if ($modSettings['postmod_active'] && allowedTo('approve_posts')) { $messageInfo['num_replies'] += $messageInfo['unapproved_posts'] - ($messageInfo['topic_approved'] ? 0 : 1); } $context['can_move'] = allowedTo('move_any') || allowedTo('move_own'); // Check if there is more than one message in the topic. (there should be.) if ($messageInfo['num_replies'] < 1) { fatal_lang_error('topic_one_post', false); } // Check if this is the first message in the topic (if so, the first and second option won't be available) if ($messageInfo['id_first_msg'] == $splitAt) { $this->_new_topic_subject = $messageInfo['subject']; $this->_set_session_values(); return $this->action_splitSelectTopics(); } // Basic template information.... $context['message'] = array('id' => $splitAt, 'subject' => $messageInfo['subject']); $context['sub_template'] = 'ask'; $context['page_title'] = $txt['split_topic']; }
/** * Show permissions for a user. */ public function action_showPermissions() { global $txt, $board, $user_profile, $context, $scripturl; // Verify if the user has sufficient permissions. isAllowedTo('manage_permissions'); loadLanguage('ManagePermissions'); loadLanguage('Admin'); loadTemplate('ManageMembers'); loadTemplate('ProfileInfo'); // Load all the permission profiles. require_once SUBSDIR . '/ManagePermissions.subs.php'; loadPermissionProfiles(); $memID = currentMemberID(); $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. require_once SUBSDIR . '/Boards.subs.php'; $board_list = getBoardList(array('moderator' => $memID), true); $context['boards'] = array(); $context['no_access_boards'] = array(); foreach ($board_list as $row) { if (count(array_intersect($curGroups, explode(',', $row['member_groups']))) === 0 && !$row['is_mod']) { $context['no_access_boards'][] = array('id' => $row['id_board'], 'name' => $row['board_name'], 'is_last' => false); } elseif ($row['id_profile'] != 1 || $row['is_mod']) { $context['boards'][$row['id_board']] = array('id' => $row['id_board'], 'name' => $row['board_name'], 'url' => $scripturl, '?board=', $row['id_board'], '.0', 'selected' => $board == $row['id_board'], 'profile' => $row['id_profile'], 'profile_name' => $context['profiles'][$row['id_profile']]['name']); } } 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; } // Get all general permissions for the groups this member is in $context['member']['permissions']['general'] = getMemberGeneralPermissions($curGroups); // Get all board permissions for this member $context['member']['permissions']['board'] = getMemberBoardPermissions($memID, $curGroups, $board); }
function EditMessageIcons() { global $user_info, $modSettings, $context, $settings, $txt; global $boarddir, $smcFunc, $scripturl, $sourcedir; // Get a list of icons. $context['icons'] = array(); $request = $smcFunc['db_query']('', ' SELECT m.id_icon, m.title, m.filename, m.icon_order, m.id_board, b.name AS board_name FROM {db_prefix}message_icons AS m LEFT JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board) WHERE ({query_see_board} OR b.id_board IS NULL)', array()); $last_icon = 0; $trueOrder = 0; while ($row = $smcFunc['db_fetch_assoc']($request)) { $context['icons'][$row['id_icon']] = array('id' => $row['id_icon'], 'title' => $row['title'], 'filename' => $row['filename'], 'image_url' => $settings[file_exists($settings['theme_dir'] . '/images/post/' . $row['filename'] . '.gif') ? 'actual_images_url' : 'default_images_url'] . '/post/' . $row['filename'] . '.gif', 'board_id' => $row['id_board'], 'board' => empty($row['board_name']) ? $txt['icons_edit_icons_all_boards'] : $row['board_name'], 'order' => $row['icon_order'], 'true_order' => $trueOrder++, 'after' => $last_icon); $last_icon = $row['id_icon']; } $smcFunc['db_free_result']($request); // Submitting a form? if (isset($_POST[$context['session_var']])) { checkSession(); // Deleting icons? if (isset($_POST['delete']) && !empty($_POST['checked_icons'])) { $deleteIcons = array(); foreach ($_POST['checked_icons'] as $icon) { $deleteIcons[] = (int) $icon; } // Do the actual delete! $smcFunc['db_query']('', ' DELETE FROM {db_prefix}message_icons WHERE id_icon IN ({array_int:icon_list})', array('icon_list' => $deleteIcons)); } elseif ($context['sub_action'] == 'editicon' && isset($_GET['icon'])) { $_GET['icon'] = (int) $_GET['icon']; // Do some preperation with the data... like check the icon exists *somewhere* if (strpos($_POST['icon_filename'], '.gif') !== false) { $_POST['icon_filename'] = substr($_POST['icon_filename'], 0, -4); } if (!file_exists($settings['default_theme_dir'] . '/images/post/' . $_POST['icon_filename'] . '.gif')) { fatal_lang_error('icon_not_found'); } elseif (strlen($_POST['icon_filename']) > 16) { fatal_lang_error('icon_name_too_long'); } elseif ($_POST['icon_location'] == $_GET['icon'] && !empty($_GET['icon'])) { fatal_lang_error('icon_after_itself'); } // First do the sorting... if this is an edit reduce the order of everything after it by one ;) if ($_GET['icon'] != 0) { $oldOrder = $context['icons'][$_GET['icon']]['true_order']; foreach ($context['icons'] as $id => $data) { if ($data['true_order'] > $oldOrder) { $context['icons'][$id]['true_order']--; } } } // If there are no existing icons and this is a new one, set the id to 1 (mainly for non-mysql) if (empty($_GET['icon']) && empty($context['icons'])) { $_GET['icon'] = 1; } // Get the new order. $newOrder = $_POST['icon_location'] == 0 ? 0 : $context['icons'][$_POST['icon_location']]['true_order'] + 1; // Do the same, but with the one that used to be after this icon, done to avoid conflict. foreach ($context['icons'] as $id => $data) { if ($data['true_order'] >= $newOrder) { $context['icons'][$id]['true_order']++; } } // Finally set the current icon's position! $context['icons'][$_GET['icon']]['true_order'] = $newOrder; // Simply replace the existing data for the other bits. $context['icons'][$_GET['icon']]['title'] = $_POST['icon_description']; $context['icons'][$_GET['icon']]['filename'] = $_POST['icon_filename']; $context['icons'][$_GET['icon']]['board_id'] = (int) $_POST['icon_board']; // Do a huge replace ;) $iconInsert = array(); $iconInsert_new = array(); foreach ($context['icons'] as $id => $icon) { if ($id != 0) { $iconInsert[] = array($id, $icon['board_id'], $icon['title'], $icon['filename'], $icon['true_order']); } else { $iconInsert_new[] = array($icon['board_id'], $icon['title'], $icon['filename'], $icon['true_order']); } } $smcFunc['db_insert']('replace', '{db_prefix}message_icons', array('id_icon' => 'int', 'id_board' => 'int', 'title' => 'string-80', 'filename' => 'string-80', 'icon_order' => 'int'), $iconInsert, array('id_icon')); if (!empty($iconInsert_new)) { $smcFunc['db_insert']('replace', '{db_prefix}message_icons', array('id_board' => 'int', 'title' => 'string-80', 'filename' => 'string-80', 'icon_order' => 'int'), $iconInsert_new, array('id_icon')); } } // Sort by order, so it is quicker :) $smcFunc['db_query']('alter_table_icons', ' ALTER TABLE {db_prefix}message_icons ORDER BY icon_order', array('db_error_skip' => true)); // Unless we're adding a new thing, we'll escape if (!isset($_POST['add'])) { redirectexit('action=admin;area=smileys;sa=editicons'); } } $context[$context['admin_menu_name']]['current_subsection'] = 'editicons'; $listOptions = array('id' => 'message_icon_list', 'base_href' => $scripturl . '?action=admin;area=smileys;sa=editicons', 'get_items' => array('function' => 'list_getMessageIcons'), 'no_items_label' => $txt['icons_no_entries'], 'columns' => array('icon' => array('data' => array('function' => create_function('$rowData', ' global $settings; $images_url = $settings[file_exists(sprintf(\'%1$s/images/post/%2$s.gif\', $settings[\'theme_dir\'], $rowData[\'filename\'])) ? \'actual_images_url\' : \'default_images_url\']; return sprintf(\'<img src="%1$s/post/%2$s.gif" alt="%3$s" />\', $images_url, $rowData[\'filename\'], htmlspecialchars($rowData[\'title\'])); ')), 'style' => 'text-align: center;'), 'filename' => array('header' => array('value' => $txt['smileys_filename']), 'data' => array('sprintf' => array('format' => '%1$s.gif', 'params' => array('filename' => true)))), 'tooltip' => array('header' => array('value' => $txt['smileys_description']), 'data' => array('db_htmlsafe' => 'title', 'class' => 'windowbg')), 'board' => array('header' => array('value' => $txt['icons_board']), 'data' => array('function' => create_function('$rowData', ' global $txt; return empty($rowData[\'board_name\']) ? $txt[\'icons_edit_icons_all_boards\'] : $rowData[\'board_name\']; '))), 'modify' => array('header' => array('value' => $txt['smileys_modify']), 'data' => array('sprintf' => array('format' => '<a href="' . $scripturl . '?action=admin;area=smileys;sa=editicon;icon=%1$s">' . $txt['smileys_modify'] . '</a>', 'params' => array('id_icon' => false)), 'style' => 'text-align: center')), 'check' => array('header' => array('value' => '<input type="checkbox" onclick="invertAll(this, this.form);" class="input_check" />'), 'data' => array('sprintf' => array('format' => '<input type="checkbox" name="checked_icons[]" value="%1$d" class="input_check" />', 'params' => array('id_icon' => false)), 'style' => 'text-align: center'))), 'form' => array('href' => $scripturl . '?action=admin;area=smileys;sa=editicons'), 'additional_rows' => array(array('position' => 'below_table_data', 'value' => '<input type="submit" name="delete" value="' . $txt['quickmod_delete_selected'] . '" style="float: right" class="button_submit" />[<a href="' . $scripturl . '?action=admin;area=smileys;sa=editicon">' . $txt['icons_add_new'] . '</a>]'))); require_once $sourcedir . '/Subs-List.php'; createList($listOptions); // If we're adding/editing an icon we'll need a list of boards if ($context['sub_action'] == 'editicon' || isset($_POST['add'])) { // Force the sub_template just in case. $context['sub_template'] = 'editicon'; $context['new_icon'] = !isset($_GET['icon']); // Get the properties of the current icon from the icon list. if (!$context['new_icon']) { $context['icon'] = $context['icons'][$_GET['icon']]; } // Get a list of boards needed for assigning this icon to a specific board. $boardListOptions = array('use_permissions' => true, 'selected_board' => isset($context['icon']['board_id']) ? $context['icon']['board_id'] : 0); require_once $sourcedir . '/Subs-MessageIndex.php'; $context['categories'] = getBoardList($boardListOptions); } }
/** * Handles showing the post screen, loading the post to be modified, and loading any post quoted. * * - additionally handles previews of posts. * - @uses the Post template and language file, main sub template. * - allows wireless access using the protocol_post sub template. * - requires different permissions depending on the actions, but most notably post_new, post_reply_own, and post_reply_any. * - shows options for the editing and posting of calendar events and attachments, as well as the posting of polls. * - accessed from ?action=post. */ function Post($post_errors = array()) { global $txt, $scripturl, $topic, $modSettings, $board; global $user_info, $sc, $board_info, $context, $settings; global $sourcedir, $options, $smcFunc, $language; loadLanguage('Post'); // You can't reply with a poll... hacker. if (isset($_REQUEST['poll']) && !empty($topic) && !isset($_REQUEST['msg'])) { unset($_REQUEST['poll']); } // Posting an event? $context['make_event'] = isset($_REQUEST['calendar']); $context['robot_no_index'] = true; // You must be posting to *some* board. if (empty($board) && !$context['make_event']) { fatal_lang_error('no_board', false); } require_once $sourcedir . '/Subs-Post.php'; if (isset($_REQUEST['xml'])) { $context['sub_template'] = 'post'; // Just in case of an earlier error... $context['preview_message'] = ''; $context['preview_subject'] = ''; } // No message is complete without a topic. if (empty($topic) && !empty($_REQUEST['msg'])) { $request = $smcFunc['db_query']('', ' SELECT id_topic FROM {db_prefix}messages WHERE id_msg = {int:msg}', array('msg' => (int) $_REQUEST['msg'])); if ($smcFunc['db_num_rows']($request) != 1) { unset($_REQUEST['msg'], $_POST['msg'], $_GET['msg']); } else { list($topic) = $smcFunc['db_fetch_row']($request); } $smcFunc['db_free_result']($request); } // Check if it's locked. It isn't locked if no topic is specified. if (!empty($topic)) { $request = $smcFunc['db_query']('', ' SELECT t.locked, IFNULL(ln.id_topic, 0) AS notify, t.is_sticky, t.id_poll, t.id_last_msg, mf.id_member, t.id_first_msg, mf.subject, CASE WHEN ml.poster_time > ml.modified_time THEN ml.poster_time ELSE ml.modified_time END AS last_post_time FROM {db_prefix}topics AS t LEFT JOIN {db_prefix}log_notify AS ln ON (ln.id_topic = t.id_topic AND ln.id_member = {int:current_member}) LEFT JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg) LEFT JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg) WHERE t.id_topic = {int:current_topic} LIMIT 1', array('current_member' => $user_info['id'], 'current_topic' => $topic)); list($locked, $context['notify'], $sticky, $pollID, $context['topic_last_message'], $id_member_poster, $id_first_msg, $first_subject, $lastPostTime) = $smcFunc['db_fetch_row']($request); $smcFunc['db_free_result']($request); // If this topic already has a poll, they sure can't add another. if (isset($_REQUEST['poll']) && $pollID > 0) { unset($_REQUEST['poll']); } if (empty($_REQUEST['msg'])) { if ($user_info['is_guest'] && !allowedTo('post_reply_any') && (!$modSettings['postmod_active'] || !allowedTo('post_unapproved_replies_any'))) { is_not_guest(); } // By default the reply will be approved... $context['becomes_approved'] = true; if ($id_member_poster != $user_info['id']) { if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_any') && !allowedTo('post_reply_any')) { $context['becomes_approved'] = false; } else { isAllowedTo('post_reply_any'); } } elseif (!allowedTo('post_reply_any')) { if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_own') && !allowedTo('post_reply_own')) { $context['becomes_approved'] = false; } else { isAllowedTo('post_reply_own'); } } } else { $context['becomes_approved'] = true; } $context['can_lock'] = allowedTo('lock_any') || $user_info['id'] == $id_member_poster && allowedTo('lock_own'); $context['can_sticky'] = allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']); $context['notify'] = !empty($context['notify']); $context['sticky'] = isset($_REQUEST['sticky']) ? !empty($_REQUEST['sticky']) : $sticky; // Check whether this is a really old post being bumped... if (!empty($modSettings['oldTopicDays']) && $lastPostTime + $modSettings['oldTopicDays'] * 86400 < time() && empty($sticky) && !isset($_REQUEST['subject'])) { $post_errors[] = array('old_topic', array($modSettings['oldTopicDays'])); } } else { $context['becomes_approved'] = true; if (!$context['make_event'] || !empty($board)) { if ($modSettings['postmod_active'] && !allowedTo('post_new') && allowedTo('post_unapproved_topics')) { $context['becomes_approved'] = false; } else { isAllowedTo('post_new'); } } $locked = 0; // @todo These won't work if you're making an event. $context['can_lock'] = allowedTo(array('lock_any', 'lock_own')); $context['can_sticky'] = allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']); $context['notify'] = !empty($context['notify']); $context['sticky'] = !empty($_REQUEST['sticky']); } // @todo These won't work if you're posting an event! $context['can_notify'] = allowedTo('mark_any_notify'); $context['can_move'] = allowedTo('move_any'); $context['move'] = !empty($_REQUEST['move']); $context['announce'] = !empty($_REQUEST['announce']); // You can only announce topics that will get approved... $context['can_announce'] = allowedTo('announce_topic') && $context['becomes_approved']; $context['locked'] = !empty($locked) || !empty($_REQUEST['lock']); $context['can_quote'] = empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC'])); // Generally don't show the approval box... (Assume we want things approved) $context['show_approval'] = allowedTo('approve_posts') && $context['becomes_approved'] ? 2 : (allowedTo('approve_posts') ? 1 : 0); // An array to hold all the attachments for this topic. $context['current_attachments'] = array(); // Don't allow a post if it's locked and you aren't all powerful. if ($locked && !allowedTo('moderate_board')) { fatal_lang_error('topic_locked', false); } // Check the users permissions - is the user allowed to add or post a poll? if (isset($_REQUEST['poll']) && $modSettings['pollMode'] == '1') { // New topic, new poll. if (empty($topic)) { isAllowedTo('poll_post'); } elseif ($user_info['id'] == $id_member_poster && !allowedTo('poll_add_any')) { isAllowedTo('poll_add_own'); } else { isAllowedTo('poll_add_any'); } require_once $sourcedir . '/Subs-Members.php'; $allowedVoteGroups = groupsAllowedTo('poll_vote', $board); // Set up the poll options. $context['poll_options'] = array('max_votes' => empty($_POST['poll_max_votes']) ? '1' : max(1, $_POST['poll_max_votes']), 'hide' => empty($_POST['poll_hide']) ? 0 : $_POST['poll_hide'], 'expire' => !isset($_POST['poll_expire']) ? '' : $_POST['poll_expire'], 'change_vote' => isset($_POST['poll_change_vote']), 'guest_vote' => isset($_POST['poll_guest_vote']), 'guest_vote_enabled' => in_array(-1, $allowedVoteGroups['allowed'])); // Make all five poll choices empty. $context['choices'] = array(array('id' => 0, 'number' => 1, 'label' => '', 'is_last' => false), array('id' => 1, 'number' => 2, 'label' => '', 'is_last' => false), array('id' => 2, 'number' => 3, 'label' => '', 'is_last' => false), array('id' => 3, 'number' => 4, 'label' => '', 'is_last' => false), array('id' => 4, 'number' => 5, 'label' => '', 'is_last' => true)); $context['last_choice_id'] = 4; } if ($context['make_event']) { // They might want to pick a board. if (!isset($context['current_board'])) { $context['current_board'] = 0; } // Start loading up the event info. $context['event'] = array(); $context['event']['title'] = isset($_REQUEST['evtitle']) ? htmlspecialchars(stripslashes($_REQUEST['evtitle'])) : ''; $context['event']['id'] = isset($_REQUEST['eventid']) ? (int) $_REQUEST['eventid'] : -1; $context['event']['new'] = $context['event']['id'] == -1; // Permissions check! isAllowedTo('calendar_post'); // Editing an event? (but NOT previewing!?) if (empty($context['event']['new']) && !isset($_REQUEST['subject'])) { // If the user doesn't have permission to edit the post in this topic, redirect them. if ((empty($id_member_poster) || $id_member_poster != $user_info['id'] || !allowedTo('modify_own')) && !allowedTo('modify_any')) { require_once $sourcedir . '/Calendar.php'; return CalendarPost(); } // Get the current event information. $request = $smcFunc['db_query']('', ' SELECT id_member, title, MONTH(start_date) AS month, DAYOFMONTH(start_date) AS day, YEAR(start_date) AS year, (TO_DAYS(end_date) - TO_DAYS(start_date)) AS span FROM {db_prefix}calendar WHERE id_event = {int:id_event} LIMIT 1', array('id_event' => $context['event']['id'])); $row = $smcFunc['db_fetch_assoc']($request); $smcFunc['db_free_result']($request); // Make sure the user is allowed to edit this event. if ($row['id_member'] != $user_info['id']) { isAllowedTo('calendar_edit_any'); } elseif (!allowedTo('calendar_edit_any')) { isAllowedTo('calendar_edit_own'); } $context['event']['month'] = $row['month']; $context['event']['day'] = $row['day']; $context['event']['year'] = $row['year']; $context['event']['title'] = $row['title']; $context['event']['span'] = $row['span'] + 1; } else { $today = getdate(); // You must have a month and year specified! if (!isset($_REQUEST['month'])) { $_REQUEST['month'] = $today['mon']; } if (!isset($_REQUEST['year'])) { $_REQUEST['year'] = $today['year']; } $context['event']['month'] = (int) $_REQUEST['month']; $context['event']['year'] = (int) $_REQUEST['year']; $context['event']['day'] = isset($_REQUEST['day']) ? $_REQUEST['day'] : ($_REQUEST['month'] == $today['mon'] ? $today['mday'] : 0); $context['event']['span'] = isset($_REQUEST['span']) ? $_REQUEST['span'] : 1; // Make sure the year and month are in the valid range. if ($context['event']['month'] < 1 || $context['event']['month'] > 12) { fatal_lang_error('invalid_month', false); } if ($context['event']['year'] < $modSettings['cal_minyear'] || $context['event']['year'] > $modSettings['cal_maxyear']) { fatal_lang_error('invalid_year', false); } // Get a list of boards they can post in. $boards = boardsAllowedTo('post_new'); if (empty($boards)) { fatal_lang_error('cannot_post_new', 'user'); } // Load a list of boards for this event in the context. require_once $sourcedir . '/Subs-MessageIndex.php'; $boardListOptions = array('included_boards' => in_array(0, $boards) ? null : $boards, 'not_redirection' => true, 'use_permissions' => true, 'selected_board' => empty($context['current_board']) ? $modSettings['cal_defaultboard'] : $context['current_board']); $context['event']['categories'] = getBoardList($boardListOptions); } // Find the last day of the month. $context['event']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['event']['month'] == 12 ? 1 : $context['event']['month'] + 1, 0, $context['event']['month'] == 12 ? $context['event']['year'] + 1 : $context['event']['year'])); $context['event']['board'] = !empty($board) ? $board : $modSettings['cal_defaultboard']; } // See if any new replies have come along. // Huh, $_REQUEST['msg'] is set upon submit, so this doesn't get executed at submit // only at preview if (empty($_REQUEST['msg']) && !empty($topic)) { if (empty($options['no_new_reply_warning']) && isset($_REQUEST['last_msg']) && $context['topic_last_message'] > $_REQUEST['last_msg']) { $request = $smcFunc['db_query']('', ' SELECT COUNT(*) FROM {db_prefix}messages WHERE id_topic = {int:current_topic} AND id_msg > {int:last_msg}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : ' AND approved = {int:approved}') . ' LIMIT 1', array('current_topic' => $topic, 'last_msg' => (int) $_REQUEST['last_msg'], 'approved' => 1)); list($context['new_replies']) = $smcFunc['db_fetch_row']($request); $smcFunc['db_free_result']($request); if (!empty($context['new_replies'])) { if ($context['new_replies'] == 1) { $txt['error_new_replies'] = isset($_GET['last_msg']) ? $txt['error_new_reply_reading'] : $txt['error_new_reply']; } else { $txt['error_new_replies'] = sprintf(isset($_GET['last_msg']) ? $txt['error_new_replies_reading'] : $txt['error_new_replies'], $context['new_replies']); } $post_errors[] = 'new_replies'; $modSettings['topicSummaryPosts'] = $context['new_replies'] > $modSettings['topicSummaryPosts'] ? max($modSettings['topicSummaryPosts'], 5) : $modSettings['topicSummaryPosts']; } } } // Get a response prefix (like 'Re:') in the default forum language. if (!isset($context['response_prefix']) && !($context['response_prefix'] = cache_get_data('response_prefix'))) { if ($language === $user_info['language']) { $context['response_prefix'] = $txt['response_prefix']; } else { loadLanguage('index', $language, false); $context['response_prefix'] = $txt['response_prefix']; loadLanguage('index'); } cache_put_data('response_prefix', $context['response_prefix'], 600); } // Previewing, modifying, or posting? // Do we have a body, but an error happened. if (isset($_REQUEST['message']) || !empty($context['post_error'])) { // Validate inputs. if (empty($context['post_error'])) { // This means they didn't click Post and get an error. $really_previewing = true; } else { if (!isset($_REQUEST['subject'])) { $_REQUEST['subject'] = ''; } if (!isset($_REQUEST['message'])) { $_REQUEST['message'] = ''; } if (!isset($_REQUEST['icon'])) { $_REQUEST['icon'] = 'xx'; } // They are previewing if they asked to preview (i.e. came from quick reply). $really_previewing = !empty($_POST['preview']); } // In order to keep the approval status flowing through, we have to pass it through the form... $context['becomes_approved'] = empty($_REQUEST['not_approved']); $context['show_approval'] = isset($_REQUEST['approve']) ? $_REQUEST['approve'] ? 2 : 1 : 0; $context['can_announce'] &= $context['becomes_approved']; // Set up the inputs for the form. $form_subject = strtr($smcFunc['htmlspecialchars']($_REQUEST['subject']), array("\r" => '', "\n" => '', "\t" => '')); $form_message = $smcFunc['htmlspecialchars']($_REQUEST['message'], ENT_QUOTES); // Make sure the subject isn't too long - taking into account special characters. if ($smcFunc['strlen']($form_subject) > 100) { $form_subject = $smcFunc['substr']($form_subject, 0, 100); } if (isset($_REQUEST['poll'])) { $context['question'] = isset($_REQUEST['question']) ? $smcFunc['htmlspecialchars'](trim($_REQUEST['question'])) : ''; $context['choices'] = array(); $choice_id = 0; $_POST['options'] = empty($_POST['options']) ? array() : htmlspecialchars__recursive($_POST['options']); foreach ($_POST['options'] as $option) { if (trim($option) == '') { continue; } $context['choices'][] = array('id' => $choice_id++, 'number' => $choice_id, 'label' => $option, 'is_last' => false); } // One empty option for those with js disabled...I know are few... :P $context['choices'][] = array('id' => $choice_id++, 'number' => $choice_id, 'label' => '', 'is_last' => false); if (count($context['choices']) < 2) { $context['choices'][] = array('id' => $choice_id++, 'number' => $choice_id, 'label' => '', 'is_last' => false); } $context['last_choice_id'] = $choice_id; $context['choices'][count($context['choices']) - 1]['is_last'] = true; } // Are you... a guest? if ($user_info['is_guest']) { $_REQUEST['guestname'] = !isset($_REQUEST['guestname']) ? '' : trim($_REQUEST['guestname']); $_REQUEST['email'] = !isset($_REQUEST['email']) ? '' : trim($_REQUEST['email']); $_REQUEST['guestname'] = htmlspecialchars($_REQUEST['guestname']); $context['name'] = $_REQUEST['guestname']; $_REQUEST['email'] = htmlspecialchars($_REQUEST['email']); $context['email'] = $_REQUEST['email']; $user_info['name'] = $_REQUEST['guestname']; } // Only show the preview stuff if they hit Preview. if (($really_previewing == true || isset($_REQUEST['xml'])) && !isset($_POST['id_draft'])) { // Set up the preview message and subject and censor them... $context['preview_message'] = $form_message; preparsecode($form_message, true); preparsecode($context['preview_message']); // Do all bulletin board code tags, with or without smileys. $context['preview_message'] = parse_bbc($context['preview_message'], isset($_REQUEST['ns']) ? 0 : 1); censorText($context['preview_message']); if ($form_subject != '') { $context['preview_subject'] = $form_subject; censorText($context['preview_subject']); } else { $context['preview_subject'] = '<em>' . $txt['no_subject'] . '</em>'; } // Protect any CDATA blocks. if (isset($_REQUEST['xml'])) { $context['preview_message'] = strtr($context['preview_message'], array(']]>' => ']]]]><![CDATA[>')); } } // Set up the checkboxes. $context['notify'] = !empty($_REQUEST['notify']); $context['use_smileys'] = !isset($_REQUEST['ns']); $context['icon'] = isset($_REQUEST['icon']) ? preg_replace('~[\\./\\\\*\':"<>]~', '', $_REQUEST['icon']) : 'xx'; // Set the destination action for submission. $context['destination'] = 'post2;start=' . $_REQUEST['start'] . (isset($_REQUEST['msg']) ? ';msg=' . $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id'] : '') . (isset($_REQUEST['poll']) ? ';poll' : ''); $context['submit_label'] = isset($_REQUEST['msg']) ? $txt['save'] : $txt['post']; // Previewing an edit? if (isset($_REQUEST['msg']) && !empty($topic)) { // Get the existing message. $request = $smcFunc['db_query']('', ' SELECT m.id_member, m.modified_time, m.smileys_enabled, m.body, m.poster_name, m.poster_email, m.subject, m.icon, m.approved, IFNULL(a.size, -1) AS filesize, a.filename, a.id_attach, a.approved AS attachment_approved, t.id_member_started AS id_member_poster, m.poster_time, log.id_action FROM {db_prefix}messages AS m INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic}) LEFT JOIN {db_prefix}attachments AS a ON (a.id_msg = m.id_msg AND a.attachment_type = {int:attachment_type}) LEFT JOIN {db_prefix}log_actions AS log ON (m.id_topic = log.id_topic AND log.action = {string:announce_action}) WHERE m.id_msg = {int:id_msg} AND m.id_topic = {int:current_topic}', array('current_topic' => $topic, 'attachment_type' => 0, 'id_msg' => $_REQUEST['msg'], 'announce_action' => 'announce_topic')); // The message they were trying to edit was most likely deleted. // @todo Change this error message? if ($smcFunc['db_num_rows']($request) == 0) { fatal_lang_error('no_board', false); } $row = $smcFunc['db_fetch_assoc']($request); $attachment_stuff = array($row); while ($row2 = $smcFunc['db_fetch_assoc']($request)) { $attachment_stuff[] = $row2; } $smcFunc['db_free_result']($request); if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any')) { // Give an extra five minutes over the disable time threshold, so they can type - assuming the post is public. if ($row['approved'] && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time()) { fatal_lang_error('modify_post_time_passed', false); } elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_own')) { isAllowedTo('modify_replies'); } else { isAllowedTo('modify_own'); } } elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_any')) { isAllowedTo('modify_replies'); } else { isAllowedTo('modify_any'); } if (!empty($modSettings['attachmentEnable'])) { $request = $smcFunc['db_query']('', ' SELECT IFNULL(size, -1) AS filesize, filename, id_attach, approved FROM {db_prefix}attachments WHERE id_msg = {int:id_msg} AND attachment_type = {int:attachment_type} ORDER BY id_attach', array('id_msg' => (int) $_REQUEST['msg'], 'attachment_type' => 0)); while ($row = $smcFunc['db_fetch_assoc']($request)) { if ($row['filesize'] <= 0) { continue; } $context['current_attachments'][] = array('name' => htmlspecialchars($row['filename']), 'size' => $row['filesize'], 'id' => $row['id_attach'], 'approved' => $row['approved']); } $smcFunc['db_free_result']($request); } if ($context['can_announce'] && !empty($row['id_action'])) { loadLanguage('Errors'); $context['post_error']['messages'][] = $txt['error_topic_already_announced']; } // Allow moderators to change names.... if (allowedTo('moderate_forum') && !empty($topic)) { $request = $smcFunc['db_query']('', ' SELECT id_member, poster_name, poster_email FROM {db_prefix}messages WHERE id_msg = {int:id_msg} AND id_topic = {int:current_topic} LIMIT 1', array('current_topic' => $topic, 'id_msg' => (int) $_REQUEST['msg'])); $row = $smcFunc['db_fetch_assoc']($request); $smcFunc['db_free_result']($request); if (empty($row['id_member'])) { $context['name'] = htmlspecialchars($row['poster_name']); $context['email'] = htmlspecialchars($row['poster_email']); } } } // No check is needed, since nothing is really posted. checkSubmitOnce('free'); } elseif (isset($_REQUEST['msg']) && !empty($topic)) { $_REQUEST['msg'] = (int) $_REQUEST['msg']; // Get the existing message. $request = $smcFunc['db_query']('', ' SELECT m.id_member, m.modified_time, m.smileys_enabled, m.body, m.poster_name, m.poster_email, m.subject, m.icon, m.approved, IFNULL(a.size, -1) AS filesize, a.filename, a.id_attach, a.approved AS attachment_approved, t.id_member_started AS id_member_poster, m.poster_time, log.id_action FROM {db_prefix}messages AS m INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic}) LEFT JOIN {db_prefix}attachments AS a ON (a.id_msg = m.id_msg AND a.attachment_type = {int:attachment_type}) LEFT JOIN {db_prefix}log_actions AS log ON (m.id_topic = log.id_topic AND log.action = {string:announce_action}) WHERE m.id_msg = {int:id_msg} AND m.id_topic = {int:current_topic}', array('current_topic' => $topic, 'attachment_type' => 0, 'id_msg' => $_REQUEST['msg'], 'announce_action' => 'announce_topic')); // The message they were trying to edit was most likely deleted. if ($smcFunc['db_num_rows']($request) == 0) { fatal_lang_error('no_message', false); } $row = $smcFunc['db_fetch_assoc']($request); $attachment_stuff = array($row); while ($row2 = $smcFunc['db_fetch_assoc']($request)) { $attachment_stuff[] = $row2; } $smcFunc['db_free_result']($request); if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any')) { // Give an extra five minutes over the disable time threshold, so they can type - assuming the post is public. if ($row['approved'] && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time()) { fatal_lang_error('modify_post_time_passed', false); } elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_own')) { isAllowedTo('modify_replies'); } else { isAllowedTo('modify_own'); } } elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_any')) { isAllowedTo('modify_replies'); } else { isAllowedTo('modify_any'); } if ($context['can_announce'] && !empty($row['id_action'])) { loadLanguage('Errors'); $context['post_error']['messages'][] = $txt['error_topic_already_announced']; } // When was it last modified? if (!empty($row['modified_time'])) { $context['last_modified'] = timeformat($row['modified_time']); } // Get the stuff ready for the form. $form_subject = $row['subject']; $form_message = un_preparsecode($row['body']); censorText($form_message); censorText($form_subject); // Check the boxes that should be checked. $context['use_smileys'] = !empty($row['smileys_enabled']); $context['icon'] = $row['icon']; // Show an "approve" box if the user can approve it, and the message isn't approved. if (!$row['approved'] && !$context['show_approval']) { $context['show_approval'] = allowedTo('approve_posts'); } // Sort the attachments so they are in the order saved $temp = array(); foreach ($attachment_stuff as $attachment) { if ($attachment['filesize'] >= 0 && !empty($modSettings['attachmentEnable'])) { $temp[$attachment['id_attach']] = $attachment; } } ksort($temp); // Load up 'em attachments! foreach ($temp as $attachment) { $context['current_attachments'][] = array('name' => htmlspecialchars($attachment['filename']), 'size' => $attachment['filesize'], 'id' => $attachment['id_attach'], 'approved' => $attachment['attachment_approved']); } // Allow moderators to change names.... if (allowedTo('moderate_forum') && empty($row['id_member'])) { $context['name'] = htmlspecialchars($row['poster_name']); $context['email'] = htmlspecialchars($row['poster_email']); } // Set the destinaton. $context['destination'] = 'post2;start=' . $_REQUEST['start'] . ';msg=' . $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id'] . (isset($_REQUEST['poll']) ? ';poll' : ''); $context['submit_label'] = $txt['save']; } else { // By default.... $context['use_smileys'] = true; $context['icon'] = 'xx'; if ($user_info['is_guest']) { $context['name'] = isset($_SESSION['guest_name']) ? $_SESSION['guest_name'] : ''; $context['email'] = isset($_SESSION['guest_email']) ? $_SESSION['guest_email'] : ''; } $context['destination'] = 'post2;start=' . $_REQUEST['start'] . (isset($_REQUEST['poll']) ? ';poll' : ''); $context['submit_label'] = $txt['post']; // Posting a quoted reply? if (!empty($topic) && !empty($_REQUEST['quote'])) { // Make sure they _can_ quote this post, and if so get it. $request = $smcFunc['db_query']('', ' SELECT m.subject, IFNULL(mem.real_name, m.poster_name) AS poster_name, m.poster_time, m.body FROM {db_prefix}messages AS m 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}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : ' AND m.approved = {int:is_approved}') . ' LIMIT 1', array('id_msg' => (int) $_REQUEST['quote'], 'is_approved' => 1)); if ($smcFunc['db_num_rows']($request) == 0) { fatal_lang_error('quoted_post_deleted', false); } list($form_subject, $mname, $mdate, $form_message) = $smcFunc['db_fetch_row']($request); $smcFunc['db_free_result']($request); // Add 'Re: ' to the front of the quoted subject. if (trim($context['response_prefix']) != '' && $smcFunc['strpos']($form_subject, trim($context['response_prefix'])) !== 0) { $form_subject = $context['response_prefix'] . $form_subject; } // Censor the message and subject. censorText($form_message); censorText($form_subject); // But if it's in HTML world, turn them into htmlspecialchar's so they can be edited! if (strpos($form_message, '[html]') !== false) { $parts = preg_split('~(\\[/code\\]|\\[code(?:=[^\\]]+)?\\])~i', $form_message, -1, PREG_SPLIT_DELIM_CAPTURE); for ($i = 0, $n = count($parts); $i < $n; $i++) { // It goes 0 = outside, 1 = begin tag, 2 = inside, 3 = close tag, repeat. if ($i % 4 == 0) { $parts[$i] = preg_replace('~\\[html\\](.+?)\\[/html\\]~ise', '\'[html]\' . preg_replace(\'~<br\\s?/?' . '>~i\', \'<br /><br />\', \'$1\') . \'[/html]\'', $parts[$i]); } } $form_message = implode('', $parts); } $form_message = preg_replace('~<br ?/?' . '>~i', "\n", $form_message); // Remove any nested quotes, if necessary. if (!empty($modSettings['removeNestedQuotes'])) { $form_message = preg_replace(array('~\\n?\\[quote.*?\\].+?\\[/quote\\]\\n?~is', '~^\\n~', '~\\[/quote\\]~'), '', $form_message); } // Add a quote string on the front and end. $form_message = '[quote author=' . $mname . ' link=topic=' . $topic . '.msg' . (int) $_REQUEST['quote'] . '#msg' . (int) $_REQUEST['quote'] . ' date=' . $mdate . ']' . "\n" . rtrim($form_message) . "\n" . '[/quote]'; } elseif (!empty($topic) && empty($_REQUEST['quote'])) { // Get the first message's subject. $form_subject = $first_subject; // Add 'Re: ' to the front of the subject. if (trim($context['response_prefix']) != '' && $form_subject != '' && $smcFunc['strpos']($form_subject, trim($context['response_prefix'])) !== 0) { $form_subject = $context['response_prefix'] . $form_subject; } // Censor the subject. censorText($form_subject); $form_message = ''; } else { $form_subject = isset($_GET['subject']) ? $_GET['subject'] : ''; $form_message = ''; } } $context['can_post_attachment'] = !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1 && (allowedTo('post_attachment') || $modSettings['postmod_active'] && allowedTo('post_unapproved_attachments')); if ($context['can_post_attachment']) { // If there are attachments, calculate the total size and how many. $context['attachments']['total_size'] = 0; $context['attachments']['quantity'] = 0; // If this isn't a new post, check the current attachments. if (isset($_REQUEST['msg'])) { $context['attachments']['quantity'] = count($context['current_attachments']); foreach ($context['current_attachments'] as $attachment) { $context['attachments']['total_size'] += $attachment['size']; } } // A bit of house keeping first. if (!empty($_SESSION['temp_attachments']) && count($_SESSION['temp_attachments']) == 1) { unset($_SESSION['temp_attachments']); } if (!empty($_SESSION['temp_attachments'])) { // Is this a request to delete them? if (isset($_GET['delete_temp'])) { foreach ($_SESSION['temp_attachments'] as $attachID => $attachment) { if (strpos($attachID, 'post_tmp_' . $user_info['id']) !== false) { if (file_exists($attachment['tmp_name'])) { unlink($attachment['tmp_name']); } } } $post_errors[] = 'temp_attachments_gone'; $_SESSION['temp_attachments'] = array(); } elseif ($context['current_action'] != 'post2' || !empty($_POST['from_qr'])) { // Let's be nice and see if they belong here first. if (empty($_REQUEST['msg']) && empty($_SESSION['temp_attachments']['post']['msg']) && $_SESSION['temp_attachments']['post']['board'] == $board || !empty($_REQUEST['msg']) && $_SESSION['temp_attachments']['post']['msg'] == $_REQUEST['msg']) { // See if any files still exist before showing the warning message and the files attached. foreach ($_SESSION['temp_attachments'] as $attachID => $attachment) { if (strpos($attachID, 'post_tmp_' . $user_info['id']) === false) { continue; } if (file_exists($attachment['tmp_name'])) { $post_errors[] = 'temp_attachments_new'; $context['files_in_session_warning'] = $txt['attached_files_in_session']; unset($_SESSION['temp_attachments']['post']['files']); break; } } } else { // Since, they don't belong here. Let's inform the user that they exist.. if (!empty($topic)) { $delete_link = '<a href="' . $scripturl . '?action=post' . (!empty($_REQUEST['msg']) ? ';msg=' . $_REQUEST['msg'] : '') . (!empty($_REQUEST['last_msg']) ? ';last_msg=' . $_REQUEST['last_msg'] : '') . ';topic=' . $topic . ';delete_temp">' . $txt['here'] . '</a>'; } else { $delete_link = '<a href="' . $scripturl . '?action=post;board=' . $board . ';delete_temp">' . $txt['here'] . '</a>'; } // Compile a list of the files to show the user. $file_list = array(); foreach ($_SESSION['temp_attachments'] as $attachID => $attachment) { if (strpos($attachID, 'post_tmp_' . $user_info['id']) !== false) { $file_list[] = $attachment['name']; } } $_SESSION['temp_attachments']['post']['files'] = $file_list; $file_list = '<div class="attachments">' . implode('<br />', $file_list) . '</div>'; if (!empty($_SESSION['temp_attachments']['post']['msg'])) { // We have a message id, so we can link back to the old topic they were trying to edit.. $goback_link = '<a href="' . $scripturl . '?action=post' . (!empty($_SESSION['temp_attachments']['post']['msg']) ? ';msg=' . $_SESSION['temp_attachments']['post']['msg'] : '') . (!empty($_SESSION['temp_attachments']['post']['last_msg']) ? ';last_msg=' . $_SESSION['temp_attachments']['post']['last_msg'] : '') . ';topic=' . $_SESSION['temp_attachments']['post']['topic'] . ';additionalOptions">' . $txt['here'] . '</a>'; $post_errors[] = array('temp_attachments_found', array($delete_link, $goback_link, $file_list)); $context['ignore_temp_attachments'] = true; } else { $post_errors[] = array('temp_attachments_lost', array($delete_link, $file_list)); $context['ignore_temp_attachments'] = true; } } } if (!empty($context['we_are_history'])) { $post_errors[] = $context['we_are_history']; } foreach ($_SESSION['temp_attachments'] as $attachID => $attachment) { if (isset($context['ignore_temp_attachments']) || isset($_SESSION['temp_attachments']['post']['files'])) { break; } if ($attachID != 'initial_error' && strpos($attachID, 'post_tmp_' . $user_info['id']) === false) { continue; } if ($attachID == 'initial_error') { $txt['error_attach_initial_error'] = $txt['attach_no_upload'] . '<div style="padding: 0 1em;">' . (is_array($attachment) ? vsprintf($txt[$attachment[0]], $attachment[1]) : $txt[$attachment]) . '</div>'; $post_errors[] = 'attach_initial_error'; unset($_SESSION['temp_attachments']); break; } // Show any errors which might of occured. if (!empty($attachment['errors'])) { $txt['error_attach_errors'] = empty($txt['error_attach_errors']) ? '<br />' : ''; $txt['error_attach_errors'] .= vsprintf($txt['attach_warning'], $attachment['name']) . '<div style="padding: 0 1em;">'; foreach ($attachment['errors'] as $error) { $txt['error_attach_errors'] .= (is_array($error) ? vsprintf($txt[$error[0]], $error[1]) : $txt[$error]) . '<br />'; } $txt['error_attach_errors'] .= '</div>'; $post_errors[] = 'attach_errors'; // Take out the trash. unset($_SESSION['temp_attachments'][$attachID]); if (file_exists($attachment['tmp_name'])) { unlink($attachment['tmp_name']); } continue; } // More house keeping. if (!file_exists($attachment['tmp_name'])) { unset($_SESSION['temp_attachments'][$attachID]); continue; } $context['attachments']['quantity']++; $context['attachments']['total_size'] += $attachment['size']; if (!isset($context['files_in_session_warning'])) { $context['files_in_session_warning'] = $txt['attached_files_in_session']; } $context['current_attachments'][] = array('name' => '<u>' . htmlspecialchars($attachment['name']) . '</u>', 'size' => $attachment['size'], 'id' => $attachID, 'unchecked' => false, 'approved' => 1); } } } // Do we need to show the visual verification image? $context['require_verification'] = !$user_info['is_mod'] && !$user_info['is_admin'] && !empty($modSettings['posts_require_captcha']) && ($user_info['posts'] < $modSettings['posts_require_captcha'] || $user_info['is_guest'] && $modSettings['posts_require_captcha'] == -1); if ($context['require_verification']) { require_once $sourcedir . '/Subs-Editor.php'; $verificationOptions = array('id' => 'post'); $context['require_verification'] = create_control_verification($verificationOptions); $context['visual_verification_id'] = $verificationOptions['id']; } // If they came from quick reply, and have to enter verification details, give them some notice. if (!empty($_REQUEST['from_qr']) && !empty($context['require_verification'])) { $post_errors[] = 'need_qr_verification'; } /* * There are two error types: serious and miinor. Serious errors * actually tell the user that a real error has occurred, while minor * errors are like warnings that let them know that something with * their post isn't right. */ $minor_errors = array('not_approved', 'new_replies', 'old_topic', 'need_qr_verification', 'no_subject'); call_integration_hook('integrate_post_errors', array($post_errors, $minor_errors)); // Any errors occurred? if (!empty($post_errors)) { loadLanguage('Errors'); $context['error_type'] = 'minor'; foreach ($post_errors as $post_error) { if (is_array($post_error)) { $post_error_id = $post_error[0]; $context['post_error'][$post_error_id] = vsprintf($txt['error_' . $post_error_id], $post_error[1]); // If it's not a minor error flag it as such. if (!in_array($post_error_id, $minor_errors)) { $context['error_type'] = 'serious'; } } else { $context['post_error'][$post_error] = $txt['error_' . $post_error]; // If it's not a minor error flag it as such. if (!in_array($post_error, $minor_errors)) { $context['error_type'] = 'serious'; } } } } // What are you doing? Posting a poll, modifying, previewing, new post, or reply... if (isset($_REQUEST['poll'])) { $context['page_title'] = $txt['new_poll']; } elseif ($context['make_event']) { $context['page_title'] = $context['event']['id'] == -1 ? $txt['calendar_post_event'] : $txt['calendar_edit']; } elseif (isset($_REQUEST['msg'])) { $context['page_title'] = $txt['modify_msg']; } elseif (isset($_REQUEST['subject'], $context['preview_subject'])) { $context['page_title'] = $txt['preview'] . ' - ' . strip_tags($context['preview_subject']); } elseif (empty($topic)) { $context['page_title'] = $txt['start_new_topic']; } else { $context['page_title'] = $txt['post_reply']; } // Build the link tree. if (empty($topic)) { $context['linktree'][] = array('name' => '<em>' . $txt['start_new_topic'] . '</em>'); } else { $context['linktree'][] = array('url' => $scripturl . '?topic=' . $topic . '.' . $_REQUEST['start'], 'name' => $form_subject, 'extra_before' => '<span><strong class="nav">' . $context['page_title'] . ' ( </strong></span>', 'extra_after' => '<span><strong class="nav"> )</strong></span>'); } // Give wireless a linktree url to the post screen, so that they can switch to full version. if (WIRELESS) { $context['linktree'][count($context['linktree']) - 1]['url'] = $scripturl . '?action=post;' . (!empty($topic) ? 'topic=' . $topic : 'board=' . $board) . '.' . $_REQUEST['start'] . (isset($_REQUEST['msg']) ? ';msg=' . (int) $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id'] : ''); } $context['subject'] = addcslashes($form_subject, '"'); $context['message'] = str_replace(array('"', '<', '>', ' '), array('"', '<', '>', ' '), $form_message); // Are post drafts enabled? $context['drafts_save'] = !empty($modSettings['drafts_enabled']) && !empty($modSettings['drafts_post_enabled']) && allowedTo('post_draft'); $context['drafts_autosave'] = !empty($context['drafts_save']) && !empty($modSettings['drafts_autosave_enabled']) && allowedTo('post_autosave_draft'); // Build a list of drafts that they can load in to the editor if (!empty($context['drafts_save'])) { require_once $sourcedir . '/Drafts.php'; ShowDrafts($user_info['id'], $topic); } // Needed for the editor and message icons. require_once $sourcedir . '/Subs-Editor.php'; // Now create the editor. $editorOptions = array('id' => 'message', 'value' => $context['message'], 'labels' => array('post_button' => $context['submit_label']), 'height' => '275px', 'width' => '100%', 'preview_type' => 2); create_control_richedit($editorOptions); // Store the ID. $context['post_box_name'] = $editorOptions['id']; $context['attached'] = ''; $context['make_poll'] = isset($_REQUEST['poll']); // Message icons - customized icons are off? $context['icons'] = getMessageIcons($board); if (!empty($context['icons'])) { $context['icons'][count($context['icons']) - 1]['is_last'] = true; } // Are we starting a poll? if set the poll icon as selected if its available if (isset($_REQUEST['poll'])) { foreach ($context['icons'] as $icons) { if (isset($icons['value']) && $icons['value'] == 'poll') { // if found we are done $context['icon'] = 'poll'; break; } } } $context['icon_url'] = ''; for ($i = 0, $n = count($context['icons']); $i < $n; $i++) { $context['icons'][$i]['selected'] = $context['icon'] == $context['icons'][$i]['value']; if ($context['icons'][$i]['selected']) { $context['icon_url'] = $context['icons'][$i]['url']; } } if (empty($context['icon_url'])) { $context['icon_url'] = $settings[file_exists($settings['theme_dir'] . '/images/post/' . $context['icon'] . '.png') ? 'images_url' : 'default_images_url'] . '/post/' . $context['icon'] . '.png'; array_unshift($context['icons'], array('value' => $context['icon'], 'name' => $txt['current_icon'], 'url' => $context['icon_url'], 'is_last' => empty($context['icons']), 'selected' => true)); } if (!empty($topic) && !empty($modSettings['topicSummaryPosts'])) { getTopic(); } // If the user can post attachments prepare the warning labels. if ($context['can_post_attachment']) { // If they've unchecked an attachment, they may still want to attach that many more files, but don't allow more than num_allowed_attachments. $context['num_allowed_attachments'] = empty($modSettings['attachmentNumPerPostLimit']) ? 50 : min($modSettings['attachmentNumPerPostLimit'] - count($context['current_attachments']), $modSettings['attachmentNumPerPostLimit']); $context['can_post_attachment_unapproved'] = allowedTo('post_attachment'); $context['attachment_restrictions'] = array(); $context['allowed_extensions'] = strtr(strtolower($modSettings['attachmentExtensions']), array(',' => ', ')); $attachmentRestrictionTypes = array('attachmentNumPerPostLimit', 'attachmentPostLimit', 'attachmentSizeLimit'); foreach ($attachmentRestrictionTypes as $type) { if (!empty($modSettings[$type])) { $context['attachment_restrictions'][] = sprintf($txt['attach_restrict_' . $type], comma_format($modSettings[$type], 0)); // Show some numbers. If they exist. if ($type == 'attachmentNumPerPostLimit' && $context['attachments']['quantity'] > 0) { $context['attachment_restrictions'][] = sprintf($txt['attach_remaining'], $modSettings['attachmentNumPerPostLimit'] - $context['attachments']['quantity']); } elseif ($type == 'attachmentPostLimit' && $context['attachments']['total_size'] > 0) { $context['attachment_restrictions'][] = sprintf($txt['attach_available'], comma_format(round(max($modSettings['attachmentPostLimit'] - $context['attachments']['total_size'] / 1028, 0)), 0)); } } } } $context['back_to_topic'] = isset($_REQUEST['goback']) || isset($_REQUEST['msg']) && !isset($_REQUEST['subject']); $context['show_additional_options'] = !empty($_POST['additional_options']) || isset($_SESSION['temp_attachments']['post']) || isset($_GET['additionalOptions']); $context['is_new_topic'] = empty($topic); $context['is_new_post'] = !isset($_REQUEST['msg']); $context['is_first_post'] = $context['is_new_topic'] || isset($_REQUEST['msg']) && $_REQUEST['msg'] == $id_first_msg; // WYSIWYG only works if BBC is enabled $modSettings['disable_wysiwyg'] = !empty($modSettings['disable_wysiwyg']) || empty($modSettings['enableBBC']); // Register this form in the session variables. checkSubmitOnce('register'); // Finally, load the template. if (WIRELESS && WIRELESS_PROTOCOL != 'wap') { $context['sub_template'] = WIRELESS_PROTOCOL . '_post'; } elseif (!isset($_REQUEST['xml'])) { loadTemplate('Post'); } }
/** * This function allows to move a topic, making sure to ask the moderator * to give reason for topic move. * It must be called with a topic specified. (that is, global $topic must * be set... @todo fix this thing.) * If the member is the topic starter requires the move_own permission, * otherwise the move_any permission. * Accessed via ?action=movetopic. * * @uses the MoveTopic template, main sub-template. */ public function action_movetopic() { global $txt, $topic, $user_info, $context, $language, $scripturl, $modSettings; if (empty($topic)) { fatal_lang_error('no_access', false); } // Retrieve the basic topic information for whats being moved require_once SUBSDIR . '/Topic.subs.php'; $topic_info = getTopicInfo($topic, 'message'); if (empty($topic_info)) { fatal_lang_error('topic_gone', false); } $context['is_approved'] = $topic_info['approved']; $context['subject'] = $topic_info['subject']; // Can they see it - if not approved? if ($modSettings['postmod_active'] && !$context['is_approved']) { isAllowedTo('approve_posts'); } // Are they allowed to actually move any topics or even their own? if (!allowedTo('move_any') && ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('move_own'))) { fatal_lang_error('cannot_move_any', false); } loadTemplate('MoveTopic'); // Get a list of boards this moderator can move to. require_once SUBSDIR . '/Boards.subs.php'; $context += getBoardList(array('not_redirection' => true)); // No boards? if (empty($context['categories']) || $context['num_boards'] == 1) { fatal_lang_error('moveto_noboards', false); } // Already used the function, let's set the selected board back to the last $last_moved_to = isset($_SESSION['move_to_topic']['move_to']) && $_SESSION['move_to_topic']['move_to'] != $context['current_board'] ? (int) $_SESSION['move_to_topic']['move_to'] : 0; if (!empty($last_moved_to)) { foreach ($context['categories'] as $id => $values) { if (isset($values['boards'][$last_moved_to])) { $context['categories'][$id]['boards'][$last_moved_to]['selected'] = true; break; } } } // Set up for the template $context['redirect_topic'] = isset($_SESSION['move_to_topic']['redirect_topic']) ? (int) $_SESSION['move_to_topic']['redirect_topic'] : 0; $context['redirect_expires'] = isset($_SESSION['move_to_topic']['redirect_expires']) ? (int) $_SESSION['move_to_topic']['redirect_expires'] : 0; $context['page_title'] = $txt['move_topic']; $context['sub_template'] = 'move_topic'; // Breadcrumbs $context['linktree'][] = array('url' => $scripturl . '?topic=' . $topic . '.0', 'name' => $context['subject']); $context['linktree'][] = array('url' => '#', 'name' => $txt['move_topic']); $context['back_to_topic'] = isset($_REQUEST['goback']); // Ugly ! if ($user_info['language'] != $language) { loadLanguage('index', $language); $temp = $txt['movetopic_default']; loadLanguage('index'); $txt['movetopic_default'] = $temp; } // We will need this moveTopicConcurrence(); // Register this form and get a sequence number in $context. checkSubmitOnce('register'); }
/** * Ask the user what they want to search for. * * What it does: * - shows the screen to search forum posts (action=search), * - uses the main sub template of the Search template. * - uses the Search language file. * - requires the search_posts permission. * - decodes and loads search parameters given in the URL (if any). * - the form redirects to index.php?action=search;sa=results. * * @uses Search language file and Errors language when needed * @uses Search template, searchform sub template */ public function action_search() { global $txt, $scripturl, $modSettings, $user_info, $context; // Is the load average too high to allow searching just now? if (!empty($modSettings['loadavg_search']) && $modSettings['current_load'] >= $modSettings['loadavg_search']) { fatal_lang_error('loadavg_search_disabled', false); } loadLanguage('Search'); // Don't load this in XML mode. if (!isset($_REQUEST['xml'])) { loadTemplate('Search'); $context['sub_template'] = 'searchform'; loadJavascriptFile('suggest.js', array('defer' => true)); } // Check the user's permissions. isAllowedTo('search_posts'); // Link tree.... $context['linktree'][] = array('url' => $scripturl . '?action=search', 'name' => $txt['search']); // This is hard coded maximum string length. $context['search_string_limit'] = 100; $context['require_verification'] = $user_info['is_guest'] && !empty($modSettings['search_enable_captcha']) && empty($_SESSION['ss_vv_passed']); if ($context['require_verification']) { require_once SUBSDIR . '/VerificationControls.class.php'; $verificationOptions = array('id' => 'search'); $context['require_verification'] = create_control_verification($verificationOptions); $context['visual_verification_id'] = $verificationOptions['id']; } // If you got back from search;sa=results by using the linktree, you get your original search parameters back. 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); $context['search_params'] = array(); foreach ($temp_params as $i => $data) { @(list($k, $v) = explode('|\'|', $data)); $context['search_params'][$k] = $v; } if (isset($context['search_params']['brd'])) { $context['search_params']['brd'] = $context['search_params']['brd'] == '' ? array() : explode(',', $context['search_params']['brd']); } } if (isset($_REQUEST['search'])) { $context['search_params']['search'] = un_htmlspecialchars($_REQUEST['search']); } if (isset($context['search_params']['search'])) { $context['search_params']['search'] = Util::htmlspecialchars($context['search_params']['search']); } if (isset($context['search_params']['userspec'])) { $context['search_params']['userspec'] = htmlspecialchars($context['search_params']['userspec'], ENT_COMPAT, 'UTF-8'); } if (!empty($context['search_params']['searchtype'])) { $context['search_params']['searchtype'] = 2; } if (!empty($context['search_params']['minage'])) { $context['search_params']['minage'] = (int) $context['search_params']['minage']; } if (!empty($context['search_params']['maxage'])) { $context['search_params']['maxage'] = (int) $context['search_params']['maxage']; } $context['search_params']['show_complete'] = !empty($context['search_params']['show_complete']); $context['search_params']['subject_only'] = !empty($context['search_params']['subject_only']); // Load the error text strings if there were errors in the search. if (!empty($context['search_errors'])) { loadLanguage('Errors'); $context['search_errors']['messages'] = array(); foreach ($context['search_errors'] as $search_error => $dummy) { if ($search_error === 'messages') { continue; } if ($search_error == 'string_too_long') { $txt['error_string_too_long'] = sprintf($txt['error_string_too_long'], $context['search_string_limit']); } $context['search_errors']['messages'][] = $txt['error_' . $search_error]; } } require_once SUBSDIR . '/Boards.subs.php'; $context += getBoardList(array('not_redirection' => true)); $context['boards_in_category'] = array(); foreach ($context['categories'] as $cat => &$category) { $context['boards_in_category'][$cat] = count($category['boards']); $category['child_ids'] = array_keys($category['boards']); foreach ($category['boards'] as &$board) { $board['selected'] = empty($context['search_params']['brd']) && (empty($modSettings['recycle_enable']) || $board['id'] != $modSettings['recycle_board']) && !in_array($board['id'], $user_info['ignoreboards']) || !empty($context['search_params']['brd']) && in_array($board['id'], $context['search_params']['brd']); } } if (!empty($_REQUEST['topic'])) { $context['search_params']['topic'] = (int) $_REQUEST['topic']; $context['search_params']['show_complete'] = true; } if (!empty($context['search_params']['topic'])) { $context['search_params']['topic'] = (int) $context['search_params']['topic']; $context['search_topic'] = array('id' => $context['search_params']['topic'], 'href' => $scripturl . '?topic=' . $context['search_params']['topic'] . '.0'); require_once SUBSDIR . '/Topic.subs.php'; $context['search_topic']['subject'] = getSubject($context['search_params']['topic']); $context['search_topic']['link'] = '<a href="' . $context['search_topic']['href'] . '">' . $context['search_topic']['subject'] . '</a>'; } $context['page_title'] = $txt['set_parameters']; $context['search_params'] = $this->_fill_default_search_params($context['search_params']); // Start guest off collapsed if ($context['user']['is_guest'] && !isset($context['minmax_preferences']['asearch'])) { $context['minmax_preferences']['asearch'] = 1; } call_integration_hook('integrate_search'); }
/** * This function determines the actions of the members passed in urls. * * Adding actions to the Who's Online list: * Adding actions to this list is actually relatively easy... * - for actions anyone should be able to see, just add a string named whoall_ACTION. * (where ACTION is the action used in index.php.) * - for actions that have a subaction which should be represented differently, use whoall_ACTION_SUBACTION. * - for actions that include a topic, and should be restricted, use whotopic_ACTION. * - for actions that use a message, by msg or quote, use whopost_ACTION. * - for administrator-only actions, use whoadmin_ACTION. * - for actions that should be viewable only with certain permissions, use whoallow_ACTION and * add a list of possible permissions to the $allowedActions array, using ACTION as the key. * * @param mixed[]|string $urls a single url (string) or an array of arrays, each inner array being (serialized request data, id_member) * @param string|false $preferred_prefix = false * @return mixed[]|string an array of descriptions if you passed an array, otherwise the string describing their current location. */ function determineActions($urls, $preferred_prefix = false) { global $txt, $user_info, $modSettings, $scripturl; $db = database(); if (!allowedTo('who_view')) { return array(); } loadLanguage('Who'); // Actions that require a specific permission level. $allowedActions = array('admin' => array('moderate_forum', 'manage_membergroups', 'manage_bans', 'admin_forum', 'manage_permissions', 'send_mail', 'manage_attachments', 'manage_smileys', 'manage_boards', 'edit_news'), 'ban' => array('manage_bans'), 'boardrecount' => array('admin_forum'), 'calendar' => array('calendar_view'), 'editnews' => array('edit_news'), 'mailing' => array('send_mail'), 'maintain' => array('admin_forum'), 'manageattachments' => array('manage_attachments'), 'manageboards' => array('manage_boards'), 'memberlist' => array('view_mlist'), 'moderate' => array('access_mod_center', 'moderate_forum', 'manage_membergroups'), 'optimizetables' => array('admin_forum'), 'repairboards' => array('admin_forum'), 'search' => array('search_posts'), 'setcensor' => array('moderate_forum'), 'setreserve' => array('moderate_forum'), 'stats' => array('view_stats'), 'viewErrorLog' => array('admin_forum'), 'viewmembers' => array('moderate_forum')); // Provide integration a way to add to the allowed action array call_integration_hook('integrate_whos_online_allowed', array(&$allowedActions)); if (!is_array($urls)) { $url_list = array(array($urls, $user_info['id'])); } else { $url_list = $urls; } // These are done to query these in large chunks. (instead of one by one.) $topic_ids = array(); $profile_ids = array(); $board_ids = array(); $data = array(); foreach ($url_list as $k => $url) { // Get the request parameters.. $actions = @unserialize($url[0]); if ($actions === false) { continue; } // If it's the admin or moderation center, and there is an area set, use that instead. if (isset($actions['action']) && ($actions['action'] == 'admin' || $actions['action'] == 'moderate') && isset($actions['area'])) { $actions['action'] = $actions['area']; } // Check if there was no action or the action is display. if (!isset($actions['action']) || $actions['action'] == 'display') { // It's a topic! Must be! if (isset($actions['topic'])) { // Assume they can't view it, and queue it up for later. $data[$k] = $txt['who_hidden']; $topic_ids[(int) $actions['topic']][$k] = $txt['who_topic']; } elseif (isset($actions['board'])) { // Hide first, show later. $data[$k] = $txt['who_hidden']; $board_ids[$actions['board']][$k] = $txt['who_board']; } else { $data[$k] = replaceBasicActionUrl($txt['who_index']); } } elseif ($actions['action'] == '') { $data[$k] = replaceBasicActionUrl($txt['who_index']); } else { // Viewing/editing a profile. if ($actions['action'] == 'profile') { // Whose? Their own? if (empty($actions['u'])) { require_once SUBSDIR . '/Profile.subs.php'; $memID = currentMemberID(); if ($memID == $user_info['id']) { $actions['u'] = $url[1]; } else { $actions['u'] = $memID; } } $data[$k] = $txt['who_hidden']; $profile_ids[(int) $actions['u']][$k] = $actions['action'] == 'profile' ? $txt['who_viewprofile'] : $txt['who_profile']; } elseif (($actions['action'] == 'post' || $actions['action'] == 'post2' || $actions['action'] == 'topicbyemail') && empty($actions['topic']) && isset($actions['board'])) { $data[$k] = $txt['who_hidden']; if ($actions['action'] == 'topicbyemail') { $board_ids[(int) $actions['board']][$k] = $txt['who_topicbyemail']; } else { $board_ids[(int) $actions['board']][$k] = isset($actions['poll']) ? $txt['who_poll'] : $txt['who_post']; } } elseif (isset($actions['sa']) && isset($txt['whoall_' . $actions['action'] . '_' . $actions['sa']])) { $data[$k] = $preferred_prefix && isset($txt[$preferred_prefix . $actions['action'] . '_' . $actions['sa']]) ? $txt[$preferred_prefix . $actions['action'] . '_' . $actions['sa']] : $txt['whoall_' . $actions['action'] . '_' . $actions['sa']]; } elseif (isset($txt['whoall_' . $actions['action']])) { $data[$k] = $preferred_prefix && isset($txt[$preferred_prefix . $actions['action']]) ? $txt[$preferred_prefix . $actions['action']] : replaceBasicActionUrl($txt['whoall_' . $actions['action']]); } elseif (isset($txt['whotopic_' . $actions['action']])) { // Find out what topic they are accessing. $topic = (int) (isset($actions['topic']) ? $actions['topic'] : (isset($actions['from']) ? $actions['from'] : 0)); $data[$k] = $txt['who_hidden']; $topic_ids[$topic][$k] = $txt['whotopic_' . $actions['action']]; } elseif (isset($actions['sa']) && isset($txt['whotopic_' . $actions['action'] . '_' . $actions['sa']])) { // Find out what topic they are accessing. $topic = (int) (isset($actions['topic']) ? $actions['topic'] : (isset($actions['from']) ? $actions['from'] : 0)); $data[$k] = $txt['who_hidden']; $topic_ids[$topic][$k] = $txt['whotopic_' . $actions['action'] . '_' . $actions['sa']]; } elseif (isset($txt['whopost_' . $actions['action']])) { // Find out what message they are accessing. $msgid = (int) (isset($actions['msg']) ? $actions['msg'] : (isset($actions['quote']) ? $actions['quote'] : 0)); $result = $db->query('', ' SELECT m.id_topic, m.subject FROM {db_prefix}messages AS m INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board) INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic' . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved}' : '') . ') WHERE m.id_msg = {int:id_msg} AND {query_see_board}' . ($modSettings['postmod_active'] ? ' AND m.approved = {int:is_approved}' : '') . ' LIMIT 1', array('is_approved' => 1, 'id_msg' => $msgid)); list($id_topic, $subject) = $db->fetch_row($result); $data[$k] = sprintf($txt['whopost_' . $actions['action']], $scripturl . '?topic=' . $id_topic . '.0', $subject); $db->free_result($result); if (empty($id_topic)) { $data[$k] = $txt['who_hidden']; } } elseif (allowedTo('moderate_forum') && isset($txt['whoadmin_' . $actions['action']])) { $data[$k] = $txt['whoadmin_' . $actions['action']]; } elseif (isset($allowedActions[$actions['action']])) { if (allowedTo($allowedActions[$actions['action']])) { if (isset($actions['sa']) && isset($txt['whoallow_' . $actions['action'] . '_' . $actions['sa']])) { $data[$k] = replaceBasicActionUrl($txt['whoallow_' . $actions['action'] . '_' . $actions['sa']]); } else { $data[$k] = replaceBasicActionUrl($txt['whoallow_' . $actions['action']]); } } elseif (in_array('moderate_forum', $allowedActions[$actions['action']])) { $data[$k] = $txt['who_moderate']; } elseif (in_array('admin_forum', $allowedActions[$actions['action']])) { $data[$k] = $txt['who_admin']; } else { $data[$k] = $txt['who_hidden']; } } elseif (!empty($actions['action'])) { $data[$k] = sprintf($txt['who_generic'], $actions['action']); } else { $data[$k] = $txt['who_unknown']; } } // Maybe the action is integrated into another system? if (count($integrate_actions = call_integration_hook('integrate_whos_online', array($actions))) > 0) { // Try each integraion hook with this url and see if they can fill in the details foreach ($integrate_actions as $integrate_action) { if (!empty($integrate_action)) { // Found it, all done then $data[$k] = $integrate_action; break; } } } } // Load topic names. if (!empty($topic_ids)) { require_once SUBSDIR . '/Topic.subs.php'; $topics_data = topicsList(array_keys($topic_ids)); foreach ($topics_data as $topic) { // Show the topic's subject for each of the members looking at this... foreach ($topic_ids[$topic['id_topic']] as $k => $session_text) { $data[$k] = sprintf($session_text, $scripturl . '?topic=' . $topic['id_topic'] . '.0', $topic['subject']); } } } // Load board names. if (!empty($board_ids)) { require_once SUBSDIR . '/Boards.subs.php'; $boards_list = getBoardList(array('included_boards' => array_keys($board_ids)), true); foreach ($boards_list as $board) { // Put the board name into the string for each member... foreach ($board_ids[$board['id_board']] as $k => $session_text) { $data[$k] = sprintf($session_text, $scripturl . '?board=' . $board['id_board'] . '.0', $board['board_name']); } } } // Load member names for the profile. if (!empty($profile_ids) && (allowedTo('profile_view_any') || allowedTo('profile_view_own'))) { require_once SUBSDIR . '/Members.subs.php'; $result = getBasicMemberData(array_keys($profile_ids)); foreach ($result as $row) { // If they aren't allowed to view this person's profile, skip it. if (!allowedTo('profile_view_any') && $user_info['id'] != $row['id_member']) { continue; } // Set their action on each - session/text to sprintf. foreach ($profile_ids[$row['id_member']] as $k => $session_text) { $data[$k] = sprintf($session_text, $scripturl . '?action=profile;u=' . $row['id_member'], $row['real_name']); } } } if (!is_array($urls)) { return isset($data[0]) ? $data[0] : false; } else { return $data; } }
/** * Set merge options and do the actual merge of two or more topics. * * the merge options screen: * * shows topics to be merged and allows to set some merge options. * * is accessed by ?action=mergetopics;sa=options.and can also internally be called by action_quickmod(). * * uses 'merge_extra_options' sub template of the MergeTopics template. * * the actual merge: * * is accessed with ?action=mergetopics;sa=execute. * * updates the statistics to reflect the merge. * * logs the action in the moderation log. * * sends a notification is sent to all users monitoring this topic. * * redirects to ?action=mergetopics;sa=done. * * @param int[] $topics = array() of topic ids */ public function action_mergeExecute($topics = array()) { global $user_info, $txt, $context, $scripturl, $modSettings; $db = database(); // Check the session. checkSession('request'); require_once SUBSDIR . '/Topic.subs.php'; require_once SUBSDIR . '/Post.subs.php'; // Handle URLs from action_mergeIndex. if (!empty($_GET['from']) && !empty($_GET['to'])) { $topics = array((int) $_GET['from'], (int) $_GET['to']); } // If we came from a form, the topic IDs came by post. if (!empty($_POST['topics']) && is_array($_POST['topics'])) { $topics = $_POST['topics']; } // There's nothing to merge with just one topic... if (empty($topics) || !is_array($topics) || count($topics) == 1) { fatal_lang_error('merge_need_more_topics'); } // Make sure every topic is numeric, or some nasty things could be done with the DB. foreach ($topics as $id => $topic) { $topics[$id] = (int) $topic; } // Joy of all joys, make sure they're not pi**ing about with unapproved topics they can't see :P if ($modSettings['postmod_active']) { $can_approve_boards = !empty($user_info['mod_cache']['ap']) ? $user_info['mod_cache']['ap'] : boardsAllowedTo('approve_posts'); } // Get info about the topics and polls that will be merged. $request = $db->query('', ' SELECT t.id_topic, t.id_board, b.id_cat, t.id_poll, t.num_views, t.is_sticky, t.approved, t.num_replies, t.unapproved_posts, m1.subject, m1.poster_time AS time_started, IFNULL(mem1.id_member, 0) AS id_member_started, IFNULL(mem1.real_name, m1.poster_name) AS name_started, m2.poster_time AS time_updated, IFNULL(mem2.id_member, 0) AS id_member_updated, IFNULL(mem2.real_name, m2.poster_name) AS name_updated FROM {db_prefix}topics AS t INNER JOIN {db_prefix}messages AS m1 ON (m1.id_msg = t.id_first_msg) INNER JOIN {db_prefix}messages AS m2 ON (m2.id_msg = t.id_last_msg) LEFT JOIN {db_prefix}members AS mem1 ON (mem1.id_member = m1.id_member) LEFT JOIN {db_prefix}members AS mem2 ON (mem2.id_member = m2.id_member) LEFT JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) WHERE t.id_topic IN ({array_int:topic_list}) ORDER BY t.id_first_msg LIMIT ' . count($topics), array('topic_list' => $topics)); if ($db->num_rows($request) < 2) { fatal_lang_error('no_topic_id'); } $num_views = 0; $is_sticky = 0; $boardTotals = array(); $topic_data = array(); $boards = array(); $polls = array(); $firstTopic = 0; $firstBoard = 0; while ($row = $db->fetch_assoc($request)) { // Make a note for the board counts... if (!isset($boardTotals[$row['id_board']])) { $boardTotals[$row['id_board']] = array('num_posts' => 0, 'num_topics' => 0, 'unapproved_posts' => 0, 'unapproved_topics' => 0); } // We can't see unapproved topics here? if ($modSettings['postmod_active'] && !$row['approved'] && $can_approve_boards != array(0) && in_array($row['id_board'], $can_approve_boards)) { continue; } elseif (!$row['approved']) { $boardTotals[$row['id_board']]['unapproved_topics']++; } else { $boardTotals[$row['id_board']]['num_topics']++; } $boardTotals[$row['id_board']]['unapproved_posts'] += $row['unapproved_posts']; $boardTotals[$row['id_board']]['num_posts'] += $row['num_replies'] + ($row['approved'] ? 1 : 0); $topic_data[$row['id_topic']] = array('id' => $row['id_topic'], 'board' => $row['id_board'], 'poll' => $row['id_poll'], 'num_views' => $row['num_views'], 'subject' => $row['subject'], 'started' => array('time' => standardTime($row['time_started']), 'html_time' => htmlTime($row['time_started']), 'timestamp' => forum_time(true, $row['time_started']), 'href' => empty($row['id_member_started']) ? '' : $scripturl . '?action=profile;u=' . $row['id_member_started'], 'link' => empty($row['id_member_started']) ? $row['name_started'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member_started'] . '">' . $row['name_started'] . '</a>'), 'updated' => array('time' => standardTime($row['time_updated']), 'html_time' => htmlTime($row['time_updated']), 'timestamp' => forum_time(true, $row['time_updated']), 'href' => empty($row['id_member_updated']) ? '' : $scripturl . '?action=profile;u=' . $row['id_member_updated'], 'link' => empty($row['id_member_updated']) ? $row['name_updated'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member_updated'] . '">' . $row['name_updated'] . '</a>')); $num_views += $row['num_views']; $boards[] = $row['id_board']; // If there's no poll, id_poll == 0... if ($row['id_poll'] > 0) { $polls[] = $row['id_poll']; } // Store the id_topic with the lowest id_first_msg. if (empty($firstTopic)) { $firstTopic = $row['id_topic']; $firstBoard = $row['id_board']; } $is_sticky = max($is_sticky, $row['is_sticky']); } $db->free_result($request); // If we didn't get any topics then they've been messing with unapproved stuff. if (empty($topic_data)) { fatal_lang_error('no_topic_id'); } $boards = array_values(array_unique($boards)); // The parameters of action_mergeExecute were set, so this must've been an internal call. if (!empty($topics)) { isAllowedTo('merge_any', $boards); loadTemplate('MergeTopics'); } // Get the boards a user is allowed to merge in. $merge_boards = boardsAllowedTo('merge_any'); if (empty($merge_boards)) { fatal_lang_error('cannot_merge_any', 'user'); } require_once SUBSDIR . '/Boards.subs.php'; // Make sure they can see all boards.... $query_boards = array('boards' => $boards); if (!in_array(0, $merge_boards)) { $query_boards['boards'] = array_merge($query_boards['boards'], $merge_boards); } // Saved in a variable to (potentially) save a query later $boards_info = fetchBoardsInfo($query_boards); $boardListOptions = array('not_redirection' => true, 'selected_board' => $firstBoard); if (!in_array(0, $merge_boards)) { $boardListOptions['included_boards'] = $merge_boards; } $context += getBoardList($boardListOptions); // This is removed to avoid the board not being selectable. $context['current_board'] = null; // This happens when a member is moderator of a board he cannot see foreach ($boards as $board) { if (!isset($boards_info[$board])) { fatal_lang_error('no_board'); } } if (empty($_REQUEST['sa']) || $_REQUEST['sa'] == 'options') { if (count($polls) > 1) { $request = $db->query('', ' SELECT t.id_topic, t.id_poll, m.subject, p.question FROM {db_prefix}polls AS p INNER JOIN {db_prefix}topics AS t ON (t.id_poll = p.id_poll) INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg) WHERE p.id_poll IN ({array_int:polls}) LIMIT ' . count($polls), array('polls' => $polls)); while ($row = $db->fetch_assoc($request)) { $context['polls'][] = array('id' => $row['id_poll'], 'topic' => array('id' => $row['id_topic'], 'subject' => $row['subject']), 'question' => $row['question'], 'selected' => $row['id_topic'] == $firstTopic); } $db->free_result($request); } if (count($boards) > 1) { // @deprecated since 1.0.3 - Kept in the remote case someone created a theme changing MergeTopics.template.php foreach ($boards_info as $row) { $context['boards'][] = array('id' => $row['id_board'], 'name' => $row['name'], 'selected' => $row['id_board'] == $topic_data[$firstTopic]['board']); } } $context['topics'] = $topic_data; foreach ($topic_data as $id => $topic) { $context['topics'][$id]['selected'] = $topic['id'] == $firstTopic; } $context['page_title'] = $txt['merge']; $context['sub_template'] = 'merge_extra_options'; return; } // Determine target board. $target_board = count($boards) > 1 ? (int) $_REQUEST['board'] : $boards[0]; if (!in_array($target_board, array_keys($boards_info))) { fatal_lang_error('no_board'); } // Determine which poll will survive and which polls won't. $target_poll = count($polls) > 1 ? (int) $_POST['poll'] : (count($polls) == 1 ? $polls[0] : 0); if ($target_poll > 0 && !in_array($target_poll, $polls)) { fatal_lang_error('no_access', false); } $deleted_polls = empty($target_poll) ? $polls : array_diff($polls, array($target_poll)); // Determine the subject of the newly merged topic - was a custom subject specified? if (empty($_POST['subject']) && isset($_POST['custom_subject']) && $_POST['custom_subject'] != '') { $target_subject = strtr(Util::htmltrim(Util::htmlspecialchars($_POST['custom_subject'])), array("\r" => '', "\n" => '', "\t" => '')); // Keep checking the length. if (Util::strlen($target_subject) > 100) { $target_subject = Util::substr($target_subject, 0, 100); } // Nothing left - odd but pick the first topics subject. if ($target_subject == '') { $target_subject = $topic_data[$firstTopic]['subject']; } } elseif (!empty($topic_data[(int) $_POST['subject']]['subject'])) { $target_subject = $topic_data[(int) $_POST['subject']]['subject']; } else { $target_subject = $topic_data[$firstTopic]['subject']; } // Get the first and last message and the number of messages.... $request = $db->query('', ' SELECT approved, MIN(id_msg) AS first_msg, MAX(id_msg) AS last_msg, COUNT(*) AS message_count FROM {db_prefix}messages WHERE id_topic IN ({array_int:topics}) GROUP BY approved ORDER BY approved DESC', array('topics' => $topics)); $topic_approved = 1; $first_msg = 0; while ($row = $db->fetch_assoc($request)) { // If this is approved, or is fully unapproved. if ($row['approved'] || !isset($first_msg)) { $first_msg = $row['first_msg']; $last_msg = $row['last_msg']; if ($row['approved']) { $num_replies = $row['message_count'] - 1; $num_unapproved = 0; } else { $topic_approved = 0; $num_replies = 0; $num_unapproved = $row['message_count']; } } else { // If this has a lower first_msg then the first post is not approved and hence the number of replies was wrong! if ($first_msg > $row['first_msg']) { $first_msg = $row['first_msg']; $num_replies++; $topic_approved = 0; } $num_unapproved = $row['message_count']; } } $db->free_result($request); // Ensure we have a board stat for the target board. if (!isset($boardTotals[$target_board])) { $boardTotals[$target_board] = array('num_posts' => 0, 'num_topics' => 0, 'unapproved_posts' => 0, 'unapproved_topics' => 0); } // Fix the topic count stuff depending on what the new one counts as. if ($topic_approved) { $boardTotals[$target_board]['num_topics']--; } else { $boardTotals[$target_board]['unapproved_topics']--; } $boardTotals[$target_board]['unapproved_posts'] -= $num_unapproved; $boardTotals[$target_board]['num_posts'] -= $topic_approved ? $num_replies + 1 : $num_replies; // Get the member ID of the first and last message. $request = $db->query('', ' SELECT id_member FROM {db_prefix}messages WHERE id_msg IN ({int:first_msg}, {int:last_msg}) ORDER BY id_msg LIMIT 2', array('first_msg' => $first_msg, 'last_msg' => $last_msg)); list($member_started) = $db->fetch_row($request); list($member_updated) = $db->fetch_row($request); // First and last message are the same, so only row was returned. if ($member_updated === null) { $member_updated = $member_started; } $db->free_result($request); // Obtain all the message ids we are going to affect. $affected_msgs = messagesInTopics($topics); // Assign the first topic ID to be the merged topic. $id_topic = min($topics); // Grab the response prefix (like 'Re: ') in the default forum language. $context['response_prefix'] = response_prefix(); $enforce_subject = isset($_POST['enforce_subject']) ? Util::htmlspecialchars(trim($_POST['enforce_subject'])) : ''; // Merge topic notifications. $notifications = isset($_POST['notifications']) && is_array($_POST['notifications']) ? array_intersect($topics, $_POST['notifications']) : array(); fixMergedTopics($first_msg, $topics, $id_topic, $target_board, $target_subject, $enforce_subject, $notifications); // Asssign the properties of the newly merged topic. $db->query('', ' UPDATE {db_prefix}topics SET id_board = {int:id_board}, id_member_started = {int:id_member_started}, id_member_updated = {int:id_member_updated}, id_first_msg = {int:id_first_msg}, id_last_msg = {int:id_last_msg}, id_poll = {int:id_poll}, num_replies = {int:num_replies}, unapproved_posts = {int:unapproved_posts}, num_views = {int:num_views}, is_sticky = {int:is_sticky}, approved = {int:approved} WHERE id_topic = {int:id_topic}', array('id_board' => $target_board, 'is_sticky' => $is_sticky, 'approved' => $topic_approved, 'id_topic' => $id_topic, 'id_member_started' => $member_started, 'id_member_updated' => $member_updated, 'id_first_msg' => $first_msg, 'id_last_msg' => $last_msg, 'id_poll' => $target_poll, 'num_replies' => $num_replies, 'unapproved_posts' => $num_unapproved, 'num_views' => $num_views)); // Get rid of the redundant polls. if (!empty($deleted_polls)) { require_once SUBSDIR . '/Poll.subs.php'; removePoll($deleted_polls); } // Cycle through each board... foreach ($boardTotals as $id_board => $stats) { decrementBoard($id_board, $stats); } // Determine the board the final topic resides in $topic_info = getTopicInfo($id_topic); $id_board = $topic_info['id_board']; // Update all the statistics. updateStats('topic'); updateStats('subject', $id_topic, $target_subject); updateLastMessages($boards); logAction('merge', array('topic' => $id_topic, 'board' => $id_board)); // Notify people that these topics have been merged? require_once SUBSDIR . '/Notification.subs.php'; sendNotifications($id_topic, 'merge'); // If there's a search index that needs updating, update it... require_once SUBSDIR . '/Search.subs.php'; $searchAPI = findSearchAPI(); if (is_callable(array($searchAPI, 'topicMerge'))) { $searchAPI->topicMerge($id_topic, $topics, $affected_msgs, empty($enforce_subject) ? null : array($context['response_prefix'], $target_subject)); } // Send them to the all done page. redirectexit('action=mergetopics;sa=done;to=' . $id_topic . ';targetboard=' . $target_board); }