/** * Change the way bad behavior ... well behaves */ public function action_bbSettings_display() { global $txt, $scripturl, $context, $modSettings, $boardurl; // Initialize the form $this->_initBBSettingsForm(); // Our callback templates are here loadTemplate('BadBehavior'); // Any errors to display? if ($context['invalid_badbehavior_httpbl_key']) { $context['settings_message'][] = $txt['badbehavior_httpbl_key_invalid']; $context['error_type'] = 'warning'; } // Have we blocked anything in the last 7 days? if (!empty($modSettings['badbehavior_enabled'])) { $context['settings_message'][] = bb2_insert_stats(true) . '<a href="' . $boardurl . '/index.php?action=admin;area=logs;sa=badbehaviorlog;desc" /> [' . $txt['badbehavior_details'] . ']</a>'; } // Current whitelist data $whitelist = array('badbehavior_ip_wl', 'badbehavior_useragent_wl', 'badbehavior_url_wl'); foreach ($whitelist as $list) { $context[$list] = array(); $context[$list . '_desc'] = array(); if (!empty($modSettings[$list])) { $context[$list] = unserialize($modSettings[$list]); } if (!empty($modSettings[$list . '_desc'])) { $context[$list . '_desc'] = unserialize($modSettings[$list . '_desc']); } } $config_vars = $this->_bbSettings->settings(); // Saving? if (isset($_GET['save'])) { checkSession(); // Make sure Bad Behavior defaults are set if nothing was specified $_POST['badbehavior_httpbl_threat'] = empty($_POST['badbehavior_httpbl_threat']) ? 25 : $_POST['badbehavior_httpbl_threat']; $_POST['badbehavior_httpbl_maxage'] = empty($_POST['badbehavior_httpbl_maxage']) ? 30 : $_POST['badbehavior_httpbl_maxage']; $_POST['badbehavior_reverse_proxy_header'] = empty($_POST['badbehavior_reverse_proxy_header']) ? 'X-Forwarded-For' : $_POST['badbehavior_reverse_proxy_header']; // Build up the whitelist options foreach ($whitelist as $list) { $this_list = array(); $this_desc = array(); if (isset($_POST[$list])) { // Clear blanks from the data field, only grab the comments that don't have blank data value $this_list = array_map('trim', array_filter($_POST[$list])); $this_desc = array_intersect_key($_POST[$list . '_desc'], $this_list); } updateSettings(array($list => serialize($this_list), $list . '_desc' => serialize($this_desc))); } Settings_Form::save_db($config_vars); redirectexit('action=admin;area=securitysettings;sa=badbehavior'); } $context['post_url'] = $scripturl . '?action=admin;area=securitysettings;save;sa=badbehavior'; // Javascript vars for the "add more xyz" buttons in the callback forms addJavascriptVar(array('sUrlParent' => '\'add_more_url_placeholder\'', 'oUrlOptionsdt' => '{name: \'badbehavior_url_wl_desc[]\', class: \'input_text\'}', 'oUrlOptionsdd' => '{name: \'badbehavior_url_wl[]\', class: \'input_text\'}', 'sUseragentParent' => '\'add_more_useragent_placeholder\'', 'oUseragentOptionsdt' => '{name: \'badbehavior_useragent_wl_desc[]\', class: \'input_text\'}', 'oUseragentOptionsdd' => '{name: \'badbehavior_useragent_wl[]\', class: \'input_text\'}', 'sIpParent' => '\'add_more_ip_placeholder\'', 'oIpOptionsdt' => '{name: \'badbehavior_ip_wl_desc[]\', class: \'input_text\'}', 'oIpOptionsdd' => '{name: \'badbehavior_ip_wl[]\', class: \'input_text\'}')); Settings_Form::prepare_db($config_vars); }
/** * Edit some profile fields? * * - Accessed with ?action=admin;area=featuresettings;sa=profileedit * * @uses sub template edit_profile_field */ public function action_profileedit() { global $txt, $scripturl, $context; require_once SUBSDIR . '/ManageFeatures.subs.php'; loadTemplate('ManageFeatures'); // Sort out the context! $context['fid'] = isset($_GET['fid']) ? (int) $_GET['fid'] : 0; $context[$context['admin_menu_name']]['current_subsection'] = 'profile'; $context['page_title'] = $context['fid'] ? $txt['custom_edit_title'] : $txt['custom_add_title']; $context['sub_template'] = 'edit_profile_field'; // any errors messages to show? if (isset($_GET['msg'])) { loadLanguage('Errors'); if (isset($txt['custom_option_' . $_GET['msg']])) { $context['custom_option__error'] = $txt['custom_option_' . $_GET['msg']]; } } // Load the profile language for section names. loadLanguage('Profile'); // Load up the profile field, if one was supplied if ($context['fid']) { $context['field'] = getProfileField($context['fid']); } // Setup the default values as needed. if (empty($context['field'])) { $context['field'] = array('name' => '', 'colname' => '???', 'desc' => '', 'profile_area' => 'forumprofile', 'reg' => false, 'display' => false, 'memberlist' => false, 'type' => 'text', 'max_length' => 255, 'rows' => 4, 'cols' => 30, 'bbc' => false, 'default_check' => false, 'default_select' => '', 'options' => array('', '', ''), 'active' => true, 'private' => false, 'can_search' => false, 'mask' => 'nohtml', 'regex' => '', 'enclose' => '', 'placement' => 0); } // All the javascript for this page... everything else is in admin.js addJavascriptVar(array('startOptID' => count($context['field']['options']))); addInlineJavascript('updateInputBoxes();', true); // Are we toggling which ones are active? if (isset($_POST['onoff'])) { checkSession(); validateToken('admin-scp'); // Enable and disable custom fields as required. $enabled = array(0); foreach ($_POST['cust'] as $id) { $enabled[] = (int) $id; } updateRenamedProfileStatus($enabled); } elseif (isset($_POST['save'])) { checkSession(); validateToken('admin-ecp'); // Everyone needs a name - even the (bracket) unknown... if (trim($_POST['field_name']) == '') { redirectexit($scripturl . '?action=admin;area=featuresettings;sa=profileedit;fid=' . $_GET['fid'] . ';msg=need_name'); } // Regex you say? Do a very basic test to see if the pattern is valid if (!empty($_POST['regex']) && @preg_match($_POST['regex'], 'dummy') === false) { redirectexit($scripturl . '?action=admin;area=featuresettings;sa=profileedit;fid=' . $_GET['fid'] . ';msg=regex_error'); } $_POST['field_name'] = Util::htmlspecialchars($_POST['field_name']); $_POST['field_desc'] = Util::htmlspecialchars($_POST['field_desc']); // Checkboxes... $show_reg = isset($_POST['reg']) ? (int) $_POST['reg'] : 0; $show_display = isset($_POST['display']) ? 1 : 0; $show_memberlist = isset($_POST['memberlist']) ? 1 : 0; $bbc = isset($_POST['bbc']) ? 1 : 0; $show_profile = $_POST['profile_area']; $active = isset($_POST['active']) ? 1 : 0; $private = isset($_POST['private']) ? (int) $_POST['private'] : 0; $can_search = isset($_POST['can_search']) ? 1 : 0; // Some masking stuff... $mask = isset($_POST['mask']) ? $_POST['mask'] : ''; if ($mask == 'regex' && isset($_POST['regex'])) { $mask .= $_POST['regex']; } $field_length = isset($_POST['max_length']) ? (int) $_POST['max_length'] : 255; $enclose = isset($_POST['enclose']) ? $_POST['enclose'] : ''; $placement = isset($_POST['placement']) ? (int) $_POST['placement'] : 0; // Select options? $field_options = ''; $newOptions = array(); $default = isset($_POST['default_check']) && $_POST['field_type'] == 'check' ? 1 : ''; if (!empty($_POST['select_option']) && ($_POST['field_type'] == 'select' || $_POST['field_type'] == 'radio')) { foreach ($_POST['select_option'] as $k => $v) { // Clean, clean, clean... $v = Util::htmlspecialchars($v); $v = strtr($v, array(',' => '')); // Nada, zip, etc... if (trim($v) == '') { continue; } // Otherwise, save it boy. $field_options .= $v . ','; // This is just for working out what happened with old options... $newOptions[$k] = $v; // Is it default? if (isset($_POST['default_select']) && $_POST['default_select'] == $k) { $default = $v; } } if (isset($_POST['default_select']) && $_POST['default_select'] == 'no_default') { $default = 'no_default'; } $field_options = substr($field_options, 0, -1); } // Text area by default has dimensions if ($_POST['field_type'] == 'textarea') { $default = (int) $_POST['rows'] . ',' . (int) $_POST['cols']; } // Come up with the unique name? if (empty($context['fid'])) { $colname = Util::substr(strtr($_POST['field_name'], array(' ' => '')), 0, 6); preg_match('~([\\w\\d_-]+)~', $colname, $matches); // If there is nothing to the name, then let's start our own - for foreign languages etc. if (isset($matches[1])) { $colname = $initial_colname = 'cust_' . strtolower($matches[1]); } else { $colname = $initial_colname = 'cust_' . mt_rand(1, 999999); } $unique = ensureUniqueProfileField($colname, $initial_colname); // Still not a unique colum name? Leave it up to the user, then. if (!$unique) { fatal_lang_error('custom_option_not_unique'); } } else { // Anything going to check or select is pointless keeping - as is anything coming from check! if ($_POST['field_type'] == 'check' && $context['field']['type'] != 'check' || ($_POST['field_type'] == 'select' || $_POST['field_type'] == 'radio') && $context['field']['type'] != 'select' && $context['field']['type'] != 'radio' || $context['field']['type'] == 'check' && $_POST['field_type'] != 'check') { deleteProfileFieldUserData($context['field']['colname']); } elseif ($_POST['field_type'] == 'select' || $_POST['field_type'] == 'radio') { $optionChanges = array(); $takenKeys = array(); // Work out what's changed! foreach ($context['field']['options'] as $k => $option) { if (trim($option) == '') { continue; } // Still exists? if (in_array($option, $newOptions)) { $takenKeys[] = $k; continue; } } // Finally - have we renamed it - or is it really gone? foreach ($optionChanges as $k => $option) { // Just been renamed? if (!in_array($k, $takenKeys) && !empty($newOptions[$k])) { updateRenamedProfileField($k, $newOptions, $context['field']['colname'], $option); } } } // @todo Maybe we should adjust based on new text length limits? } // Updating an existing field? if ($context['fid']) { $field_data = array('field_length' => $field_length, 'show_reg' => $show_reg, 'show_display' => $show_display, 'show_memberlist' => $show_memberlist, 'private' => $private, 'active' => $active, 'can_search' => $can_search, 'bbc' => $bbc, 'current_field' => $context['fid'], 'field_name' => $_POST['field_name'], 'field_desc' => $_POST['field_desc'], 'field_type' => $_POST['field_type'], 'field_options' => $field_options, 'show_profile' => $show_profile, 'default_value' => $default, 'mask' => $mask, 'enclose' => $enclose, 'placement' => $placement); updateProfileField($field_data); // Just clean up any old selects - these are a pain! if (($_POST['field_type'] == 'select' || $_POST['field_type'] == 'radio') && !empty($newOptions)) { deleteOldProfileFieldSelects($newOptions, $context['field']['colname']); } } else { $new_field = array('col_name' => $colname, 'field_name' => $_POST['field_name'], 'field_desc' => $_POST['field_desc'], 'field_type' => $_POST['field_type'], 'field_length' => $field_length, 'field_options' => $field_options, 'show_reg' => $show_reg, 'show_display' => $show_display, 'show_memberlist' => $show_memberlist, 'show_profile' => $show_profile, 'private' => $private, 'active' => $active, 'default' => $default, 'can_search' => $can_search, 'bbc' => $bbc, 'mask' => $mask, 'enclose' => $enclose, 'placement' => $placement, 'vieworder' => list_getProfileFieldSize() + 1); addProfileField($new_field); } } elseif (isset($_POST['delete']) && $context['field']['colname']) { checkSession(); validateToken('admin-ecp'); // Delete the old data first, then the field. deleteProfileFieldUserData($context['field']['colname']); deleteProfileField($context['fid']); } // Rebuild display cache etc. if (isset($_POST['delete']) || isset($_POST['save']) || isset($_POST['onoff'])) { checkSession(); // Update the display cache updateDisplayCache(); redirectexit('action=admin;area=featuresettings;sa=profile'); } createToken('admin-ecp'); }
/** * The central part of the board - topic display. * * What it does: * - This function loads the posts in a topic up so they can be displayed. * - It uses the main sub template of the Display template. * - It requires a topic, and can go to the previous or next topic from it. * - It jumps to the correct post depending on a number/time/IS_MSG passed. * - It depends on the messages_per_page, defaultMaxMessages and enableAllMessages settings. * - It is accessed by ?topic=id_topic.START. */ public function action_display() { global $scripturl, $txt, $modSettings, $context, $settings; global $options, $user_info, $board_info, $topic, $board; global $attachments, $messages_request; // What are you gonna display if these are empty?! if (empty($topic)) { fatal_lang_error('no_board', false); } // Load the template loadTemplate('Display'); $context['sub_template'] = 'messages'; // And the topic functions require_once SUBSDIR . '/Topic.subs.php'; require_once SUBSDIR . '/Messages.subs.php'; // Not only does a prefetch make things slower for the server, but it makes it impossible to know if they read it. if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') { @ob_end_clean(); header('HTTP/1.1 403 Prefetch Forbidden'); die; } // How much are we sticking on each page? $context['messages_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) ? $options['messages_per_page'] : $modSettings['defaultMaxMessages']; $template_layers = Template_Layers::getInstance(); $template_layers->addEnd('messages_informations'); $includeUnapproved = !$modSettings['postmod_active'] || allowedTo('approve_posts'); // Let's do some work on what to search index. if (count($_GET) > 2) { foreach ($_GET as $k => $v) { if (!in_array($k, array('topic', 'board', 'start', session_name()))) { $context['robot_no_index'] = true; } } } if (!empty($_REQUEST['start']) && (!is_numeric($_REQUEST['start']) || $_REQUEST['start'] % $context['messages_per_page'] != 0)) { $context['robot_no_index'] = true; } // Find the previous or next topic. Make a fuss if there are no more. if (isset($_REQUEST['prev_next']) && ($_REQUEST['prev_next'] == 'prev' || $_REQUEST['prev_next'] == 'next')) { // No use in calculating the next topic if there's only one. if ($board_info['num_topics'] > 1) { $includeStickies = !empty($modSettings['enableStickyTopics']); $topic = $_REQUEST['prev_next'] === 'prev' ? previousTopic($topic, $board, $user_info['id'], $includeUnapproved, $includeStickies) : nextTopic($topic, $board, $user_info['id'], $includeUnapproved, $includeStickies); $context['current_topic'] = $topic; } // Go to the newest message on this topic. $_REQUEST['start'] = 'new'; } // Add 1 to the number of views of this topic (except for robots). if (!$user_info['possibly_robot'] && (empty($_SESSION['last_read_topic']) || $_SESSION['last_read_topic'] != $topic)) { increaseViewCounter($topic); $_SESSION['last_read_topic'] = $topic; } $topic_selects = array(); $topic_tables = array(); $topic_parameters = array('topic' => $topic, 'member' => $user_info['id'], 'board' => (int) $board); // Allow addons to add additional details to the topic query call_integration_hook('integrate_topic_query', array(&$topic_selects, &$topic_tables, &$topic_parameters)); // Load the topic details $topicinfo = getTopicInfo($topic_parameters, 'all', $topic_selects, $topic_tables); if (empty($topicinfo)) { fatal_lang_error('not_a_topic', false); } // Is this a moved topic that we are redirecting to? if (!empty($topicinfo['id_redirect_topic']) && !isset($_GET['noredir'])) { markTopicsRead(array($user_info['id'], $topic, $topicinfo['id_last_msg'], 0), $topicinfo['new_from'] !== 0); redirectexit('topic=' . $topicinfo['id_redirect_topic'] . '.0;redirfrom=' . $topicinfo['id_topic']); } $context['real_num_replies'] = $context['num_replies'] = $topicinfo['num_replies']; $context['topic_first_message'] = $topicinfo['id_first_msg']; $context['topic_last_message'] = $topicinfo['id_last_msg']; $context['topic_unwatched'] = isset($topicinfo['unwatched']) ? $topicinfo['unwatched'] : 0; if (isset($_GET['redirfrom'])) { $redir_topics = topicsList(array((int) $_GET['redirfrom'])); if (!empty($redir_topics[(int) $_GET['redirfrom']])) { $context['topic_redirected_from'] = $redir_topics[(int) $_GET['redirfrom']]; $context['topic_redirected_from']['redir_href'] = $scripturl . '?topic=' . $context['topic_redirected_from']['id_topic'] . '.0;noredir'; } } // Add up unapproved replies to get real number of replies... if ($modSettings['postmod_active'] && allowedTo('approve_posts')) { $context['real_num_replies'] += $topicinfo['unapproved_posts'] - ($topicinfo['approved'] ? 0 : 1); } // If this topic was derived from another, set the followup details if (!empty($topicinfo['derived_from'])) { require_once SUBSDIR . '/FollowUps.subs.php'; $context['topic_derived_from'] = topicStartedHere($topic, $includeUnapproved); } // If this topic has unapproved posts, we need to work out how many posts the user can see, for page indexing. if (!$includeUnapproved && $topicinfo['unapproved_posts'] && !$user_info['is_guest']) { $myUnapprovedPosts = unapprovedPosts($topic, $user_info['id']); $context['total_visible_posts'] = $context['num_replies'] + $myUnapprovedPosts + ($topicinfo['approved'] ? 1 : 0); } elseif ($user_info['is_guest']) { $context['total_visible_posts'] = $context['num_replies'] + ($topicinfo['approved'] ? 1 : 0); } else { $context['total_visible_posts'] = $context['num_replies'] + $topicinfo['unapproved_posts'] + ($topicinfo['approved'] ? 1 : 0); } // When was the last time this topic was replied to? Should we warn them about it? if (!empty($modSettings['oldTopicDays'])) { $mgsOptions = basicMessageInfo($topicinfo['id_last_msg'], true); $context['oldTopicError'] = $mgsOptions['poster_time'] + $modSettings['oldTopicDays'] * 86400 < time() && empty($topicinfo['is_sticky']); } else { $context['oldTopicError'] = false; } // The start isn't a number; it's information about what to do, where to go. if (!is_numeric($_REQUEST['start'])) { // Redirect to the page and post with new messages, originally by Omar Bazavilvazo. if ($_REQUEST['start'] == 'new') { // Guests automatically go to the last post. if ($user_info['is_guest']) { $context['start_from'] = $context['total_visible_posts'] - 1; $_REQUEST['start'] = $context['start_from']; } else { // Fall through to the next if statement. $_REQUEST['start'] = 'msg' . $topicinfo['new_from']; } } // Start from a certain time index, not a message. if (substr($_REQUEST['start'], 0, 4) == 'from') { $timestamp = (int) substr($_REQUEST['start'], 4); if ($timestamp === 0) { $_REQUEST['start'] = 0; } else { // Find the number of messages posted before said time... $context['start_from'] = countNewPosts($topic, $topicinfo, $timestamp); $_REQUEST['start'] = $context['start_from']; } } elseif (substr($_REQUEST['start'], 0, 3) == 'msg') { $virtual_msg = (int) substr($_REQUEST['start'], 3); if (!$topicinfo['unapproved_posts'] && $virtual_msg >= $topicinfo['id_last_msg']) { $context['start_from'] = $context['total_visible_posts'] - 1; } elseif (!$topicinfo['unapproved_posts'] && $virtual_msg <= $topicinfo['id_first_msg']) { $context['start_from'] = 0; } else { $only_approved = $modSettings['postmod_active'] && $topicinfo['unapproved_posts'] && !allowedTo('approve_posts'); $context['start_from'] = countMessagesBefore($topic, $virtual_msg, false, $only_approved, !$user_info['is_guest']); } // We need to reverse the start as well in this case. $_REQUEST['start'] = $context['start_from']; } } // Mark the mention as read if requested if (isset($_REQUEST['mentionread']) && !empty($virtual_msg)) { require_once CONTROLLERDIR . '/Mentions.controller.php'; $mentions = new Mentions_Controller(); $mentions->setData(array('id_mention' => $_REQUEST['item'], 'mark' => $_REQUEST['mark'])); $mentions->action_markread(); } // Create a previous next string if the selected theme has it as a selected option. if ($modSettings['enablePreviousNext']) { $context['links'] += array('go_prev' => $scripturl . '?topic=' . $topic . '.0;prev_next=prev#new', 'go_next' => $scripturl . '?topic=' . $topic . '.0;prev_next=next#new'); } // Derived from, set the link back if (!empty($context['topic_derived_from'])) { $context['links']['derived_from'] = $scripturl . '?msg=' . $context['topic_derived_from']['derived_from']; } // Check if spellchecking is both enabled and actually working. (for quick reply.) $context['show_spellchecking'] = !empty($modSettings['enableSpellChecking']) && function_exists('pspell_new'); if ($context['show_spellchecking']) { loadJavascriptFile('spellcheck.js', array('defer' => true)); } // Do we need to show the visual verification image? $context['require_verification'] = !$user_info['is_mod'] && !$user_info['is_admin'] && !empty($modSettings['posts_require_captcha']) && ($user_info['posts'] < $modSettings['posts_require_captcha'] || $user_info['is_guest'] && $modSettings['posts_require_captcha'] == -1); if ($context['require_verification']) { require_once SUBSDIR . '/VerificationControls.class.php'; $verificationOptions = array('id' => 'post'); $context['require_verification'] = create_control_verification($verificationOptions); $context['visual_verification_id'] = $verificationOptions['id']; } // Are we showing signatures - or disabled fields? $context['signature_enabled'] = substr($modSettings['signature_settings'], 0, 1) == 1; $context['disabled_fields'] = isset($modSettings['disabled_profile_fields']) ? array_flip(explode(',', $modSettings['disabled_profile_fields'])) : array(); // Censor the title... censorText($topicinfo['subject']); $context['page_title'] = $topicinfo['subject']; // Is this topic sticky, or can it even be? $topicinfo['is_sticky'] = empty($modSettings['enableStickyTopics']) ? '0' : $topicinfo['is_sticky']; // Allow addons access to the topicinfo array call_integration_hook('integrate_display_topic', array($topicinfo)); // Default this topic to not marked for notifications... of course... $context['is_marked_notify'] = false; // Did we report a post to a moderator just now? $context['report_sent'] = isset($_GET['reportsent']); if ($context['report_sent']) { $template_layers->add('report_sent'); } // Let's get nosey, who is viewing this topic? if (!empty($settings['display_who_viewing'])) { require_once SUBSDIR . '/Who.subs.php'; formatViewers($topic, 'topic'); } // If all is set, but not allowed... just unset it. $can_show_all = !empty($modSettings['enableAllMessages']) && $context['total_visible_posts'] > $context['messages_per_page'] && $context['total_visible_posts'] < $modSettings['enableAllMessages']; if (isset($_REQUEST['all']) && !$can_show_all) { unset($_REQUEST['all']); } elseif (isset($_REQUEST['all'])) { $_REQUEST['start'] = -1; } // Construct the page index, allowing for the .START method... $context['page_index'] = constructPageIndex($scripturl . '?topic=' . $topic . '.%1$d', $_REQUEST['start'], $context['total_visible_posts'], $context['messages_per_page'], true, array('all' => $can_show_all, 'all_selected' => isset($_REQUEST['all']))); $context['start'] = $_REQUEST['start']; // This is information about which page is current, and which page we're on - in case you don't like the constructed page index. (again, wireles..) $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['messages_per_page'] + 1, 'num_pages' => floor(($context['total_visible_posts'] - 1) / $context['messages_per_page']) + 1); // Figure out all the link to the next/prev $context['links'] += array('prev' => $_REQUEST['start'] >= $context['messages_per_page'] ? $scripturl . '?topic=' . $topic . '.' . ($_REQUEST['start'] - $context['messages_per_page']) : '', 'next' => $_REQUEST['start'] + $context['messages_per_page'] < $context['total_visible_posts'] ? $scripturl . '?topic=' . $topic . '.' . ($_REQUEST['start'] + $context['messages_per_page']) : ''); // If they are viewing all the posts, show all the posts, otherwise limit the number. if ($can_show_all && isset($_REQUEST['all'])) { // No limit! (actually, there is a limit, but...) $context['messages_per_page'] = -1; // Set start back to 0... $_REQUEST['start'] = 0; } // Build the link tree. $context['linktree'][] = array('url' => $scripturl . '?topic=' . $topic . '.0', 'name' => $topicinfo['subject']); // Build a list of this board's moderators. $context['moderators'] =& $board_info['moderators']; $context['link_moderators'] = array(); // Information about the current topic... $context['is_locked'] = $topicinfo['locked']; $context['is_sticky'] = $topicinfo['is_sticky']; $context['is_very_hot'] = $topicinfo['num_replies'] >= $modSettings['hotTopicVeryPosts']; $context['is_hot'] = $topicinfo['num_replies'] >= $modSettings['hotTopicPosts']; $context['is_approved'] = $topicinfo['approved']; $context['is_poll'] = $topicinfo['id_poll'] > 0 && !empty($modSettings['pollMode']) && allowedTo('poll_view'); determineTopicClass($context); // Did this user start the topic or not? $context['user']['started'] = $user_info['id'] == $topicinfo['id_member_started'] && !$user_info['is_guest']; $context['topic_starter_id'] = $topicinfo['id_member_started']; // Set the topic's information for the template. $context['subject'] = $topicinfo['subject']; $context['num_views'] = $topicinfo['num_views']; $context['num_views_text'] = $context['num_views'] == 1 ? $txt['read_one_time'] : sprintf($txt['read_many_times'], $context['num_views']); $context['mark_unread_time'] = !empty($virtual_msg) ? $virtual_msg : $topicinfo['new_from']; // Set a canonical URL for this page. $context['canonical_url'] = $scripturl . '?topic=' . $topic . '.' . $context['start']; // For quick reply we need a response prefix in the default forum language. $context['response_prefix'] = response_prefix(); // If we want to show event information in the topic, prepare the data. if (allowedTo('calendar_view') && !empty($modSettings['cal_showInTopic']) && !empty($modSettings['cal_enabled'])) { // We need events details and all that jazz require_once SUBSDIR . '/Calendar.subs.php'; // First, try create a better time format, ignoring the "time" elements. if (preg_match('~%[AaBbCcDdeGghjmuYy](?:[^%]*%[AaBbCcDdeGghjmuYy])*~', $user_info['time_format'], $matches) == 0 || empty($matches[0])) { $date_string = $user_info['time_format']; } else { $date_string = $matches[0]; } // Get event information for this topic. $events = eventInfoForTopic($topic); $context['linked_calendar_events'] = array(); foreach ($events as $event) { // Prepare the dates for being formatted. $start_date = sscanf($event['start_date'], '%04d-%02d-%02d'); $start_date = mktime(12, 0, 0, $start_date[1], $start_date[2], $start_date[0]); $end_date = sscanf($event['end_date'], '%04d-%02d-%02d'); $end_date = mktime(12, 0, 0, $end_date[1], $end_date[2], $end_date[0]); $context['linked_calendar_events'][] = array('id' => $event['id_event'], 'title' => $event['title'], 'can_edit' => allowedTo('calendar_edit_any') || $event['id_member'] == $user_info['id'] && allowedTo('calendar_edit_own'), 'modify_href' => $scripturl . '?action=post;msg=' . $topicinfo['id_first_msg'] . ';topic=' . $topic . '.0;calendar;eventid=' . $event['id_event'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'can_export' => allowedTo('calendar_edit_any') || $event['id_member'] == $user_info['id'] && allowedTo('calendar_edit_own'), 'export_href' => $scripturl . '?action=calendar;sa=ical;eventid=' . $event['id_event'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'start_date' => standardTime($start_date, $date_string, 'none'), 'start_timestamp' => $start_date, 'end_date' => standardTime($end_date, $date_string, 'none'), 'end_timestamp' => $end_date, 'is_last' => false); } if (!empty($context['linked_calendar_events'])) { $context['linked_calendar_events'][count($context['linked_calendar_events']) - 1]['is_last'] = true; $template_layers->add('display_calendar'); } } // Create the poll info if it exists. if ($context['is_poll']) { $template_layers->add('display_poll'); require_once SUBSDIR . '/Poll.subs.php'; loadPollContext($topicinfo['id_poll']); // Build the poll moderation button array. $context['poll_buttons'] = array('vote' => array('test' => 'allow_return_vote', 'text' => 'poll_return_vote', 'image' => 'poll_options.png', 'lang' => true, 'url' => $scripturl . '?topic=' . $context['current_topic'] . '.' . $context['start']), 'results' => array('test' => 'allow_poll_view', 'text' => 'poll_results', 'image' => 'poll_results.png', 'lang' => true, 'url' => $scripturl . '?topic=' . $context['current_topic'] . '.' . $context['start'] . ';viewresults'), 'change_vote' => array('test' => 'allow_change_vote', 'text' => 'poll_change_vote', 'image' => 'poll_change_vote.png', 'lang' => true, 'url' => $scripturl . '?action=poll;sa=vote;topic=' . $context['current_topic'] . '.' . $context['start'] . ';poll=' . $context['poll']['id'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'lock' => array('test' => 'allow_lock_poll', 'text' => !$context['poll']['is_locked'] ? 'poll_lock' : 'poll_unlock', 'image' => 'poll_lock.png', 'lang' => true, 'url' => $scripturl . '?action=lockvoting;topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'edit' => array('test' => 'allow_edit_poll', 'text' => 'poll_edit', 'image' => 'poll_edit.png', 'lang' => true, 'url' => $scripturl . '?action=editpoll;topic=' . $context['current_topic'] . '.' . $context['start']), 'remove_poll' => array('test' => 'can_remove_poll', 'text' => 'poll_remove', 'image' => 'admin_remove_poll.png', 'lang' => true, 'custom' => 'onclick="return confirm(\'' . $txt['poll_remove_warn'] . '\');"', 'url' => $scripturl . '?action=poll;sa=remove;topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id'])); // Allow mods to add additional buttons here call_integration_hook('integrate_poll_buttons'); } // Calculate the fastest way to get the messages! $ascending = true; $start = $_REQUEST['start']; $limit = $context['messages_per_page']; $firstIndex = 0; if ($start >= $context['total_visible_posts'] / 2 && $context['messages_per_page'] != -1) { $ascending = !$ascending; $limit = $context['total_visible_posts'] <= $start + $limit ? $context['total_visible_posts'] - $start : $limit; $start = $context['total_visible_posts'] <= $start + $limit ? 0 : $context['total_visible_posts'] - $start - $limit; $firstIndex = $limit - 1; } // Taking care of member specific settings $limit_settings = array('messages_per_page' => $context['messages_per_page'], 'start' => $start, 'offset' => $limit); // Get each post and poster in this topic. $topic_details = getTopicsPostsAndPoster($topic, $limit_settings, $ascending); $messages = $topic_details['messages']; $posters = array_unique($topic_details['all_posters']); $all_posters = $topic_details['all_posters']; unset($topic_details); call_integration_hook('integrate_display_message_list', array(&$messages, &$posters)); // Guests can't mark topics read or for notifications, just can't sorry. if (!$user_info['is_guest'] && !empty($messages)) { $mark_at_msg = max($messages); if ($mark_at_msg >= $topicinfo['id_last_msg']) { $mark_at_msg = $modSettings['maxMsgID']; } if ($mark_at_msg >= $topicinfo['new_from']) { markTopicsRead(array($user_info['id'], $topic, $mark_at_msg, $topicinfo['unwatched']), $topicinfo['new_from'] !== 0); } updateReadNotificationsFor($topic, $board); // Have we recently cached the number of new topics in this board, and it's still a lot? if (isset($_REQUEST['topicseen']) && isset($_SESSION['topicseen_cache'][$board]) && $_SESSION['topicseen_cache'][$board] > 5) { $_SESSION['topicseen_cache'][$board]--; } elseif (isset($_REQUEST['topicseen'])) { // Use the mark read tables... and the last visit to figure out if this should be read or not. $numNewTopics = getUnreadCountSince($board, empty($_SESSION['id_msg_last_visit']) ? 0 : $_SESSION['id_msg_last_visit']); // If there're no real new topics in this board, mark the board as seen. if (empty($numNewTopics)) { $_REQUEST['boardseen'] = true; } else { $_SESSION['topicseen_cache'][$board] = $numNewTopics; } } elseif (isset($_SESSION['topicseen_cache'][$board])) { $_SESSION['topicseen_cache'][$board]--; } // Mark board as seen if we came using last post link from BoardIndex. (or other places...) if (isset($_REQUEST['boardseen'])) { require_once SUBSDIR . '/Boards.subs.php'; markBoardsRead($board, false, false); } } $attachments = array(); // If there _are_ messages here... (probably an error otherwise :!) if (!empty($messages)) { require_once SUBSDIR . '/Attachments.subs.php'; // Fetch attachments. $includeUnapproved = !$modSettings['postmod_active'] || allowedTo('approve_posts'); if (!empty($modSettings['attachmentEnable']) && allowedTo('view_attachments')) { $attachments = getAttachments($messages, $includeUnapproved, 'filter_accessible_attachment', $all_posters); } $msg_parameters = array('message_list' => $messages, 'new_from' => $topicinfo['new_from']); $msg_selects = array(); $msg_tables = array(); call_integration_hook('integrate_message_query', array(&$msg_selects, &$msg_tables, &$msg_parameters)); // What? It's not like it *couldn't* be only guests in this topic... if (!empty($posters)) { loadMemberData($posters); } // Load in the likes for this group of messages if (!empty($modSettings['likes_enabled'])) { require_once SUBSDIR . '/Likes.subs.php'; $context['likes'] = loadLikes($messages, true); // ajax controller for likes loadJavascriptFile('like_posts.js', array('defer' => true)); loadLanguage('Errors'); // Initiate likes and the tooltips for likes addInlineJavascript(' $(document).ready(function () { var likePostInstance = likePosts.prototype.init({ oTxt: ({ btnText : ' . JavaScriptEscape($txt['ok_uppercase']) . ', likeHeadingError : ' . JavaScriptEscape($txt['like_heading_error']) . ', error_occurred : ' . JavaScriptEscape($txt['error_occurred']) . ' }), }); $(".like_button, .unlike_button").SiteTooltip({ hoverIntent: { sensitivity: 10, interval: 150, timeout: 50 } }); });', true); } $messages_request = loadMessageRequest($msg_selects, $msg_tables, $msg_parameters); if (!empty($modSettings['enableFollowup'])) { require_once SUBSDIR . '/FollowUps.subs.php'; $context['follow_ups'] = followupTopics($messages, $includeUnapproved); } // Go to the last message if the given time is beyond the time of the last message. if (isset($context['start_from']) && $context['start_from'] >= $topicinfo['num_replies']) { $context['start_from'] = $topicinfo['num_replies']; } // Since the anchor information is needed on the top of the page we load these variables beforehand. $context['first_message'] = isset($messages[$firstIndex]) ? $messages[$firstIndex] : $messages[0]; $context['first_new_message'] = isset($context['start_from']) && $_REQUEST['start'] == $context['start_from']; } else { $messages_request = false; $context['first_message'] = 0; $context['first_new_message'] = false; } $context['jump_to'] = array('label' => addslashes(un_htmlspecialchars($txt['jump_to'])), 'board_name' => htmlspecialchars(strtr(strip_tags($board_info['name']), array('&' => '&')), ENT_COMPAT, 'UTF-8'), 'child_level' => $board_info['child_level']); // Set the callback. (do you REALIZE how much memory all the messages would take?!?) // This will be called from the template. $context['get_message'] = array($this, 'prepareDisplayContext_callback'); // Now set all the wonderful, wonderful permissions... like moderation ones... $common_permissions = array('can_approve' => 'approve_posts', 'can_ban' => 'manage_bans', 'can_sticky' => 'make_sticky', 'can_merge' => 'merge_any', 'can_split' => 'split_any', 'calendar_post' => 'calendar_post', 'can_mark_notify' => 'mark_any_notify', 'can_send_topic' => 'send_topic', 'can_send_pm' => 'pm_send', 'can_send_email' => 'send_email_to_members', 'can_report_moderator' => 'report_any', 'can_moderate_forum' => 'moderate_forum', 'can_issue_warning' => 'issue_warning', 'can_restore_topic' => 'move_any', 'can_restore_msg' => 'move_any'); foreach ($common_permissions as $contextual => $perm) { $context[$contextual] = allowedTo($perm); } // Permissions with _any/_own versions. $context[YYY] => ZZZ_any/_own. $anyown_permissions = array('can_move' => 'move', 'can_lock' => 'lock', 'can_delete' => 'remove', 'can_add_poll' => 'poll_add', 'can_remove_poll' => 'poll_remove', 'can_reply' => 'post_reply', 'can_reply_unapproved' => 'post_unapproved_replies'); foreach ($anyown_permissions as $contextual => $perm) { $context[$contextual] = allowedTo($perm . '_any') || $context['user']['started'] && allowedTo($perm . '_own'); } // Cleanup all the permissions with extra stuff... $context['can_mark_notify'] &= !$context['user']['is_guest']; $context['can_sticky'] &= !empty($modSettings['enableStickyTopics']); $context['calendar_post'] &= !empty($modSettings['cal_enabled']) && (allowedTo('modify_any') || $context['user']['started'] && allowedTo('modify_own')); $context['can_add_poll'] &= !empty($modSettings['pollMode']) && $topicinfo['id_poll'] <= 0; $context['can_remove_poll'] &= !empty($modSettings['pollMode']) && $topicinfo['id_poll'] > 0; $context['can_reply'] &= empty($topicinfo['locked']) || allowedTo('moderate_board'); $context['can_reply_unapproved'] &= $modSettings['postmod_active'] && (empty($topicinfo['locked']) || allowedTo('moderate_board')); $context['can_issue_warning'] &= in_array('w', $context['admin_features']) && !empty($modSettings['warning_enable']); // Handle approval flags... $context['can_reply_approved'] = $context['can_reply']; $context['can_reply'] |= $context['can_reply_unapproved']; $context['can_quote'] = $context['can_reply'] && (empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC']))); $context['can_mark_unread'] = !$user_info['is_guest'] && $settings['show_mark_read']; $context['can_unwatch'] = !$user_info['is_guest'] && $modSettings['enable_unwatch']; $context['can_send_topic'] = (!$modSettings['postmod_active'] || $topicinfo['approved']) && allowedTo('send_topic'); $context['can_print'] = empty($modSettings['disable_print_topic']); // Start this off for quick moderation - it will be or'd for each post. $context['can_remove_post'] = allowedTo('delete_any') || allowedTo('delete_replies') && $context['user']['started']; // Can restore topic? That's if the topic is in the recycle board and has a previous restore state. $context['can_restore_topic'] &= !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board && !empty($topicinfo['id_previous_board']); $context['can_restore_msg'] &= !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board && !empty($topicinfo['id_previous_topic']); $context['can_follow_up'] = !empty($modSettings['enableFollowup']) && boardsallowedto('post_new') !== array(); // Check if the draft functions are enabled and that they have permission to use them (for quick reply.) $context['drafts_save'] = !empty($modSettings['drafts_enabled']) && !empty($modSettings['drafts_post_enabled']) && allowedTo('post_draft') && $context['can_reply']; $context['drafts_autosave'] = !empty($context['drafts_save']) && !empty($modSettings['drafts_autosave_enabled']) && allowedTo('post_autosave_draft'); if (!empty($context['drafts_save'])) { loadLanguage('Drafts'); } if (!empty($context['drafts_autosave']) && empty($options['use_editor_quick_reply'])) { loadJavascriptFile('drafts.js'); } if (!empty($modSettings['mentions_enabled'])) { $context['mentions_enabled'] = true; // Just using the plain text quick reply and not the editor if (empty($options['use_editor_quick_reply'])) { loadJavascriptFile(array('jquery.atwho.js', 'jquery.caret.min.js', 'mentioning.js')); } loadCSSFile('jquery.atwho.css'); addInlineJavascript(' $(document).ready(function () { for (var i = 0, count = all_elk_mentions.length; i < count; i++) all_elk_mentions[i].oMention = new elk_mentions(all_elk_mentions[i].oOptions); });'); } // Load up the Quick ModifyTopic and Quick Reply scripts loadJavascriptFile('topic.js'); // Auto video embeding enabled? if (!empty($modSettings['enableVideoEmbeding'])) { addInlineJavascript(' $(document).ready(function() { $().linkifyvideo(oEmbedtext); });'); } // Load up the "double post" sequencing magic. if (!empty($options['display_quick_reply'])) { checkSubmitOnce('register'); $context['name'] = isset($_SESSION['guest_name']) ? $_SESSION['guest_name'] : ''; $context['email'] = isset($_SESSION['guest_email']) ? $_SESSION['guest_email'] : ''; if (!empty($options['use_editor_quick_reply']) && $context['can_reply']) { // Needed for the editor and message icons. require_once SUBSDIR . '/Editor.subs.php'; // Now create the editor. $editorOptions = array('id' => 'message', 'value' => '', 'labels' => array('post_button' => $txt['post']), 'height' => '250px', 'width' => '100%', 'preview_type' => 0); create_control_richedit($editorOptions); $context['attached'] = ''; $context['make_poll'] = isset($_REQUEST['poll']); // Message icons - customized icons are off? $context['icons'] = getMessageIcons($board); if (!empty($context['icons'])) { $context['icons'][count($context['icons']) - 1]['is_last'] = true; } } } addJavascriptVar(array('notification_topic_notice' => $context['is_marked_notify'] ? $txt['notification_disable_topic'] : $txt['notification_enable_topic']), true); if ($context['can_send_topic']) { addJavascriptVar(array('sendtopic_cancel' => $txt['modify_cancel'], 'sendtopic_back' => $txt['back'], 'sendtopic_close' => $txt['find_close'], 'sendtopic_error' => $txt['send_error_occurred'], 'required_field' => $txt['require_field']), true); } // Build the normal button array. $context['normal_buttons'] = array('reply' => array('test' => 'can_reply', 'text' => 'reply', 'image' => 'reply.png', 'lang' => true, 'url' => $scripturl . '?action=post;topic=' . $context['current_topic'] . '.' . $context['start'] . ';last_msg=' . $context['topic_last_message'], 'active' => true), 'notify' => array('test' => 'can_mark_notify', 'text' => $context['is_marked_notify'] ? 'unnotify' : 'notify', 'image' => ($context['is_marked_notify'] ? 'un' : '') . 'notify.png', 'lang' => true, 'custom' => 'onclick="return notifyButton(this);"', 'url' => $scripturl . '?action=notify;sa=' . ($context['is_marked_notify'] ? 'off' : 'on') . ';topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'mark_unread' => array('test' => 'can_mark_unread', 'text' => 'mark_unread', 'image' => 'markunread.png', 'lang' => true, 'url' => $scripturl . '?action=markasread;sa=topic;t=' . $context['mark_unread_time'] . ';topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'unwatch' => array('test' => 'can_unwatch', 'text' => ($context['topic_unwatched'] ? '' : 'un') . 'watch', 'image' => ($context['topic_unwatched'] ? '' : 'un') . 'watched.png', 'lang' => true, 'custom' => 'onclick="return unwatchButton(this);"', 'url' => $scripturl . '?action=unwatchtopic;topic=' . $context['current_topic'] . '.' . $context['start'] . ';sa=' . ($context['topic_unwatched'] ? 'off' : 'on') . ';' . $context['session_var'] . '=' . $context['session_id']), 'send' => array('test' => 'can_send_topic', 'text' => 'send_topic', 'image' => 'sendtopic.png', 'lang' => true, 'url' => $scripturl . '?action=emailuser;sa=sendtopic;topic=' . $context['current_topic'] . '.0', 'custom' => 'onclick="return sendtopicOverlayDiv(this.href, \'' . $txt['send_topic'] . '\');"'), 'print' => array('test' => 'can_print', 'text' => 'print', 'image' => 'print.png', 'lang' => true, 'custom' => 'rel="nofollow"', 'class' => 'new_win', 'url' => $scripturl . '?action=topic;sa=printpage;topic=' . $context['current_topic'] . '.0')); // Build the mod button array $context['mod_buttons'] = array('move' => array('test' => 'can_move', 'text' => 'move_topic', 'image' => 'admin_move.png', 'lang' => true, 'url' => $scripturl . '?action=movetopic;current_board=' . $context['current_board'] . ';topic=' . $context['current_topic'] . '.0'), 'delete' => array('test' => 'can_delete', 'text' => 'remove_topic', 'image' => 'admin_rem.png', 'lang' => true, 'custom' => 'onclick="return confirm(\'' . $txt['are_sure_remove_topic'] . '\');"', 'url' => $scripturl . '?action=removetopic2;topic=' . $context['current_topic'] . '.0;' . $context['session_var'] . '=' . $context['session_id']), 'lock' => array('test' => 'can_lock', 'text' => empty($context['is_locked']) ? 'set_lock' : 'set_unlock', 'image' => 'admin_lock.png', 'lang' => true, 'url' => $scripturl . '?action=topic;sa=lock;topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'sticky' => array('test' => 'can_sticky', 'text' => empty($context['is_sticky']) ? 'set_sticky' : 'set_nonsticky', 'image' => 'admin_sticky.png', 'lang' => true, 'url' => $scripturl . '?action=topic;sa=sticky;topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'merge' => array('test' => 'can_merge', 'text' => 'merge', 'image' => 'merge.png', 'lang' => true, 'url' => $scripturl . '?action=mergetopics;board=' . $context['current_board'] . '.0;from=' . $context['current_topic']), 'calendar' => array('test' => 'calendar_post', 'text' => 'calendar_link', 'image' => 'linktocal.png', 'lang' => true, 'url' => $scripturl . '?action=post;calendar;msg=' . $context['topic_first_message'] . ';topic=' . $context['current_topic'] . '.0')); // Restore topic. eh? No monkey business. if ($context['can_restore_topic']) { $context['mod_buttons'][] = array('text' => 'restore_topic', 'image' => '', 'lang' => true, 'url' => $scripturl . '?action=restoretopic;topics=' . $context['current_topic'] . ';' . $context['session_var'] . '=' . $context['session_id']); } if ($context['can_reply'] && !empty($options['display_quick_reply'])) { $template_layers->add('quickreply'); } $template_layers->add('pages_and_buttons'); // Allow adding new buttons easily. call_integration_hook('integrate_display_buttons'); call_integration_hook('integrate_mod_buttons'); }
/** * Creates a box that can be used for richedit stuff like BBC, Smileys etc. * @param mixed[] $editorOptions associative array of options => value * must contain: * - id => unique id for the css * - value => text for the editor or blank * Optionaly * - height => height of the intial box * - width => width of the box (100%) * - force_rich => force wysiwyg to be enabled * - disable_smiley_box => boolean to turn off the smiley box * - labels => array( * - 'post_button' => $txt['for post button'], * ), * - preview_type => 2 how to act on preview click, see template_control_richedit_buttons */ function create_control_richedit($editorOptions) { global $txt, $modSettings, $options, $context, $settings, $user_info, $scripturl; static $bbc_tags; $db = database(); // Load the Post language file... for the moment at least. loadLanguage('Post'); if (!empty($context['drafts_save']) || !empty($context['drafts_pm_save'])) { loadLanguage('Drafts'); } // Every control must have a ID! assert(isset($editorOptions['id'])); assert(isset($editorOptions['value'])); // Is this the first richedit - if so we need to ensure things are initialised and that we load all of the needed files if (empty($context['controls']['richedit'])) { // Store the name / ID we are creating for template compatibility. $context['post_box_name'] = $editorOptions['id']; // Some general stuff. $settings['smileys_url'] = $modSettings['smileys_url'] . '/' . $user_info['smiley_set']; if (!empty($context['drafts_autosave']) && !empty($options['drafts_autosave_enabled'])) { $context['drafts_autosave_frequency'] = empty($modSettings['drafts_autosave_frequency']) ? 30000 : $modSettings['drafts_autosave_frequency'] * 1000; } // This really has some WYSIWYG stuff. loadTemplate('GenericControls', 'jquery.sceditor'); if (!empty($context['theme_variant']) && file_exists($settings['theme_dir'] . '/css/' . $context['theme_variant'] . '/jquery.sceditor.elk' . $context['theme_variant'] . '.css')) { loadCSSFile($context['theme_variant'] . '/jquery.sceditor.elk' . $context['theme_variant'] . '.css'); } // JS makes the editor go round loadJavascriptFile(array('jquery.sceditor.min.js', 'jquery.sceditor.bbcode.min.js', 'jquery.sceditor.elkarte.js', 'post.js', 'splittag.plugin.js', 'dropAttachments.js')); addJavascriptVar(array('post_box_name' => $editorOptions['id'], 'elk_smileys_url' => $settings['smileys_url'], 'bbc_quote_from' => $txt['quote_from'], 'bbc_quote' => $txt['quote'], 'bbc_search_on' => $txt['search_on']), true); // Editor language file if (!empty($txt['lang_locale'])) { loadJavascriptFile($scripturl . '?action=jslocale;sa=sceditor', array('defer' => true), 'sceditor_language'); } // Drafts? if ((!empty($context['drafts_save']) || !empty($context['drafts_pm_save'])) && !empty($context['drafts_autosave']) && !empty($options['drafts_autosave_enabled'])) { loadJavascriptFile('drafts.plugin.js'); } // Mentions? if (!empty($context['mentions_enabled'])) { loadJavascriptFile(array('jquery.atwho.js', 'jquery.caret.min.js', 'mentioning.plugin.js')); } // Our not so concise shortcut line $context['shortcuts_text'] = $txt['shortcuts' . (!empty($context['drafts_save']) || !empty($context['drafts_pm_save']) ? '_drafts' : '') . (isBrowser('is_firefox') ? '_firefox' : '')]; // Spellcheck? $context['show_spellchecking'] = !empty($modSettings['enableSpellChecking']) && function_exists('pspell_new'); if ($context['show_spellchecking']) { // Some hidden information is needed in order to make spell check work. if (!isset($_REQUEST['xml'])) { $context['insert_after_template'] .= ' <form name="spell_form" id="spell_form" method="post" accept-charset="UTF-8" target="spellWindow" action="' . $scripturl . '?action=spellcheck"> <input type="hidden" name="spellstring" value="" /> <input type="hidden" name="fulleditor" value="" /> </form>'; } loadJavascriptFile('spellcheck.js', array('defer' => true)); } } // Start off the editor... $context['controls']['richedit'][$editorOptions['id']] = array('id' => $editorOptions['id'], 'value' => $editorOptions['value'], 'rich_active' => !empty($options['wysiwyg_default']) || !empty($editorOptions['force_rich']) || !empty($_REQUEST[$editorOptions['id'] . '_mode']), 'disable_smiley_box' => !empty($editorOptions['disable_smiley_box']), 'columns' => isset($editorOptions['columns']) ? $editorOptions['columns'] : 60, 'rows' => isset($editorOptions['rows']) ? $editorOptions['rows'] : 18, 'width' => isset($editorOptions['width']) ? $editorOptions['width'] : '100%', 'height' => isset($editorOptions['height']) ? $editorOptions['height'] : '250px', 'form' => isset($editorOptions['form']) ? $editorOptions['form'] : 'postmodify', 'bbc_level' => !empty($editorOptions['bbc_level']) ? $editorOptions['bbc_level'] : 'full', 'preview_type' => isset($editorOptions['preview_type']) ? (int) $editorOptions['preview_type'] : 1, 'labels' => !empty($editorOptions['labels']) ? $editorOptions['labels'] : array(), 'locale' => !empty($txt['lang_locale']) ? $txt['lang_locale'] : 'en_US'); // Switch between default images and back... mostly in case you don't have an PersonalMessage template, but do have a Post template. if (isset($settings['use_default_images']) && $settings['use_default_images'] == 'defaults' && isset($settings['default_template'])) { $temp1 = $settings['theme_url']; $settings['theme_url'] = $settings['default_theme_url']; $temp2 = $settings['images_url']; $settings['images_url'] = $settings['default_images_url']; $temp3 = $settings['theme_dir']; $settings['theme_dir'] = $settings['default_theme_dir']; } if (empty($bbc_tags)) { // The below array is used to show a command button in the editor, the execution // and display details of any added buttons must be defined in the javascript files // see jquery.sceditor.elkarte.js under the $.sceditor.plugins.bbcode.bbcode area // for examples of how to use the .set command to add codes. Include your new // JS with addInlineJavascript() or loadJavascriptFile() $bbc_tags['row1'] = array(array('bold', 'italic', 'underline', 'strike', 'superscript', 'subscript'), array('left', 'center', 'right', 'pre', 'tt'), array('font', 'size', 'color')); $bbc_tags['row2'] = array(array('quote', 'code', 'table'), array('bulletlist', 'orderedlist', 'horizontalrule'), array('spoiler', 'footnote'), array('image', 'link', 'email')); // Allow mods to add BBC buttons to the toolbar, actions are defined in the JS call_integration_hook('integrate_bbc_buttons', array(&$bbc_tags)); // Show the wysiwyg format and toggle buttons? $bbc_tags['row2'][] = array('removeformat', 'source'); // Generate a list of buttons that shouldn't be shown $disabled_tags = array(); if (!empty($modSettings['disabledBBC'])) { $disabled_tags = explode(',', $modSettings['disabledBBC']); } // Map codes to tags $translate_tags_to_code = array('b' => 'bold', 'i' => 'italic', 'u' => 'underline', 's' => 'strike', 'img' => 'image', 'url' => 'link', 'sup' => 'superscript', 'sub' => 'subscript', 'hr' => 'horizontalrule'); // Remove the toolbar buttons for any bbc tags that have been turned off in the ACP foreach ($disabled_tags as $tag) { // list is special, its prevents two tags if ($tag === 'list') { $context['disabled_tags']['bulletlist'] = true; $context['disabled_tags']['orderedlist'] = true; } elseif (isset($translate_tags_to_code[$tag])) { $context['disabled_tags'][$translate_tags_to_code[$tag]] = true; } // Tag is the same as the code, like font, color, size etc $context['disabled_tags'][trim($tag)] = true; } // Build our toolbar, taking in to account any bbc codes from integration $context['bbc_toolbar'] = array(); foreach ($bbc_tags as $row => $tagRow) { if (!isset($context['bbc_toolbar'][$row])) { $context['bbc_toolbar'][$row] = array(); } $tagsRow = array(); // For each row of buttons defined, lets build our tags foreach ($tagRow as $tags) { foreach ($tags as $tag) { // Just add this code in the existing grouping if (!isset($context['disabled_tags'][$tag])) { $tagsRow[] = $tag; } } // If the row is not empty, and the last added tag is not a space, add a space. if (!empty($tagsRow) && $tagsRow[count($tagsRow) - 1] != 'space') { $tagsRow[] = 'space'; } } // Build that beautiful button row if (!empty($tagsRow)) { $context['bbc_toolbar'][$row][] = implode(',', $tagsRow); } } } // Initialize smiley array... if not loaded before. if (empty($context['smileys']) && empty($editorOptions['disable_smiley_box'])) { $context['smileys'] = array('postform' => array(), 'popup' => array()); // Load smileys - don't bother to run a query if we're not using the database's ones anyhow. if (empty($modSettings['smiley_enable']) && $user_info['smiley_set'] != 'none') { $context['smileys']['postform'][] = array('smileys' => array(array('code' => ':)', 'filename' => 'smiley.gif', 'description' => $txt['icon_smiley']), array('code' => ';)', 'filename' => 'wink.gif', 'description' => $txt['icon_wink']), array('code' => ':D', 'filename' => 'cheesy.gif', 'description' => $txt['icon_cheesy']), array('code' => ';D', 'filename' => 'grin.gif', 'description' => $txt['icon_grin']), array('code' => '>:(', 'filename' => 'angry.gif', 'description' => $txt['icon_angry']), array('code' => ':))', 'filename' => 'laugh.gif', 'description' => $txt['icon_laugh']), array('code' => ':(', 'filename' => 'sad.gif', 'description' => $txt['icon_sad']), array('code' => ':o', 'filename' => 'shocked.gif', 'description' => $txt['icon_shocked']), array('code' => '8)', 'filename' => 'cool.gif', 'description' => $txt['icon_cool']), array('code' => '???', 'filename' => 'huh.gif', 'description' => $txt['icon_huh']), array('code' => '::)', 'filename' => 'rolleyes.gif', 'description' => $txt['icon_rolleyes']), array('code' => ':P', 'filename' => 'tongue.gif', 'description' => $txt['icon_tongue']), array('code' => ':-[', 'filename' => 'embarrassed.gif', 'description' => $txt['icon_embarrassed']), array('code' => ':-X', 'filename' => 'lipsrsealed.gif', 'description' => $txt['icon_lips']), array('code' => ':-\\', 'filename' => 'undecided.gif', 'description' => $txt['icon_undecided']), array('code' => ':-*', 'filename' => 'kiss.gif', 'description' => $txt['icon_kiss']), array('code' => 'O:)', 'filename' => 'angel.gif', 'description' => $txt['icon_angel']), array('code' => ':\'(', 'filename' => 'cry.gif', 'description' => $txt['icon_cry'], 'isLast' => true)), 'isLast' => true); } elseif ($user_info['smiley_set'] != 'none') { if (($temp = cache_get_data('posting_smileys', 480)) == null) { $request = $db->query('', ' SELECT code, filename, description, smiley_row, hidden FROM {db_prefix}smileys WHERE hidden IN (0, 2) ORDER BY smiley_row, smiley_order', array()); while ($row = $db->fetch_assoc($request)) { $row['filename'] = htmlspecialchars($row['filename'], ENT_COMPAT, 'UTF-8'); $row['description'] = htmlspecialchars($row['description'], ENT_COMPAT, 'UTF-8'); $context['smileys'][empty($row['hidden']) ? 'postform' : 'popup'][$row['smiley_row']]['smileys'][] = $row; } $db->free_result($request); foreach ($context['smileys'] as $section => $smileyRows) { $last_row = null; foreach ($smileyRows as $rowIndex => $smileys) { $context['smileys'][$section][$rowIndex]['smileys'][count($smileys['smileys']) - 1]['isLast'] = true; $last_row = $rowIndex; } if ($last_row !== null) { $context['smileys'][$section][$last_row]['isLast'] = true; } } cache_put_data('posting_smileys', $context['smileys'], 480); } else { $context['smileys'] = $temp; } // The smiley popup may take advantage of Jquery UI .... if (!empty($context['smileys']['popup'])) { $modSettings['jquery_include_ui'] = true; } } } // Set a flag so the sub template knows what to do... $context['show_bbc'] = !empty($modSettings['enableBBC']) && !empty($settings['show_bbc']); // Switch the URLs back... now we're back to whatever the main sub template is. (like folder in PersonalMessage.) if (isset($settings['use_default_images']) && $settings['use_default_images'] == 'defaults' && isset($settings['default_template'])) { $settings['theme_url'] = $temp1; $settings['images_url'] = $temp2; $settings['theme_dir'] = $temp3; } if (!empty($editorOptions['live_errors'])) { loadLanguage('Errors'); addInlineJavascript(' error_txts[\'no_subject\'] = ' . JavaScriptEscape($txt['error_no_subject']) . '; error_txts[\'no_message\'] = ' . JavaScriptEscape($txt['error_no_message']) . '; var subject_err = new errorbox_handler({ self: \'subject_err\', error_box_id: \'post_error\', error_checks: [{ code: \'no_subject\', efunction: function(box_value) { if (box_value.length === 0) return true; else return false; } }], check_id: "post_subject" }); var body_err_' . $editorOptions['id'] . ' = new errorbox_handler({ self: \'body_err_' . $editorOptions['id'] . '\', error_box_id: \'post_error\', error_checks: [{ code: \'no_message\', efunction: function(box_value) { if (box_value.length === 0) return true; else return false; } }], editor_id: \'' . $editorOptions['id'] . '\', editor: ' . JavaScriptEscape(' (function () { return $editor_data[\'' . $editorOptions['id'] . '\'].val(); });') . ' });', true); } }
/** * Deals with the initialization of SimplePortal headers. */ function sportal_init_headers() { global $modSettings, $txt, $user_info, $scripturl; static $initialized; // If already loaded just return if (!empty($initialized)) { return $initialized; } // Generate a safe scripturl $safe_scripturl = $scripturl; $current_request = empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] : $_SERVER['HTTP_HOST']; if (strpos($scripturl, 'www.') !== false && strpos($current_request, 'www.') === false) { $safe_scripturl = str_replace('://www.', '://', $scripturl); } elseif (strpos($scripturl, 'www.') === false && strpos($current_request, 'www.') !== false) { $safe_scripturl = str_replace('://', '://www.', $scripturl); } // The shoutbox may fail to function in certain cases without using a safe scripturl addJavascriptVar(array('sp_script_url' => '\'' . $safe_scripturl . '\'')); // Load up some javascript! loadJavascriptFile('portal.js?sp100'); $javascript = ''; // We use drag and sort blocks for the front page if ($modSettings['sp_portal_mode'] == 1) { $modSettings['jquery_include_ui'] = true; // Javascipt to allow D&D ordering of the front page blocks, not for guests if (empty($_REQUEST['action']) && !($user_info['is_guest'] || $user_info['id'] == 0)) { $javascript .= ' // Set up our sortable call $().elkSortable({ sa: "userblockorder", error: "' . $txt['portal_order_error'] . '", title: "' . $txt['portal_order_title'] . '", handle: ".sp_drag_header", tag: ".sp_column", opacity: 0.9, connect: ".sp_column", containment: "#main_content_section", tolerance: "pointer", href: "/", placeholder: "ui-state-highlight", axis: "", });'; } } if ($modSettings['sp_resize_images']) { $javascript .= ' createEventListener(window); window.addEventListener("load", sp_image_resize, false);'; } // Let the template know we have some inline JS to display addInlineJavascript($javascript, true); $initialized = true; return $initialized; }
/** * Load a theme, by ID. * * What it does: * - identify the theme to be loaded. * - validate that the theme is valid and that the user has permission to use it * - load the users theme settings and site setttings into $options. * - prepares the list of folders to search for template loading. * - identify what smiley set to use. * - sets up $context['user'] * - detects the users browser and sets a mobile friendly enviroment if needed * - loads default JS variables for use in every theme * - loads default JS scripts for use in every theme * * @param int $id_theme = 0 * @param bool $initialize = true */ function loadTheme($id_theme = 0, $initialize = true) { global $user_info, $user_settings, $board_info; global $txt, $boardurl, $scripturl, $mbname, $modSettings; global $context, $settings, $options, $ssi_theme; $db = database(); // The theme was specified by parameter. if (!empty($id_theme)) { $id_theme = (int) $id_theme; } elseif (!empty($_REQUEST['theme']) && (!empty($modSettings['theme_allow']) || allowedTo('admin_forum'))) { $id_theme = (int) $_REQUEST['theme']; $_SESSION['id_theme'] = $id_theme; } elseif (!empty($_SESSION['id_theme']) && (!empty($modSettings['theme_allow']) || allowedTo('admin_forum'))) { $id_theme = (int) $_SESSION['id_theme']; } elseif (!empty($user_info['theme']) && !isset($_REQUEST['theme']) && (!empty($modSettings['theme_allow']) || allowedTo('admin_forum'))) { $id_theme = $user_info['theme']; } elseif (!empty($board_info['theme'])) { $id_theme = $board_info['theme']; } else { $id_theme = $modSettings['theme_guests']; } // Verify the id_theme... no foul play. // Always allow the board specific theme, if they are overriding. if (!empty($board_info['theme']) && $board_info['override_theme']) { $id_theme = $board_info['theme']; } elseif (!empty($ssi_theme) && $id_theme == $ssi_theme) { $id_theme = (int) $id_theme; } elseif (!empty($modSettings['knownThemes']) && !allowedTo('admin_forum')) { $themes = explode(',', $modSettings['knownThemes']); if (!in_array($id_theme, $themes)) { $id_theme = $modSettings['theme_guests']; } else { $id_theme = (int) $id_theme; } } else { $id_theme = (int) $id_theme; } $member = empty($user_info['id']) ? -1 : $user_info['id']; // Do we already have this members theme data and specific options loaded (for agressive cache settings) if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2 && ($temp = cache_get_data('theme_settings-' . $id_theme . ':' . $member, 60)) != null && time() - 60 > $modSettings['settings_updated']) { $themeData = $temp; $flag = true; } elseif (($temp = cache_get_data('theme_settings-' . $id_theme, 90)) != null && time() - 60 > $modSettings['settings_updated']) { $themeData = $temp + array($member => array()); } else { $themeData = array(-1 => array(), 0 => array(), $member => array()); } if (empty($flag)) { // Load variables from the current or default theme, global or this user's. $result = $db->query('', ' SELECT variable, value, id_member, id_theme FROM {db_prefix}themes WHERE id_member' . (empty($themeData[0]) ? ' IN (-1, 0, {int:id_member})' : ' = {int:id_member}') . ' AND id_theme' . ($id_theme == 1 ? ' = {int:id_theme}' : ' IN ({int:id_theme}, 1)'), array('id_theme' => $id_theme, 'id_member' => $member)); // Pick between $settings and $options depending on whose data it is. while ($row = $db->fetch_assoc($result)) { // There are just things we shouldn't be able to change as members. if ($row['id_member'] != 0 && in_array($row['variable'], array('actual_theme_url', 'actual_images_url', 'base_theme_dir', 'base_theme_url', 'default_images_url', 'default_theme_dir', 'default_theme_url', 'default_template', 'images_url', 'number_recent_posts', 'smiley_sets_default', 'theme_dir', 'theme_id', 'theme_layers', 'theme_templates', 'theme_url'))) { continue; } // If this is the theme_dir of the default theme, store it. if (in_array($row['variable'], array('theme_dir', 'theme_url', 'images_url')) && $row['id_theme'] == '1' && empty($row['id_member'])) { $themeData[0]['default_' . $row['variable']] = $row['value']; } // If this isn't set yet, is a theme option, or is not the default theme.. if (!isset($themeData[$row['id_member']][$row['variable']]) || $row['id_theme'] != '1') { $themeData[$row['id_member']][$row['variable']] = substr($row['variable'], 0, 5) == 'show_' ? $row['value'] == '1' : $row['value']; } } $db->free_result($result); // Set the defaults if the user has not chosen on their own if (!empty($themeData[-1])) { foreach ($themeData[-1] as $k => $v) { if (!isset($themeData[$member][$k])) { $themeData[$member][$k] = $v; } } } // If being aggressive we save the site wide and member theme settings if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2) { cache_put_data('theme_settings-' . $id_theme . ':' . $member, $themeData, 60); } elseif (!isset($temp)) { cache_put_data('theme_settings-' . $id_theme, array(-1 => $themeData[-1], 0 => $themeData[0]), 90); } } $settings = $themeData[0]; $options = $themeData[$member]; $settings['theme_id'] = $id_theme; $settings['actual_theme_url'] = $settings['theme_url']; $settings['actual_images_url'] = $settings['images_url']; $settings['actual_theme_dir'] = $settings['theme_dir']; $settings['template_dirs'] = array(); // This theme first. $settings['template_dirs'][] = $settings['theme_dir']; // Based on theme (if there is one). if (!empty($settings['base_theme_dir'])) { $settings['template_dirs'][] = $settings['base_theme_dir']; } // Lastly the default theme. if ($settings['theme_dir'] != $settings['default_theme_dir']) { $settings['template_dirs'][] = $settings['default_theme_dir']; } if (!$initialize) { return; } // Check to see if they're accessing it from the wrong place. if (isset($_SERVER['HTTP_HOST']) || isset($_SERVER['SERVER_NAME'])) { $detected_url = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 'https://' : 'http://'; $detected_url .= empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] . (empty($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] == '80' ? '' : ':' . $_SERVER['SERVER_PORT']) : $_SERVER['HTTP_HOST']; $temp = preg_replace('~/' . basename($scripturl) . '(/.+)?$~', '', strtr(dirname($_SERVER['PHP_SELF']), '\\', '/')); if ($temp != '/') { $detected_url .= $temp; } } if (isset($detected_url) && $detected_url != $boardurl) { // Try #1 - check if it's in a list of alias addresses. if (!empty($modSettings['forum_alias_urls'])) { $aliases = explode(',', $modSettings['forum_alias_urls']); foreach ($aliases as $alias) { // Rip off all the boring parts, spaces, etc. if ($detected_url == trim($alias) || strtr($detected_url, array('http://' => '', 'https://' => '')) == trim($alias)) { $do_fix = true; } } } // Hmm... check #2 - is it just different by a www? Send them to the correct place!! if (empty($do_fix) && strtr($detected_url, array('://' => '://www.')) == $boardurl && (empty($_GET) || count($_GET) == 1) && ELK != 'SSI') { // Okay, this seems weird, but we don't want an endless loop - this will make $_GET not empty ;). if (empty($_GET)) { redirectexit('wwwRedirect'); } else { list($k, $v) = each($_GET); if ($k != 'wwwRedirect') { redirectexit('wwwRedirect;' . $k . '=' . $v); } } } // #3 is just a check for SSL... if (strtr($detected_url, array('https://' => 'http://')) == $boardurl) { $do_fix = true; } // Okay, #4 - perhaps it's an IP address? We're gonna want to use that one, then. (assuming it's the IP or something...) if (!empty($do_fix) || preg_match('~^http[s]?://(?:[\\d\\.:]+|\\[[\\d:]+\\](?::\\d+)?)(?:$|/)~', $detected_url) == 1) { // Caching is good ;). $oldurl = $boardurl; // Fix $boardurl and $scripturl. $boardurl = $detected_url; $scripturl = strtr($scripturl, array($oldurl => $boardurl)); $_SERVER['REQUEST_URL'] = strtr($_SERVER['REQUEST_URL'], array($oldurl => $boardurl)); // Fix the theme urls... $settings['theme_url'] = strtr($settings['theme_url'], array($oldurl => $boardurl)); $settings['default_theme_url'] = strtr($settings['default_theme_url'], array($oldurl => $boardurl)); $settings['actual_theme_url'] = strtr($settings['actual_theme_url'], array($oldurl => $boardurl)); $settings['images_url'] = strtr($settings['images_url'], array($oldurl => $boardurl)); $settings['default_images_url'] = strtr($settings['default_images_url'], array($oldurl => $boardurl)); $settings['actual_images_url'] = strtr($settings['actual_images_url'], array($oldurl => $boardurl)); // And just a few mod settings :). $modSettings['smileys_url'] = strtr($modSettings['smileys_url'], array($oldurl => $boardurl)); $modSettings['avatar_url'] = strtr($modSettings['avatar_url'], array($oldurl => $boardurl)); // Clean up after loadBoard(). if (isset($board_info['moderators'])) { foreach ($board_info['moderators'] as $k => $dummy) { $board_info['moderators'][$k]['href'] = strtr($dummy['href'], array($oldurl => $boardurl)); $board_info['moderators'][$k]['link'] = strtr($dummy['link'], array('"' . $oldurl => '"' . $boardurl)); } } foreach ($context['linktree'] as $k => $dummy) { $context['linktree'][$k]['url'] = strtr($dummy['url'], array($oldurl => $boardurl)); } } } // Set up the contextual user array. $context['user'] = array('id' => $user_info['id'], 'is_logged' => !$user_info['is_guest'], 'is_guest' => &$user_info['is_guest'], 'is_admin' => &$user_info['is_admin'], 'is_mod' => &$user_info['is_mod'], 'is_moderator' => &$user_info['is_moderator'], 'can_mod' => allowedTo('access_mod_center') || !$user_info['is_guest'] && ($user_info['mod_cache']['gq'] != '0=1' || $user_info['mod_cache']['bq'] != '0=1' || $modSettings['postmod_active'] && !empty($user_info['mod_cache']['ap'])), 'username' => $user_info['username'], 'language' => $user_info['language'], 'email' => $user_info['email'], 'ignoreusers' => $user_info['ignoreusers']); // Something for the guests if (!$context['user']['is_guest']) { $context['user']['name'] = $user_info['name']; } elseif ($context['user']['is_guest'] && !empty($txt['guest_title'])) { $context['user']['name'] = $txt['guest_title']; } // Set up some additional interface preference context $context['admin_preferences'] = !empty($options['admin_preferences']) ? unserialize($options['admin_preferences']) : array(); if (!$user_info['is_guest']) { $context['minmax_preferences'] = !empty($options['minmax_preferences']) ? unserialize($options['minmax_preferences']) : array(); } elseif ($user_info['is_guest'] && isset($_COOKIE['upshrink'])) { $context['minmax_preferences'] = array('upshrink' => $_COOKIE['upshrink']); } // Determine the current smiley set. $user_info['smiley_set'] = !in_array($user_info['smiley_set'], explode(',', $modSettings['smiley_sets_known'])) && $user_info['smiley_set'] != 'none' || empty($modSettings['smiley_sets_enable']) ? !empty($settings['smiley_sets_default']) ? $settings['smiley_sets_default'] : $modSettings['smiley_sets_default'] : $user_info['smiley_set']; $context['user']['smiley_set'] = $user_info['smiley_set']; // Some basic information... if (!isset($context['html_headers'])) { $context['html_headers'] = ''; } if (!isset($context['links'])) { $context['links'] = array(); } if (!isset($context['javascript_files'])) { $context['javascript_files'] = array(); } if (!isset($context['css_files'])) { $context['css_files'] = array(); } if (!isset($context['javascript_inline'])) { $context['javascript_inline'] = array('standard' => array(), 'defer' => array()); } if (!isset($context['javascript_vars'])) { $context['javascript_vars'] = array(); } $context['menu_separator'] = !empty($settings['use_image_buttons']) ? ' ' : ' | '; $context['session_var'] = $_SESSION['session_var']; $context['session_id'] = $_SESSION['session_value']; $context['forum_name'] = $mbname; $context['forum_name_html_safe'] = $context['forum_name']; $context['current_action'] = isset($_REQUEST['action']) ? $_REQUEST['action'] : null; $context['current_subaction'] = isset($_REQUEST['sa']) ? $_REQUEST['sa'] : null; $context['can_register'] = empty($modSettings['registration_method']) || $modSettings['registration_method'] != 3; foreach (array('theme_header', 'upper_content') as $call) { if (!isset($context[$call . '_callbacks'])) { $context[$call . '_callbacks'] = array(); } } // Set some permission related settings. if ($user_info['is_guest'] && !empty($modSettings['enableVBStyleLogin'])) { $context['show_login_bar'] = true; $context['theme_header_callbacks'][] = 'login_bar'; loadJavascriptFile('sha256.js', array('defer' => true)); } // This determines the server... not used in many places, except for login fixing. detectServer(); // Detect the browser. This is separated out because it's also used in attachment downloads detectBrowser(); // Set the top level linktree up. array_unshift($context['linktree'], array('url' => $scripturl, 'name' => $context['forum_name'])); // This allows sticking some HTML on the page output - useful for controls. $context['insert_after_template'] = ''; // Just some mobile-friendly settings if ($context['browser_body_id'] == 'mobile') { // Disable the preview text. $modSettings['message_index_preview'] = 0; // Force the usage of click menu instead of a hover menu. $options['use_click_menu'] = 1; // No space left for a sidebar $options['use_sidebar_menu'] = false; // Disable the search dropdown. $modSettings['search_dropdown'] = false; } if (!isset($txt)) { $txt = array(); } $simpleActions = array('findmember', 'quickhelp', 'printpage', 'quotefast', 'spellcheck'); call_integration_hook('integrate_simple_actions', array(&$simpleActions)); // Output is fully XML, so no need for the index template. if (isset($_REQUEST['xml'])) { loadLanguage('index+Addons'); // @todo added because some $settings in template_init are necessary even in xml mode. Maybe move template_init to a settings file? loadTemplate('index'); loadTemplate('Xml'); Template_Layers::getInstance()->removeAll(); } elseif (!empty($_REQUEST['action']) && in_array($_REQUEST['action'], $simpleActions)) { loadLanguage('index+Addons'); Template_Layers::getInstance()->removeAll(); } else { // Custom templates to load, or just default? if (isset($settings['theme_templates'])) { $templates = explode(',', $settings['theme_templates']); } else { $templates = array('index'); } // Load each template... foreach ($templates as $template) { loadTemplate($template); } // ...and attempt to load their associated language files. $required_files = implode('+', array_merge($templates, array('Addons'))); loadLanguage($required_files, '', false); // Custom template layers? if (isset($settings['theme_layers'])) { $layers = explode(',', $settings['theme_layers']); } else { $layers = array('html', 'body'); } $template_layers = Template_Layers::getInstance(true); foreach ($layers as $layer) { $template_layers->addBegin($layer); } } // Initialize the theme. if (function_exists('template_init')) { $settings = array_merge($settings, template_init()); } // Call initialization theme integration functions. call_integration_hook('integrate_init_theme', array($id_theme, &$settings)); // Guests may still need a name. if ($context['user']['is_guest'] && empty($context['user']['name'])) { $context['user']['name'] = $txt['guest_title']; } // Any theme-related strings that need to be loaded? if (!empty($settings['require_theme_strings'])) { loadLanguage('ThemeStrings', '', false); } // Load font Awesome fonts loadCSSFile('font-awesome.min.css'); // We allow theme variants, because we're cool. $context['theme_variant'] = ''; $context['theme_variant_url'] = ''; if (!empty($settings['theme_variants'])) { // Overriding - for previews and that ilk. if (!empty($_REQUEST['variant'])) { $_SESSION['id_variant'] = $_REQUEST['variant']; } // User selection? if (empty($settings['disable_user_variant']) || allowedTo('admin_forum')) { $context['theme_variant'] = !empty($_SESSION['id_variant']) ? $_SESSION['id_variant'] : (!empty($options['theme_variant']) ? $options['theme_variant'] : ''); } // If not a user variant, select the default. if ($context['theme_variant'] == '' || !in_array($context['theme_variant'], $settings['theme_variants'])) { $context['theme_variant'] = !empty($settings['default_variant']) && in_array($settings['default_variant'], $settings['theme_variants']) ? $settings['default_variant'] : $settings['theme_variants'][0]; } // Do this to keep things easier in the templates. $context['theme_variant'] = '_' . $context['theme_variant']; $context['theme_variant_url'] = $context['theme_variant'] . '/'; // The most efficient way of writing multi themes is to use a master index.css plus variant.css files. if (!empty($context['theme_variant'])) { loadCSSFile($context['theme_variant'] . '/index' . $context['theme_variant'] . '.css'); } } // A bit lonely maybe, though I think it should be set up *after* teh theme variants detection $context['header_logo_url_html_safe'] = empty($settings['header_logo_url']) ? $settings['images_url'] . '/' . $context['theme_variant_url'] . 'logo_elk.png' : Util::htmlspecialchars($settings['header_logo_url']); // Allow overriding the board wide time/number formats. if (empty($user_settings['time_format']) && !empty($txt['time_format'])) { $user_info['time_format'] = $txt['time_format']; } if (isset($settings['use_default_images']) && $settings['use_default_images'] == 'always') { $settings['theme_url'] = $settings['default_theme_url']; $settings['images_url'] = $settings['default_images_url']; $settings['theme_dir'] = $settings['default_theme_dir']; } // Make a special URL for the language. $settings['lang_images_url'] = $settings['images_url'] . '/' . (!empty($txt['image_lang']) ? $txt['image_lang'] : $user_info['language']); // Set a couple of bits for the template. $context['right_to_left'] = !empty($txt['lang_rtl']); $context['tabindex'] = 1; // RTL languages require an additional stylesheet. if ($context['right_to_left']) { loadCSSFile('rtl.css'); } if (!empty($context['theme_variant']) && $context['right_to_left']) { loadCSSFile($context['theme_variant'] . '/rtl' . $context['theme_variant'] . '.css'); } // Compatibility. if (!isset($settings['theme_version'])) { $modSettings['memberCount'] = $modSettings['totalMembers']; } // This allows us to change the way things look for the admin. $context['admin_features'] = isset($modSettings['admin_features']) ? explode(',', $modSettings['admin_features']) : array('cd,cp,k,w,rg,ml,pm'); if (!empty($modSettings['xmlnews_enable']) && (!empty($modSettings['allow_guestAccess']) || $context['user']['is_logged'])) { $context['newsfeed_urls'] = array('rss' => $scripturl . '?action=.xml;type=rss2;limit=' . (!empty($modSettings['xmlnews_limit']) ? $modSettings['xmlnews_limit'] : 5), 'atom' => $scripturl . '?action=.xml;type=atom;limit=' . (!empty($modSettings['xmlnews_limit']) ? $modSettings['xmlnews_limit'] : 5)); } // Default JS variables for use in every theme addJavascriptVar(array('elk_theme_url' => JavaScriptEscape($settings['theme_url']), 'elk_default_theme_url' => JavaScriptEscape($settings['default_theme_url']), 'elk_images_url' => JavaScriptEscape($settings['images_url']), 'elk_smiley_url' => JavaScriptEscape($modSettings['smileys_url']), 'elk_scripturl' => '\'' . $scripturl . '\'', 'elk_iso_case_folding' => $context['server']['iso_case_folding'] ? 'true' : 'false', 'elk_charset' => '"UTF-8"', 'elk_session_id' => JavaScriptEscape($context['session_id']), 'elk_session_var' => JavaScriptEscape($context['session_var']), 'elk_member_id' => $context['user']['id'], 'ajax_notification_text' => JavaScriptEscape($txt['ajax_in_progress']), 'ajax_notification_cancel_text' => JavaScriptEscape($txt['modify_cancel']), 'help_popup_heading_text' => JavaScriptEscape($txt['help_popup']), 'use_click_menu' => !empty($options['use_click_menu']) ? 'true' : 'false', 'todayMod' => !empty($modSettings['todayMod']) ? (int) $modSettings['todayMod'] : 0)); // Auto video embeding enabled, then load the needed JS if (!empty($modSettings['enableVideoEmbeding'])) { addInlineJavascript(' var oEmbedtext = ({ preview_image : ' . JavaScriptEscape($txt['preview_image']) . ', ctp_video : ' . JavaScriptEscape($txt['ctp_video']) . ', hide_video : ' . JavaScriptEscape($txt['hide_video']) . ', youtube : ' . JavaScriptEscape($txt['youtube']) . ', vimeo : ' . JavaScriptEscape($txt['vimeo']) . ', dailymotion : ' . JavaScriptEscape($txt['dailymotion']) . ' });', true); loadJavascriptFile('elk_jquery_embed.js', array('defer' => true)); } // Prettify code tags? Load the needed JS and CSS. if (!empty($modSettings['enableCodePrettify'])) { loadCSSFile('prettify.css'); loadJavascriptFile('prettify.min.js', array('defer' => true)); addInlineJavascript(' $(document).ready(function(){ prettyPrint(); });', true); } // Relative times? if (!empty($modSettings['todayMod']) && $modSettings['todayMod'] > 2) { addInlineJavascript(' var oRttime = ({ referenceTime : ' . forum_time() * 1000 . ', now : ' . JavaScriptEscape($txt['rt_now']) . ', minute : ' . JavaScriptEscape($txt['rt_minute']) . ', minutes : ' . JavaScriptEscape($txt['rt_minutes']) . ', hour : ' . JavaScriptEscape($txt['rt_hour']) . ', hours : ' . JavaScriptEscape($txt['rt_hours']) . ', day : ' . JavaScriptEscape($txt['rt_day']) . ', days : ' . JavaScriptEscape($txt['rt_days']) . ', week : ' . JavaScriptEscape($txt['rt_week']) . ', weeks : ' . JavaScriptEscape($txt['rt_weeks']) . ', month : ' . JavaScriptEscape($txt['rt_month']) . ', months : ' . JavaScriptEscape($txt['rt_months']) . ', year : ' . JavaScriptEscape($txt['rt_year']) . ', years : ' . JavaScriptEscape($txt['rt_years']) . ', }); updateRelativeTime();', true); $context['using_relative_time'] = true; } // Queue our Javascript loadJavascriptFile(array('elk_jquery_plugins.js', 'script.js', 'script_elk.js', 'theme.js')); // If we think we have mail to send, let's offer up some possibilities... robots get pain (Now with scheduled task support!) if (!empty($modSettings['mail_next_send']) && $modSettings['mail_next_send'] < time() && empty($modSettings['mail_queue_use_cron']) || empty($modSettings['next_task_time']) || $modSettings['next_task_time'] < time()) { if (isBrowser('possibly_robot')) { // @todo Maybe move this somewhere better?! require_once CONTROLLERDIR . '/ScheduledTasks.controller.php'; $controller = new ScheduledTasks_Controller(); // What to do, what to do?! if (empty($modSettings['next_task_time']) || $modSettings['next_task_time'] < time()) { $controller->action_autotask(); } else { $controller->action_reducemailqueue(); } } else { $type = empty($modSettings['next_task_time']) || $modSettings['next_task_time'] < time() ? 'task' : 'mailq'; $ts = $type == 'mailq' ? $modSettings['mail_next_send'] : $modSettings['next_task_time']; addInlineJavascript(' function elkAutoTask() { var tempImage = new Image(); tempImage.src = elk_scripturl + "?scheduled=' . $type . ';ts=' . $ts . '"; } window.setTimeout("elkAutoTask();", 1);', true); } } // Any files to include at this point? call_integration_include_hook('integrate_theme_include'); // Call load theme integration functions. call_integration_hook('integrate_load_theme'); // We are ready to go. $context['theme_loaded'] = true; }
/** * Add/Edit/Delete profiles. */ public function action_profiles() { global $context, $txt; require_once SUBSDIR . '/ManagePermissions.subs.php'; // Setup the template, first for fun. $context['page_title'] = $txt['permissions_profile_edit']; $context['sub_template'] = 'edit_profiles'; // If we're creating a new one do it first. if (isset($_POST['create']) && trim($_POST['profile_name']) != '') { checkSession(); validateToken('admin-mpp'); copyPermissionProfile($_POST['profile_name'], (int) $_POST['copy_from']); } elseif (isset($_POST['rename'])) { checkSession(); validateToken('admin-mpp'); // Just showing the boxes? if (!isset($_POST['rename_profile'])) { $context['show_rename_boxes'] = true; } else { foreach ($_POST['rename_profile'] as $id => $name) { renamePermissionProfile($id, $name); } } } elseif (isset($_POST['delete']) && !empty($_POST['delete_profile'])) { checkSession('post'); validateToken('admin-mpp'); $profiles = array(); foreach ($_POST['delete_profile'] as $profile) { if ($profile > 4) { $profiles[] = (int) $profile; } } deletePermissionProfiles($profiles); } // Clearly, we'll need this! loadPermissionProfiles(); // Work out what ones are in use. $context['profiles'] = permProfilesInUse($context['profiles']); // What can we do with these? $context['can_edit_something'] = false; foreach ($context['profiles'] as $id => $profile) { // Can't delete special ones. $context['profiles'][$id]['can_edit'] = isset($txt['permissions_profile_' . $profile['unformatted_name']]) ? false : true; if ($context['profiles'][$id]['can_edit']) { $context['can_edit_something'] = true; } // You can only delete it if you can edit it AND it's not in use. $context['profiles'][$id]['can_delete'] = $context['profiles'][$id]['can_edit'] && empty($profile['in_use']) ? true : false; } addJavascriptVar(array('txt_permissions_commit' => $txt['permissions_commit'], 'txt_permissions_profile_rename' => $txt['permissions_profile_rename']), true); createToken('admin-mpp'); }
/** * This function handles submission of a template file. * It checks the file for syntax errors, and if it passes, it saves it. * * This function is forwarded to, from * ?action=admin;area=theme;sa=edit */ private function _action_edit_submit() { global $context, $settings; $selectedTheme = isset($_GET['th']) ? (int) $_GET['th'] : (isset($_GET['id']) ? (int) $_GET['id'] : 0); if (empty($selectedTheme)) { // This should never be happening. Never I say. But... in case it does :P fatal_lang_error('theme_edit_missing'); } $theme_dir = themeDirectory($context['theme_id']); $file = isset($_POST['entire_file']) ? $_POST['entire_file'] : ''; // You did submit *something*, didn't you? if (empty($file)) { // @todo a better error message fatal_lang_error('theme_edit_missing'); } // Checking PHP syntax on css files is not a most constructive use of processing power :P // We need to know what kind of file we have $is_php = substr($_REQUEST['filename'], -4) == '.php'; $is_template = substr($_REQUEST['filename'], -13) == '.template.php'; $is_css = substr($_REQUEST['filename'], -4) == '.css'; // Check you up if (checkSession('post', '', false) == '' && validateToken('admin-te-' . md5($selectedTheme . '-' . $_REQUEST['filename']), 'post', false) == true) { // Consolidate the format in which we received the file contents if (is_array($file)) { $entire_file = implode("\n", $file); } else { $entire_file = $file; } // Convert our tabs back to tabs! $entire_file = rtrim(strtr($entire_file, array("\r" => '', ' ' => "\t"))); // Errors? No errors! $errors = array(); // For PHP files, we check the syntax. if ($is_php) { require_once SUBSDIR . '/DataValidator.class.php'; $validator = new Data_Validator(); $validator->validation_rules(array('entire_file' => 'php_syntax')); $validator->validate(array('entire_file' => $entire_file)); // Retrieve the errors $errors = $validator->validation_errors(); } // If successful so far, we'll take the plunge and save this piece of art. if (empty($errors)) { // Try to save the new file contents $fp = fopen($theme_dir . '/' . $_REQUEST['filename'], 'w'); fwrite($fp, $entire_file); fclose($fp); // We're done here. redirectexit('action=admin;area=theme;th=' . $selectedTheme . ';' . $context['session_var'] . '=' . $context['session_id'] . ';sa=browse;directory=' . dirname($_REQUEST['filename'])); } else { // Pick the right sub-template for the next try if ($is_template) { $context['sub_template'] = 'edit_template'; } else { $context['sub_template'] = 'edit_file'; } // Fill contextual data for the template, the errors to show foreach ($errors as $error) { $context['parse_error'][] = $error; } // The format of the data depends on template/non-template file. if (!is_array($file)) { $file = array($file); } // Send back the file contents $context['entire_file'] = htmlspecialchars(strtr(implode('', $file), array("\t" => ' ')), ENT_COMPAT, 'UTF-8'); foreach ($file as $i => $file_part) { $context['file_parts'][$i]['lines'] = strlen($file_part); $context['file_parts'][$i]['data'] = $file_part; } // Re-create token for another try createToken('admin-te-' . md5($selectedTheme . '-' . $_REQUEST['filename'])); return; } } else { loadLanguage('Errors'); // Notify the template of trouble $context['session_error'] = true; // Recycle the submitted data. if (is_array($file)) { $context['entire_file'] = htmlspecialchars(implode("\n", $file), ENT_COMPAT, 'UTF-8'); } else { $context['entire_file'] = htmlspecialchars($file, ENT_COMPAT, 'UTF-8'); } $context['edit_filename'] = htmlspecialchars($_POST['filename'], ENT_COMPAT, 'UTF-8'); // Choose sub-template if ($is_template) { $context['sub_template'] = 'edit_template'; } elseif ($is_css) { addJavascriptVar(array('previewData' => '\'\'', 'previewTimeout' => '\'\'', 'refreshPreviewCache' => '\'\'', 'editFilename' => JavaScriptEscape($context['edit_filename']), 'theme_id' => $settings['theme_id'])); $context['sub_template'] = 'edit_style'; } else { $context['sub_template'] = 'edit_file'; } // Re-create the token so that it can be used createToken('admin-te-' . md5($selectedTheme . '-' . $_REQUEST['filename'])); return; } }
/** * 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'; } }
/** * Show the list of topics in this board, along with any sub-boards. * @uses MessageIndex template topic_listing sub template */ public function action_messageindex() { global $txt, $scripturl, $board, $modSettings, $context; global $options, $settings, $board_info, $user_info; // Fairly often, we'll work with boards. Current board, sub-boards. require_once SUBSDIR . '/Boards.subs.php'; // If this is a redirection board head off. if ($board_info['redirect']) { incrementBoard($board, 'num_posts'); redirectexit($board_info['redirect']); } loadTemplate('MessageIndex'); loadJavascriptFile('topic.js'); $context['name'] = $board_info['name']; $context['sub_template'] = 'topic_listing'; $context['description'] = $board_info['description']; $template_layers = Template_Layers::getInstance(); // How many topics do we have in total? $board_info['total_topics'] = allowedTo('approve_posts') ? $board_info['num_topics'] + $board_info['unapproved_topics'] : $board_info['num_topics'] + $board_info['unapproved_user_topics']; // View all the topics, or just a few? $context['topics_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['topics_per_page']) ? $options['topics_per_page'] : $modSettings['defaultMaxTopics']; $context['messages_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) ? $options['messages_per_page'] : $modSettings['defaultMaxMessages']; $maxindex = isset($_REQUEST['all']) && !empty($modSettings['enableAllMessages']) ? $board_info['total_topics'] : $context['topics_per_page']; // Right, let's only index normal stuff! if (count($_GET) > 1) { $session_name = session_name(); foreach ($_GET as $k => $v) { if (!in_array($k, array('board', 'start', $session_name))) { $context['robot_no_index'] = true; } } } if (!empty($_REQUEST['start']) && (!is_numeric($_REQUEST['start']) || $_REQUEST['start'] % $context['messages_per_page'] != 0)) { $context['robot_no_index'] = true; } // If we can view unapproved messages and there are some build up a list. if (allowedTo('approve_posts') && ($board_info['unapproved_topics'] || $board_info['unapproved_posts'])) { $untopics = $board_info['unapproved_topics'] ? '<a href="' . $scripturl . '?action=moderate;area=postmod;sa=topics;brd=' . $board . '">' . $board_info['unapproved_topics'] . '</a>' : 0; $unposts = $board_info['unapproved_posts'] ? '<a href="' . $scripturl . '?action=moderate;area=postmod;sa=posts;brd=' . $board . '">' . ($board_info['unapproved_posts'] - $board_info['unapproved_topics']) . '</a>' : 0; $context['unapproved_posts_message'] = sprintf($txt['there_are_unapproved_topics'], $untopics, $unposts, $scripturl . '?action=moderate;area=postmod;sa=' . ($board_info['unapproved_topics'] ? 'topics' : 'posts') . ';brd=' . $board); } // We only know these. if (isset($_REQUEST['sort']) && !in_array($_REQUEST['sort'], array('subject', 'starter', 'last_poster', 'replies', 'views', 'likes', 'first_post', 'last_post'))) { $_REQUEST['sort'] = 'last_post'; } // Make sure the starting place makes sense and construct the page index. if (isset($_REQUEST['sort'])) { $sort_string = ';sort=' . $_REQUEST['sort'] . (isset($_REQUEST['desc']) ? ';desc' : ''); } else { $sort_string = ''; } $context['page_index'] = constructPageIndex($scripturl . '?board=' . $board . '.%1$d' . $sort_string, $_REQUEST['start'], $board_info['total_topics'], $maxindex, true); $context['start'] =& $_REQUEST['start']; // Set a canonical URL for this page. $context['canonical_url'] = $scripturl . '?board=' . $board . '.' . $context['start']; $context['links'] += array('prev' => $_REQUEST['start'] >= $context['topics_per_page'] ? $scripturl . '?board=' . $board . '.' . ($_REQUEST['start'] - $context['topics_per_page']) : '', 'next' => $_REQUEST['start'] + $context['topics_per_page'] < $board_info['total_topics'] ? $scripturl . '?board=' . $board . '.' . ($_REQUEST['start'] + $context['topics_per_page']) : ''); $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['topics_per_page'] + 1, 'num_pages' => floor(($board_info['total_topics'] - 1) / $context['topics_per_page']) + 1); if (isset($_REQUEST['all']) && !empty($modSettings['enableAllMessages']) && $maxindex > $modSettings['enableAllMessages']) { $maxindex = $modSettings['enableAllMessages']; $_REQUEST['start'] = 0; } // Build a list of the board's moderators. $context['moderators'] =& $board_info['moderators']; $context['link_moderators'] = array(); if (!empty($board_info['moderators'])) { foreach ($board_info['moderators'] as $mod) { $context['link_moderators'][] = '<a href="' . $scripturl . '?action=profile;u=' . $mod['id'] . '" title="' . $txt['board_moderator'] . '">' . $mod['name'] . '</a>'; } } // Mark current and parent boards as seen. if (!$user_info['is_guest']) { // We can't know they read it if we allow prefetches. if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') { @ob_end_clean(); header('HTTP/1.1 403 Prefetch Forbidden'); die; } // Mark the board as read, and its parents. if (!empty($board_info['parent_boards'])) { $board_list = array_keys($board_info['parent_boards']); $board_list[] = $board; } else { $board_list = array($board); } // Mark boards as read. Boards alone, no need for topics. markBoardsRead($board_list, false, false); // Clear topicseen cache if (!empty($board_info['parent_boards'])) { // We've seen all these boards now! foreach ($board_info['parent_boards'] as $k => $dummy) { if (isset($_SESSION['topicseen_cache'][$k])) { unset($_SESSION['topicseen_cache'][$k]); } } } if (isset($_SESSION['topicseen_cache'][$board])) { unset($_SESSION['topicseen_cache'][$board]); } // From now on, they've seen it. So we reset notifications. $context['is_marked_notify'] = resetSentBoardNotification($user_info['id'], $board); } else { $context['is_marked_notify'] = false; } // 'Print' the header and board info. $context['page_title'] = strip_tags($board_info['name']); // Set the variables up for the template. $context['can_mark_notify'] = allowedTo('mark_notify') && !$user_info['is_guest']; $context['can_post_new'] = allowedTo('post_new') || $modSettings['postmod_active'] && allowedTo('post_unapproved_topics'); $context['can_post_poll'] = !empty($modSettings['pollMode']) && allowedTo('poll_post') && $context['can_post_new']; $context['can_moderate_forum'] = allowedTo('moderate_forum'); $context['can_approve_posts'] = allowedTo('approve_posts'); // Prepare sub-boards for display. require_once SUBSDIR . '/BoardsList.class.php'; $boardIndexOptions = array('include_categories' => false, 'base_level' => $board_info['child_level'] + 1, 'parent_id' => $board_info['id'], 'set_latest_post' => false, 'countChildPosts' => !empty($modSettings['countChildPosts'])); $boardlist = new Boards_List($boardIndexOptions); $context['boards'] = $boardlist->getBoards(); // Nosey, nosey - who's viewing this board? if (!empty($settings['display_who_viewing'])) { require_once SUBSDIR . '/Who.subs.php'; formatViewers($board, 'board'); } // And now, what we're here for: topics! require_once SUBSDIR . '/MessageIndex.subs.php'; // Known sort methods. $sort_methods = messageIndexSort(); // They didn't pick one, default to by last post descending. if (!isset($_REQUEST['sort']) || !isset($sort_methods[$_REQUEST['sort']])) { $context['sort_by'] = 'last_post'; $ascending = isset($_REQUEST['asc']); } else { $context['sort_by'] = $_REQUEST['sort']; $ascending = !isset($_REQUEST['desc']); } $sort_column = $sort_methods[$context['sort_by']]; $context['sort_direction'] = $ascending ? 'up' : 'down'; $context['sort_title'] = $ascending ? $txt['sort_desc'] : $txt['sort_asc']; // Trick $txt['starter'] = $txt['started_by']; foreach ($sort_methods as $key => $val) { $context['topics_headers'][$key] = array('url' => $scripturl . '?board=' . $context['current_board'] . '.' . $context['start'] . ';sort=' . $key . ($context['sort_by'] == $key && $context['sort_direction'] == 'up' ? ';desc' : ''), 'sort_dir_img' => $context['sort_by'] == $key ? '<img class="sort" src="' . $settings['images_url'] . '/sort_' . $context['sort_direction'] . '.png" alt="" title="' . $context['sort_title'] . '" />' : ''); } // Calculate the fastest way to get the topics. $start = (int) $_REQUEST['start']; if ($start > ($board_info['total_topics'] - 1) / 2) { $ascending = !$ascending; $fake_ascending = true; $maxindex = $board_info['total_topics'] < $start + $maxindex + 1 ? $board_info['total_topics'] - $start : $maxindex; $start = $board_info['total_topics'] < $start + $maxindex + 1 ? 0 : $board_info['total_topics'] - $start - $maxindex; } else { $fake_ascending = false; } // Setup the default topic icons... $context['icon_sources'] = MessageTopicIcons(); $topic_ids = array(); $context['topics'] = array(); // Set up the query options $indexOptions = array('include_sticky' => !empty($modSettings['enableStickyTopics']), 'only_approved' => $modSettings['postmod_active'] && !allowedTo('approve_posts'), 'previews' => !empty($modSettings['message_index_preview']) ? empty($modSettings['preview_characters']) ? -1 : $modSettings['preview_characters'] : 0, 'include_avatars' => !empty($settings['avatars_on_indexes']), 'ascending' => $ascending, 'fake_ascending' => $fake_ascending); // Allow integration to modify / add to the $indexOptions call_integration_hook('integrate_messageindex_topics', array(&$sort_column, &$indexOptions)); $topics_info = messageIndexTopics($board, $user_info['id'], $start, $maxindex, $context['sort_by'], $sort_column, $indexOptions); // Prepare for links to guests (for search engines) $context['pageindex_multiplier'] = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) ? $options['messages_per_page'] : $modSettings['defaultMaxMessages']; // Begin 'printing' the message index for current board. foreach ($topics_info as $row) { $topic_ids[] = $row['id_topic']; // Do they want message previews? if (!empty($modSettings['message_index_preview'])) { // Limit them to $modSettings['preview_characters'] characters $row['first_body'] = strip_tags(strtr(parse_bbc($row['first_body'], false, $row['id_first_msg']), array('<br />' => "\n", ' ' => ' '))); $row['first_body'] = Util::shorten_text($row['first_body'], !empty($modSettings['preview_characters']) ? $modSettings['preview_characters'] : 128, true); // No reply then they are the same, no need to process it again if ($row['num_replies'] == 0) { $row['last_body'] == $row['first_body']; } else { $row['last_body'] = strip_tags(strtr(parse_bbc($row['last_body'], false, $row['id_last_msg']), array('<br />' => "\n", ' ' => ' '))); $row['last_body'] = Util::shorten_text($row['last_body'], !empty($modSettings['preview_characters']) ? $modSettings['preview_characters'] : 128, true); } // Censor the subject and message preview. censorText($row['first_subject']); censorText($row['first_body']); // Don't censor them twice! if ($row['id_first_msg'] == $row['id_last_msg']) { $row['last_subject'] = $row['first_subject']; $row['last_body'] = $row['first_body']; } else { censorText($row['last_subject']); censorText($row['last_body']); } } else { $row['first_body'] = ''; $row['last_body'] = ''; censorText($row['first_subject']); if ($row['id_first_msg'] == $row['id_last_msg']) { $row['last_subject'] = $row['first_subject']; } else { censorText($row['last_subject']); } } // Decide how many pages the topic should have. if ($row['num_replies'] + 1 > $context['messages_per_page']) { // We can't pass start by reference. $start = -1; $pages = constructPageIndex($scripturl . '?topic=' . $row['id_topic'] . '.%1$d', $start, $row['num_replies'] + 1, $context['messages_per_page'], true, array('prev_next' => false, 'all' => !empty($modSettings['enableAllMessages']) && $row['num_replies'] + 1 < $modSettings['enableAllMessages'])); } else { $pages = ''; } // We need to check the topic icons exist... if (!empty($modSettings['messageIconChecks_enable'])) { if (!isset($context['icon_sources'][$row['first_icon']])) { $context['icon_sources'][$row['first_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['first_icon'] . '.png') ? 'images_url' : 'default_images_url'; } if (!isset($context['icon_sources'][$row['last_icon']])) { $context['icon_sources'][$row['last_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['last_icon'] . '.png') ? 'images_url' : 'default_images_url'; } } else { if (!isset($context['icon_sources'][$row['first_icon']])) { $context['icon_sources'][$row['first_icon']] = 'images_url'; } if (!isset($context['icon_sources'][$row['last_icon']])) { $context['icon_sources'][$row['last_icon']] = 'images_url'; } } // 'Print' the topic info. $context['topics'][$row['id_topic']] = array('id' => $row['id_topic'], 'first_post' => array('id' => $row['id_first_msg'], 'member' => array('username' => $row['first_member_name'], 'name' => $row['first_display_name'], 'id' => $row['first_id_member'], 'href' => !empty($row['first_id_member']) ? $scripturl . '?action=profile;u=' . $row['first_id_member'] : '', 'link' => !empty($row['first_id_member']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['first_id_member'] . '" title="' . $txt['profile_of'] . ' ' . $row['first_display_name'] . '" class="preview">' . $row['first_display_name'] . '</a>' : $row['first_display_name']), 'time' => standardTime($row['first_poster_time']), 'html_time' => htmlTime($row['first_poster_time']), 'timestamp' => forum_time(true, $row['first_poster_time']), 'subject' => $row['first_subject'], 'preview' => trim($row['first_body']), 'icon' => $row['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['first_icon']]] . '/post/' . $row['first_icon'] . '.png', 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.0', 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0">' . $row['first_subject'] . '</a>'), 'last_post' => array('id' => $row['id_last_msg'], 'member' => array('username' => $row['last_member_name'], 'name' => $row['last_display_name'], 'id' => $row['last_id_member'], 'href' => !empty($row['last_id_member']) ? $scripturl . '?action=profile;u=' . $row['last_id_member'] : '', 'link' => !empty($row['last_id_member']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['last_id_member'] . '">' . $row['last_display_name'] . '</a>' : $row['last_display_name']), 'time' => standardTime($row['last_poster_time']), 'html_time' => htmlTime($row['last_poster_time']), 'timestamp' => forum_time(true, $row['last_poster_time']), 'subject' => $row['last_subject'], 'preview' => trim($row['last_body']), 'icon' => $row['last_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['last_icon']]] . '/post/' . $row['last_icon'] . '.png', 'href' => $scripturl . '?topic=' . $row['id_topic'] . ($user_info['is_guest'] ? '.' . (int) ($row['num_replies'] / $context['pageindex_multiplier']) * $context['pageindex_multiplier'] . '#msg' . $row['id_last_msg'] : ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['id_last_msg']) . '#new'), 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . ($user_info['is_guest'] ? '.' . (int) ($row['num_replies'] / $context['pageindex_multiplier']) * $context['pageindex_multiplier'] . '#msg' . $row['id_last_msg'] : ($row['num_replies'] == 0 ? '.0' : '.msg' . $row['id_last_msg']) . '#new') . '" ' . ($row['num_replies'] == 0 ? '' : 'rel="nofollow"') . '>' . $row['last_subject'] . '</a>'), 'default_preview' => trim($row[!empty($modSettings['message_index_preview']) && $modSettings['message_index_preview'] == 2 ? 'last_body' : 'first_body']), 'is_sticky' => !empty($modSettings['enableStickyTopics']) && !empty($row['is_sticky']), 'is_locked' => !empty($row['locked']), 'is_poll' => !empty($modSettings['pollMode']) && $row['id_poll'] > 0, 'is_hot' => !empty($modSettings['useLikesNotViews']) ? $row['num_likes'] >= $modSettings['hotTopicPosts'] : $row['num_replies'] >= $modSettings['hotTopicPosts'], 'is_very_hot' => !empty($modSettings['useLikesNotViews']) ? $row['num_likes'] >= $modSettings['hotTopicVeryPosts'] : $row['num_replies'] >= $modSettings['hotTopicVeryPosts'], 'is_posted_in' => false, 'icon' => $row['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$row['first_icon']]] . '/post/' . $row['first_icon'] . '.png', 'subject' => $row['first_subject'], 'new' => $row['new_from'] <= $row['id_msg_modified'], 'new_from' => $row['new_from'], 'newtime' => $row['new_from'], 'new_href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['new_from'] . '#new', 'redir_href' => !empty($row['id_redirect_topic']) ? $scripturl . '?topic=' . $row['id_topic'] . '.0;noredir' : '', 'pages' => $pages, 'replies' => comma_format($row['num_replies']), 'views' => comma_format($row['num_views']), 'likes' => comma_format($row['num_likes']), 'approved' => $row['approved'], 'unapproved_posts' => $row['unapproved_posts']); if (!empty($settings['avatars_on_indexes'])) { $context['topics'][$row['id_topic']]['last_post']['member']['avatar'] = determineAvatar($row); } determineTopicClass($context['topics'][$row['id_topic']]); } // Allow addons to add to the $context['topics'] call_integration_hook('integrate_messageindex_listing', array($topics_info)); // Fix the sequence of topics if they were retrieved in the wrong order. (for speed reasons...) if ($fake_ascending) { $context['topics'] = array_reverse($context['topics'], true); } if (!empty($modSettings['enableParticipation']) && !$user_info['is_guest'] && !empty($topic_ids)) { $topics_participated_in = topicsParticipation($user_info['id'], $topic_ids); foreach ($topics_participated_in as $participated) { $context['topics'][$participated['id_topic']]['is_posted_in'] = true; $context['topics'][$participated['id_topic']]['class'] = 'my_' . $context['topics'][$participated['id_topic']]['class']; } } $context['jump_to'] = array('label' => addslashes(un_htmlspecialchars($txt['jump_to'])), 'board_name' => htmlspecialchars(strtr(strip_tags($board_info['name']), array('&' => '&')), ENT_COMPAT, 'UTF-8'), 'child_level' => $board_info['child_level']); // Is Quick Moderation active/needed? if (!empty($options['display_quick_mod']) && !empty($context['topics'])) { $context['can_markread'] = $context['user']['is_logged']; $context['can_lock'] = allowedTo('lock_any'); $context['can_sticky'] = allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']); $context['can_move'] = allowedTo('move_any'); $context['can_remove'] = allowedTo('remove_any'); $context['can_merge'] = allowedTo('merge_any'); // Ignore approving own topics as it's unlikely to come up... $context['can_approve'] = $modSettings['postmod_active'] && allowedTo('approve_posts') && !empty($board_info['unapproved_topics']); // Can we restore topics? $context['can_restore'] = allowedTo('move_any') && !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board; // Set permissions for all the topics. foreach ($context['topics'] as $t => $topic) { $started = $topic['first_post']['member']['id'] == $user_info['id']; $context['topics'][$t]['quick_mod'] = array('lock' => allowedTo('lock_any') || $started && allowedTo('lock_own'), 'sticky' => allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']), 'move' => allowedTo('move_any') || $started && allowedTo('move_own'), 'modify' => allowedTo('modify_any') || $started && allowedTo('modify_own'), 'remove' => allowedTo('remove_any') || $started && allowedTo('remove_own'), 'approve' => $context['can_approve'] && $topic['unapproved_posts']); $context['can_lock'] |= $started && allowedTo('lock_own'); $context['can_move'] |= $started && allowedTo('move_own'); $context['can_remove'] |= $started && allowedTo('remove_own'); } // Can we use quick moderation checkboxes? if ($options['display_quick_mod'] == 1) { $context['can_quick_mod'] = $context['user']['is_logged'] || $context['can_approve'] || $context['can_remove'] || $context['can_lock'] || $context['can_sticky'] || $context['can_move'] || $context['can_merge'] || $context['can_restore']; } else { $context['can_quick_mod'] = $context['can_remove'] || $context['can_lock'] || $context['can_sticky'] || $context['can_move']; } } if (!empty($context['can_quick_mod']) && $options['display_quick_mod'] == 1) { $context['qmod_actions'] = array('approve', 'remove', 'lock', 'sticky', 'move', 'merge', 'restore', 'markread'); call_integration_hook('integrate_quick_mod_actions'); } if (!empty($context['boards']) && $context['start'] == 0) { $template_layers->add('display_child_boards'); } // If there are children, but no topics and no ability to post topics... $context['no_topic_listing'] = !empty($context['boards']) && empty($context['topics']) && !$context['can_post_new']; $template_layers->add('topic_listing'); addJavascriptVar(array('notification_board_notice' => $context['is_marked_notify'] ? $txt['notification_disable_board'] : $txt['notification_enable_board']), true); // Build the message index button array. $context['normal_buttons'] = array('new_topic' => array('test' => 'can_post_new', 'text' => 'new_topic', 'image' => 'new_topic.png', 'lang' => true, 'url' => $scripturl . '?action=post;board=' . $context['current_board'] . '.0', 'active' => true), 'notify' => array('test' => 'can_mark_notify', 'text' => $context['is_marked_notify'] ? 'unnotify' : 'notify', 'image' => ($context['is_marked_notify'] ? 'un' : '') . 'notify.png', 'lang' => true, 'custom' => 'onclick="return notifyboardButton(this);"', 'url' => $scripturl . '?action=notifyboard;sa=' . ($context['is_marked_notify'] ? 'off' : 'on') . ';board=' . $context['current_board'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id'])); // They can only mark read if they are logged in and it's enabled! if (!$user_info['is_guest'] && $settings['show_mark_read']) { $context['normal_buttons']['markread'] = array('text' => 'mark_read_short', 'image' => 'markread.png', 'lang' => true, 'url' => $scripturl . '?action=markasread;sa=board;board=' . $context['current_board'] . '.0;' . $context['session_var'] . '=' . $context['session_id'], 'custom' => 'onclick="return markboardreadButton(this);"'); } // Allow adding new buttons easily. call_integration_hook('integrate_messageindex_buttons'); }
/** * List and allow adding/entering all man rules, such as * * What it does: * - If it itches, it will be scratched. * - Yes or No are perfectly acceptable answers to almost every question. * - Men see in only 16 colors, Peach, for example, is a fruit, not a color. * * @uses sub template rules */ public function action_manrules() { global $txt, $context, $user_info, $scripturl; require_once SUBSDIR . '/PersonalMessage.subs.php'; // The link tree - gotta have this :o $context['linktree'][] = array('url' => $scripturl . '?action=pm;sa=manrules', 'name' => $txt['pm_manage_rules']); $context['page_title'] = $txt['pm_manage_rules']; $context['sub_template'] = 'rules'; // Load them... load them!! loadRules(); // Likely to need all the groups! require_once SUBSDIR . '/Membergroups.subs.php'; $context['groups'] = accessibleGroups(); // Applying all rules? if (isset($_GET['apply'])) { checkSession('get'); applyRules(true); redirectexit('action=pm;sa=manrules'); } // Editing a specific rule? if (isset($_GET['add'])) { $context['rid'] = isset($_GET['rid']) && isset($context['rules'][$_GET['rid']]) ? (int) $_GET['rid'] : 0; $context['sub_template'] = 'add_rule'; // Any known rule $js_rules = ''; foreach ($context['known_rules'] as $rule) { $js_rules .= JavaScriptEscape($rule) . ': ' . JavaScriptEscape($txt['pm_rule_' . $rule]) . ','; } $js_rules = '{' . substr($js_rules, 0, -1) . '}'; // Any known label $js_labels = ''; foreach ($context['labels'] as $label) { if ($label['id'] != -1) { $js_labels .= JavaScriptEscape($label['id'] + 1) . ': ' . JavaScriptEscape($label['name']) . ','; } } $js_labels = '{' . substr($js_labels, 0, -1) . '}'; // And all of the groups as well $js_groups = ''; foreach ($context['groups'] as $id => $title) { $js_groups .= JavaScriptEscape($id) . ': ' . JavaScriptEscape($title) . ','; } $js_groups = '{' . substr($js_groups, 0, -1) . '}'; // Oh my, we have a lot of text strings for this addJavascriptVar(array('criteriaNum' => 0, 'actionNum' => 0, 'groups' => $js_groups, 'labels' => $js_labels, 'rules' => $js_rules, 'txt_pm_readable_and' => $txt['pm_readable_and'], 'txt_pm_readable_or' => $txt['pm_readable_or'], 'txt_pm_readable_member' => $txt['pm_readable_member'], 'txt_pm_readable_group' => $txt['pm_readable_group'], 'txt_pm_readable_subject ' => $txt['pm_readable_subject'], 'txt_pm_readable_body' => $txt['pm_readable_body'], 'txt_pm_readable_buddy' => $txt['pm_readable_buddy'], 'txt_pm_readable_label' => $txt['pm_readable_label'], 'txt_pm_readable_delete' => $txt['pm_readable_delete'], 'txt_pm_readable_start' => $txt['pm_readable_start'], 'txt_pm_readable_end' => $txt['pm_readable_end'], 'txt_pm_readable_then' => $txt['pm_readable_then'], 'txt_pm_rule_not_defined' => $txt['pm_rule_not_defined'], 'txt_pm_rule_criteria_pick' => $txt['pm_rule_criteria_pick'], 'txt_pm_rule_sel_group' => $txt['pm_rule_sel_group'], 'txt_pm_rule_sel_action' => $txt['pm_rule_sel_action'], 'txt_pm_rule_label' => $txt['pm_rule_label'], 'txt_pm_rule_delete' => $txt['pm_rule_delete'], 'txt_pm_rule_sel_label' => $txt['pm_rule_sel_label']), true); // Current rule information... if ($context['rid']) { $context['rule'] = $context['rules'][$context['rid']]; $members = array(); // Need to get member names! foreach ($context['rule']['criteria'] as $k => $criteria) { if ($criteria['t'] == 'mid' && !empty($criteria['v'])) { $members[(int) $criteria['v']] = $k; } } if (!empty($members)) { require_once SUBSDIR . '/Members.subs.php'; $result = getBasicMemberData(array_keys($members)); foreach ($result as $row) { $context['rule']['criteria'][$members[$row['id_member']]]['v'] = $row['member_name']; } } } else { $context['rule'] = array('id' => '', 'name' => '', 'criteria' => array(), 'actions' => array(), 'logic' => 'and'); } // Add a dummy criteria to allow expansion for none js users. $context['rule']['criteria'][] = array('t' => '', 'v' => ''); } elseif (isset($_GET['save'])) { checkSession('post'); $context['rid'] = isset($_GET['rid']) && isset($context['rules'][$_GET['rid']]) ? (int) $_GET['rid'] : 0; // Name is easy! $ruleName = Util::htmlspecialchars(trim($_POST['rule_name'])); if (empty($ruleName)) { fatal_lang_error('pm_rule_no_name', false); } // Sanity check... if (empty($_POST['ruletype']) || empty($_POST['acttype'])) { fatal_lang_error('pm_rule_no_criteria', false); } // Let's do the criteria first - it's also hardest! $criteria = array(); foreach ($_POST['ruletype'] as $ind => $type) { // Check everything is here... if ($type == 'gid' && (!isset($_POST['ruledefgroup'][$ind]) || !isset($context['groups'][$_POST['ruledefgroup'][$ind]]))) { continue; } elseif ($type != 'bud' && !isset($_POST['ruledef'][$ind])) { continue; } // Members need to be found. if ($type == 'mid') { require_once SUBSDIR . '/Members.subs.php'; $name = trim($_POST['ruledef'][$ind]); $member = getMemberByName($name, true); if (empty($member)) { continue; } $criteria[] = array('t' => 'mid', 'v' => $member['id_member']); } elseif ($type == 'bud') { $criteria[] = array('t' => 'bud', 'v' => 1); } elseif ($type == 'gid') { $criteria[] = array('t' => 'gid', 'v' => (int) $_POST['ruledefgroup'][$ind]); } elseif (in_array($type, array('sub', 'msg')) && trim($_POST['ruledef'][$ind]) != '') { $criteria[] = array('t' => $type, 'v' => Util::htmlspecialchars(trim($_POST['ruledef'][$ind]))); } } // Also do the actions! $actions = array(); $doDelete = 0; $isOr = $_POST['rule_logic'] == 'or' ? 1 : 0; foreach ($_POST['acttype'] as $ind => $type) { // Picking a valid label? if ($type == 'lab' && (!isset($_POST['labdef'][$ind]) || !isset($context['labels'][$_POST['labdef'][$ind] - 1]))) { continue; } // Record what we're doing. if ($type == 'del') { $doDelete = 1; } elseif ($type == 'lab') { $actions[] = array('t' => 'lab', 'v' => (int) $_POST['labdef'][$ind] - 1); } } if (empty($criteria) || empty($actions) && !$doDelete) { fatal_lang_error('pm_rule_no_criteria', false); } // What are we storing? $criteria = serialize($criteria); $actions = serialize($actions); // Create the rule? if (empty($context['rid'])) { addPMRule($user_info['id'], $ruleName, $criteria, $actions, $doDelete, $isOr); } else { updatePMRule($user_info['id'], $context['rid'], $ruleName, $criteria, $actions, $doDelete, $isOr); } redirectexit('action=pm;sa=manrules'); } elseif (isset($_POST['delselected']) && !empty($_POST['delrule'])) { checkSession('post'); $toDelete = array(); foreach ($_POST['delrule'] as $k => $v) { $toDelete[] = (int) $k; } if (!empty($toDelete)) { deletePMRules($user_info['id'], $toDelete); } redirectexit('action=pm;sa=manrules'); } }
/** * This function is behind the screen for adding new bans and modifying existing ones. * * Adding new bans: * - is accesssed by ?action=admin;area=ban;sa=add. * - uses the ban_edit sub template of the ManageBans template. * * Modifying existing bans: * - is accesssed by ?action=admin;area=ban;sa=edit;bg=x * - uses the ban_edit sub template of the ManageBans template. * - shows a list of ban triggers for the specified ban. */ public function action_edit() { global $txt, $modSettings, $context, $scripturl; require_once SUBSDIR . '/Bans.subs.php'; $ban_errors = Error_Context::context('ban', 1); // Saving a new or edited ban? if ((isset($_POST['add_ban']) || isset($_POST['modify_ban']) || isset($_POST['remove_selection'])) && !$ban_errors->hasErrors()) { $this->action_edit2(); } $ban_group_id = isset($context['ban']['id']) ? $context['ban']['id'] : (isset($_REQUEST['bg']) ? (int) $_REQUEST['bg'] : 0); // Template needs this to show errors using javascript loadLanguage('Errors'); createToken('admin-bet'); $context['form_url'] = $scripturl . '?action=admin;area=ban;sa=edit'; // Prepare any errors found to the template to show $context['ban_errors'] = array('errors' => $ban_errors->prepareErrors(), 'type' => $ban_errors->getErrorType() == 0 ? 'minor' : 'serious', 'title' => $txt['ban_errors_detected']); if (!$ban_errors->hasErrors()) { // If we're editing an existing ban, get it from the database. if (!empty($ban_group_id)) { $context['ban_group_id'] = $ban_group_id; // We're going to want this for making our list. require_once SUBSDIR . '/GenericList.class.php'; // Setup for a createlist $listOptions = array('id' => 'ban_items', 'base_href' => $scripturl . '?action=admin;area=ban;sa=edit;bg=' . $ban_group_id, 'no_items_label' => $txt['ban_no_triggers'], 'items_per_page' => $modSettings['defaultMaxMessages'], 'get_items' => array('function' => 'list_getBanItems', 'params' => array('ban_group_id' => $ban_group_id)), 'get_count' => array('function' => 'list_getNumBanItems', 'params' => array('ban_group_id' => $ban_group_id)), 'columns' => array('type' => array('header' => array('value' => $txt['ban_banned_entity'], 'style' => 'width: 60%;'), 'data' => array('function' => create_function('$ban_item', ' global $txt; if (in_array($ban_item[\'type\'], array(\'ip\', \'hostname\', \'email\'))) return \'<strong>\' . $txt[$ban_item[\'type\']] . \':</strong> \' . $ban_item[$ban_item[\'type\']]; elseif ($ban_item[\'type\'] == \'user\') return \'<strong>\' . $txt[\'username\'] . \':</strong> \' . $ban_item[\'user\'][\'link\']; else return \'<strong>\' . $txt[\'unknown\'] . \':</strong> \' . $ban_item[\'no_bantype_selected\']; '))), 'hits' => array('header' => array('value' => $txt['ban_hits'], 'style' => 'width: 15%;text-align: center'), 'data' => array('db' => 'hits', 'class' => 'centertext')), 'id' => array('header' => array('value' => $txt['ban_actions'], 'style' => 'width: 15%;'), 'data' => array('function' => create_function('$ban_item', ' global $txt, $context, $scripturl; return \'<a href="\' . $scripturl . \'?action=admin;area=ban;sa=edittrigger;bg=\' . $context[\'ban\'][\'id\'] . \';bi=\' . $ban_item[\'id\'] . \'">\' . $txt[\'ban_edit_trigger\'] . \'</a>\'; '))), 'checkboxes' => array('header' => array('value' => '<input type="checkbox" onclick="invertAll(this, this.form, \'ban_items\');" class="input_check" />', 'style' => 'width: 5%;'), 'data' => array('sprintf' => array('format' => '<input type="checkbox" name="ban_items[]" value="%1$d" class="input_check" />', 'params' => array('id' => false))))), 'form' => array('href' => $scripturl . '?action=admin;area=ban;sa=edit;bg=' . $ban_group_id), 'additional_rows' => array(array('position' => 'below_table_data', 'class' => 'submitbutton', 'value' => ' <input type="submit" name="remove_selection" value="' . $txt['ban_remove_selected_triggers'] . '" class="right_submit" /> <a class="linkbutton" href="' . $scripturl . '?action=admin;area=ban;sa=edittrigger;bg=' . $ban_group_id . '">' . $txt['ban_add_trigger'] . '</a> <input type="hidden" name="bg" value="' . $ban_group_id . '" /> <input type="hidden" name="' . $context['session_var'] . '" value="' . $context['session_id'] . '" /> <input type="hidden" name="' . $context['admin-bet_token_var'] . '" value="' . $context['admin-bet_token'] . '" />'))); createList($listOptions); } else { $context['ban'] = array('id' => 0, 'name' => '', 'expiration' => array('status' => 'never', 'days' => 0), 'reason' => '', 'notes' => '', 'ban_days' => 0, 'cannot' => array('access' => true, 'post' => false, 'register' => false, 'login' => false), 'is_new' => true); $context['ban_suggestions'] = array('main_ip' => '', 'hostname' => '', 'email' => '', 'member' => array('id' => 0)); // Overwrite some of the default form values if a user ID was given. if (!empty($_REQUEST['u'])) { $context['ban_suggestions'] = array_merge($context['ban_suggestions'], getMemberData((int) $_REQUEST['u'])); if (!empty($context['ban_suggestions']['member']['id'])) { $context['ban_suggestions']['href'] = $scripturl . '?action=profile;u=' . $context['ban_suggestions']['member']['id']; $context['ban_suggestions']['member']['link'] = '<a href="' . $context['ban_suggestions']['href'] . '">' . $context['ban_suggestions']['member']['name'] . '</a>'; // Default the ban name to the name of the banned member. $context['ban']['name'] = $context['ban_suggestions']['member']['name']; // @todo: there should be a better solution... // used to lock the "Ban on Username" input when banning from profile $context['ban']['from_user'] = true; // Would be nice if we could also ban the hostname. if ((preg_match('/^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/', $context['ban_suggestions']['main_ip']) == 1 || isValidIPv6($context['ban_suggestions']['main_ip'])) && empty($modSettings['disableHostnameLookup'])) { $context['ban_suggestions']['hostname'] = host_from_ip($context['ban_suggestions']['main_ip']); } $context['ban_suggestions']['other_ips'] = banLoadAdditionalIPs($context['ban_suggestions']['member']['id']); } } else { $context['use_autosuggest'] = true; loadJavascriptFile('suggest.js'); } } } // Set the right template $context['sub_template'] = 'ban_edit'; // A couple of text strings we *may* need addJavascriptVar(array('txt_ban_name_empty' => $txt['ban_name_empty'], 'txt_ban_restriction_empty' => $txt['ban_restriction_empty']), true); // And a bit of javascript to enable/disable some fields addInlineJavascript('addLoadEvent(fUpdateStatus);', true); }
/** * Sets up the basic theme context stuff. * * @param bool $forceload = false */ function setupThemeContext($forceload = false) { global $modSettings, $user_info, $scripturl, $context, $settings, $options, $txt; global $user_settings; static $loaded = false; // Under SSI this function can be called more then once. That can cause some problems. // So only run the function once unless we are forced to run it again. if ($loaded && !$forceload) { return; } $loaded = true; $context['current_time'] = standardTime(time(), false); $context['current_action'] = isset($_GET['action']) ? $_GET['action'] : ''; $context['show_quick_login'] = !empty($modSettings['enableVBStyleLogin']) && $user_info['is_guest']; // Get some news... $context['news_lines'] = array_filter(explode("\n", str_replace("\r", '', trim(addslashes($modSettings['news']))))); for ($i = 0, $n = count($context['news_lines']); $i < $n; $i++) { if (trim($context['news_lines'][$i]) == '') { continue; } // Clean it up for presentation ;). $context['news_lines'][$i] = parse_bbc(stripslashes(trim($context['news_lines'][$i])), true, 'news' . $i); } if (!empty($context['news_lines'])) { $context['random_news_line'] = $context['news_lines'][mt_rand(0, count($context['news_lines']) - 1)]; $context['upper_content_callbacks'][] = 'news_fader'; } if (!$user_info['is_guest']) { $context['user']['messages'] =& $user_info['messages']; $context['user']['unread_messages'] =& $user_info['unread_messages']; $context['user']['mentions'] =& $user_info['mentions']; // Personal message popup... if ($user_info['unread_messages'] > (isset($_SESSION['unread_messages']) ? $_SESSION['unread_messages'] : 0)) { $context['user']['popup_messages'] = true; } else { $context['user']['popup_messages'] = false; } $_SESSION['unread_messages'] = $user_info['unread_messages']; $context['user']['avatar'] = array('href' => !empty($user_info['avatar']['href']) ? $user_info['avatar']['href'] : '', 'image' => !empty($user_info['avatar']['image']) ? $user_info['avatar']['image'] : ''); // @deprecated since 1.0.2 if (!empty($modSettings['avatar_max_width'])) { $context['user']['avatar']['width'] = $modSettings['avatar_max_width']; } // @deprecated since 1.0.2 if (!empty($modSettings['avatar_max_height'])) { $context['user']['avatar']['height'] = $modSettings['avatar_max_height']; } // Figure out how long they've been logged in. $context['user']['total_time_logged_in'] = array('days' => floor($user_info['total_time_logged_in'] / 86400), 'hours' => floor($user_info['total_time_logged_in'] % 86400 / 3600), 'minutes' => floor($user_info['total_time_logged_in'] % 3600 / 60)); } else { $context['user']['messages'] = 0; $context['user']['unread_messages'] = 0; $context['user']['mentions'] = 0; $context['user']['avatar'] = array(); $context['user']['total_time_logged_in'] = array('days' => 0, 'hours' => 0, 'minutes' => 0); $context['user']['popup_messages'] = false; if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 1) { $txt['welcome_guest'] .= $txt['welcome_guest_activate']; } $txt['welcome_guest'] = replaceBasicActionUrl($txt['welcome_guest']); // If we've upgraded recently, go easy on the passwords. if (!empty($modSettings['enable_password_conversion'])) { $context['disable_login_hashing'] = true; } } // Setup the main menu items. setupMenuContext(); if (empty($settings['theme_version'])) { $context['show_vBlogin'] = $context['show_quick_login']; } // This is here because old index templates might still use it. $context['show_news'] = !empty($settings['enable_news']); $context['additional_dropdown_search'] = prepareSearchEngines(); // This is done to allow theme authors to customize it as they want. $context['show_pm_popup'] = $context['user']['popup_messages'] && !empty($options['popup_messages']) && (!isset($_REQUEST['action']) || $_REQUEST['action'] != 'pm'); // Add the PM popup here instead. Theme authors can still override it simply by editing/removing the 'fPmPopup' in the array. if ($context['show_pm_popup']) { addInlineJavascript(' $(document).ready(function(){ new smc_Popup({ heading: ' . JavaScriptEscape($txt['show_personal_messages_heading']) . ', content: ' . JavaScriptEscape(sprintf($txt['show_personal_messages'], $context['user']['unread_messages'], $scripturl . '?action=pm')) . ', icon: elk_images_url + \'/im_sm_newmsg.png\' }); });', true); } // This looks weird, but it's because BoardIndex.controller.php references the variable. $context['common_stats']['latest_member'] = array('id' => $modSettings['latestMember'], 'name' => $modSettings['latestRealName'], 'href' => $scripturl . '?action=profile;u=' . $modSettings['latestMember'], 'link' => '<a href="' . $scripturl . '?action=profile;u=' . $modSettings['latestMember'] . '">' . $modSettings['latestRealName'] . '</a>'); $context['common_stats'] = array('total_posts' => comma_format($modSettings['totalMessages']), 'total_topics' => comma_format($modSettings['totalTopics']), 'total_members' => comma_format($modSettings['totalMembers']), 'latest_member' => $context['common_stats']['latest_member']); $context['common_stats']['boardindex_total_posts'] = sprintf($txt['boardindex_total_posts'], $context['common_stats']['total_posts'], $context['common_stats']['total_topics'], $context['common_stats']['total_members']); if (empty($settings['theme_version'])) { addJavascriptVar(array('elk_scripturl' => '\'' . $scripturl . '\'')); } if (!isset($context['page_title'])) { $context['page_title'] = ''; } // Set some specific vars. $context['page_title_html_safe'] = Util::htmlspecialchars(un_htmlspecialchars($context['page_title'])) . (!empty($context['current_page']) ? ' - ' . $txt['page'] . ' ' . ($context['current_page'] + 1) : ''); $context['meta_keywords'] = !empty($modSettings['meta_keywords']) ? Util::htmlspecialchars($modSettings['meta_keywords']) : ''; // Load a custom CSS file? if (file_exists($settings['theme_dir'] . '/css/custom.css')) { loadCSSFile('custom.css'); } if (!empty($context['theme_variant']) && file_exists($settings['theme_dir'] . '/css/' . $context['theme_variant'] . '/custom' . $context['theme_variant'] . '.css')) { loadCSSFile($context['theme_variant'] . '/custom' . $context['theme_variant'] . '.css'); } }