/** * Makes sure the calendar post is valid. * * @package Calendar */ function validateEventPost() { global $modSettings; if (!isset($_POST['deleteevent'])) { // No month? No year? if (!isset($_POST['month'])) { fatal_lang_error('event_month_missing', false); } if (!isset($_POST['year'])) { fatal_lang_error('event_year_missing', false); } // Check the month and year... if ($_POST['month'] < 1 || $_POST['month'] > 12) { fatal_lang_error('invalid_month', false); } if ($_POST['year'] < $modSettings['cal_minyear'] || $_POST['year'] > $modSettings['cal_maxyear']) { fatal_lang_error('invalid_year', false); } } // Make sure they're allowed to post... isAllowedTo('calendar_post'); if (isset($_POST['span'])) { // Make sure it's turned on and not some fool trying to trick it. if (empty($modSettings['cal_allowspan'])) { fatal_lang_error('no_span', false); } if ($_POST['span'] < 1 || $_POST['span'] > $modSettings['cal_maxspan']) { fatal_lang_error('invalid_days_numb', false); } } // There is no need to validate the following values if we are just deleting the event. if (!isset($_POST['deleteevent'])) { // No day? if (!isset($_POST['day'])) { fatal_lang_error('event_day_missing', false); } if (!isset($_POST['evtitle']) && !isset($_POST['subject'])) { fatal_lang_error('event_title_missing', false); } elseif (!isset($_POST['evtitle'])) { $_POST['evtitle'] = $_POST['subject']; } // Bad day? if (!checkdate($_POST['month'], $_POST['day'], $_POST['year'])) { fatal_lang_error('invalid_date', false); } // No title? if (Util::htmltrim($_POST['evtitle']) === '') { fatal_lang_error('no_event_title', false); } if (Util::strlen($_POST['evtitle']) > 100) { $_POST['evtitle'] = Util::substr($_POST['evtitle'], 0, 100); } $_POST['evtitle'] = str_replace(';', '', $_POST['evtitle']); } }
/** * Add or edit a portal wide permissions profile */ public function action_sportal_admin_permission_profiles_edit() { global $context, $txt; // New or an edit? $context['is_new'] = empty($_REQUEST['profile_id']); // Saving the form if (!empty($_POST['submit'])) { // Security first checkSession(); // Always clean the name if (!isset($_POST['name']) || Util::htmltrim(Util::htmlspecialchars($_POST['name'], ENT_QUOTES)) === '') { fatal_lang_error('sp_error_profile_name_empty', false); } $groups_allowed = $groups_denied = ''; // If specific member groups were picked, build the allow/deny arrays if (!empty($_POST['membergroups']) && is_array($_POST['membergroups'])) { $groups_allowed = $groups_denied = array(); foreach ($_POST['membergroups'] as $id => $value) { if ($value == 1) { $groups_allowed[] = (int) $id; } elseif ($value == -1) { $groups_denied[] = (int) $id; } } $groups_allowed = implode(',', $groups_allowed); $groups_denied = implode(',', $groups_denied); } // Add the data to place in the fields $profile_info = array('id' => (int) $_POST['profile_id'], 'type' => 1, 'name' => Util::htmlspecialchars($_POST['name'], ENT_QUOTES), 'value' => implode('|', array($groups_allowed, $groups_denied))); // New we simply insert $profile_info['id'] = sp_add_permission_profile($profile_info, $context['is_new']); redirectexit('action=admin;area=portalprofiles'); } // Not saving, then its time to show the permission form if ($context['is_new']) { $context['profile'] = array('id' => 0, 'name' => $txt['sp_profiles_default_name'], 'label' => $txt['sp_profiles_default_name'], 'groups_allowed' => array(), 'groups_denied' => array()); } else { $_REQUEST['profile_id'] = (int) $_REQUEST['profile_id']; $context['profile'] = sportal_get_profiles($_REQUEST['profile_id']); } // Sub template time $context['profile']['groups'] = sp_load_membergroups(); $context['page_title'] = $context['is_new'] ? $txt['sp_admin_profiles_add'] : $txt['sp_admin_profiles_edit']; $context['sub_template'] = 'permission_profiles_edit'; }
/** * General function to split off a topic. * creates a new topic and moves the messages with the IDs in * array messagesToBeSplit to the new topic. * the subject of the newly created topic is set to 'newSubject'. * marks the newly created message as read for the user splitting it. * updates the statistics to reflect a newly created topic. * logs the action in the moderation log. * a notification is sent to all users monitoring this topic. * * @param int $split1_ID_TOPIC * @param int[] $splitMessages * @param string $new_subject * @return int the topic ID of the new split topic. */ function splitTopic($split1_ID_TOPIC, $splitMessages, $new_subject) { global $txt; $db = database(); // Nothing to split? if (empty($splitMessages)) { fatal_lang_error('no_posts_selected', false); } // Get some board info. $request = $db->query('', ' SELECT id_board, approved FROM {db_prefix}topics WHERE id_topic = {int:id_topic} LIMIT 1', array('id_topic' => $split1_ID_TOPIC)); list($id_board, $split1_approved) = $db->fetch_row($request); $db->free_result($request); // Find the new first and last not in the list. (old topic) $request = $db->query('', ' SELECT MIN(m.id_msg) AS myid_first_msg, MAX(m.id_msg) AS myid_last_msg, COUNT(*) AS message_count, m.approved FROM {db_prefix}messages AS m INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:id_topic}) WHERE m.id_msg NOT IN ({array_int:no_msg_list}) AND m.id_topic = {int:id_topic} GROUP BY m.approved ORDER BY m.approved DESC LIMIT 2', array('id_topic' => $split1_ID_TOPIC, 'no_msg_list' => $splitMessages)); // You can't select ALL the messages! if ($db->num_rows($request) == 0) { fatal_lang_error('selected_all_posts', false); } $split1_first_msg = null; $split1_last_msg = null; while ($row = $db->fetch_assoc($request)) { // Get the right first and last message dependant on approved state... if (empty($split1_first_msg) || $row['myid_first_msg'] < $split1_first_msg) { $split1_first_msg = $row['myid_first_msg']; } if (empty($split1_last_msg) || $row['approved']) { $split1_last_msg = $row['myid_last_msg']; } // Get the counts correct... if ($row['approved']) { $split1_replies = $row['message_count'] - 1; $split1_unapprovedposts = 0; } else { if (!isset($split1_replies)) { $split1_replies = 0; } elseif (!$split1_approved) { $split1_replies++; } $split1_unapprovedposts = $row['message_count']; } } $db->free_result($request); $split1_firstMem = getMsgMemberID($split1_first_msg); $split1_lastMem = getMsgMemberID($split1_last_msg); // Find the first and last in the list. (new topic) $request = $db->query('', ' SELECT MIN(id_msg) AS myid_first_msg, MAX(id_msg) AS myid_last_msg, COUNT(*) AS message_count, approved FROM {db_prefix}messages WHERE id_msg IN ({array_int:msg_list}) AND id_topic = {int:id_topic} GROUP BY id_topic, approved ORDER BY approved DESC LIMIT 2', array('msg_list' => $splitMessages, 'id_topic' => $split1_ID_TOPIC)); while ($row = $db->fetch_assoc($request)) { // As before get the right first and last message dependant on approved state... if (empty($split2_first_msg) || $row['myid_first_msg'] < $split2_first_msg) { $split2_first_msg = $row['myid_first_msg']; } if (empty($split2_last_msg) || $row['approved']) { $split2_last_msg = $row['myid_last_msg']; } // Then do the counts again... if ($row['approved']) { $split2_approved = true; $split2_replies = $row['message_count'] - 1; $split2_unapprovedposts = 0; } else { // Should this one be approved?? if ($split2_first_msg == $row['myid_first_msg']) { $split2_approved = false; } if (!isset($split2_replies)) { $split2_replies = 0; } elseif (!$split2_approved) { $split2_replies++; } $split2_unapprovedposts = $row['message_count']; } } $db->free_result($request); $split2_firstMem = getMsgMemberID($split2_first_msg); $split2_lastMem = getMsgMemberID($split2_last_msg); // No database changes yet, so let's double check to see if everything makes at least a little sense. if ($split1_first_msg <= 0 || $split1_last_msg <= 0 || $split2_first_msg <= 0 || $split2_last_msg <= 0 || $split1_replies < 0 || $split2_replies < 0 || $split1_unapprovedposts < 0 || $split2_unapprovedposts < 0 || !isset($split1_approved) || !isset($split2_approved)) { fatal_lang_error('cant_find_messages'); } // You cannot split off the first message of a topic. if ($split1_first_msg > $split2_first_msg) { fatal_lang_error('split_first_post', false); } // We're off to insert the new topic! Use 0 for now to avoid UNIQUE errors. $db->insert('', '{db_prefix}topics', array('id_board' => 'int', 'id_member_started' => 'int', 'id_member_updated' => 'int', 'id_first_msg' => 'int', 'id_last_msg' => 'int', 'num_replies' => 'int', 'unapproved_posts' => 'int', 'approved' => 'int', 'is_sticky' => 'int'), array((int) $id_board, $split2_firstMem, $split2_lastMem, 0, 0, $split2_replies, $split2_unapprovedposts, (int) $split2_approved, 0), array('id_topic')); $split2_ID_TOPIC = $db->insert_id('{db_prefix}topics', 'id_topic'); if ($split2_ID_TOPIC <= 0) { fatal_lang_error('cant_insert_topic'); } // Move the messages over to the other topic. $new_subject = strtr(Util::htmltrim(Util::htmlspecialchars($new_subject)), array("\r" => '', "\n" => '', "\t" => '')); // Check the subject length. if (Util::strlen($new_subject) > 100) { $new_subject = Util::substr($new_subject, 0, 100); } // Valid subject? if ($new_subject != '') { $db->query('', ' UPDATE {db_prefix}messages SET id_topic = {int:id_topic}, subject = CASE WHEN id_msg = {int:split_first_msg} THEN {string:new_subject} ELSE {string:new_subject_replies} END WHERE id_msg IN ({array_int:split_msgs})', array('split_msgs' => $splitMessages, 'id_topic' => $split2_ID_TOPIC, 'new_subject' => $new_subject, 'split_first_msg' => $split2_first_msg, 'new_subject_replies' => $txt['response_prefix'] . $new_subject)); // Cache the new topics subject... we can do it now as all the subjects are the same! updateStats('subject', $split2_ID_TOPIC, $new_subject); } // Any associated reported posts better follow... require_once SUBSDIR . '/Topic.subs.php'; updateSplitTopics(array('splitMessages' => $splitMessages, 'split2_ID_TOPIC' => $split2_ID_TOPIC, 'split1_replies' => $split1_replies, 'split1_first_msg' => $split1_first_msg, 'split1_last_msg' => $split1_last_msg, 'split1_firstMem' => $split1_firstMem, 'split1_lastMem' => $split1_lastMem, 'split1_unapprovedposts' => $split1_unapprovedposts, 'split1_ID_TOPIC' => $split1_ID_TOPIC, 'split2_first_msg' => $split2_first_msg, 'split2_last_msg' => $split2_last_msg, 'split2_ID_TOPIC' => $split2_ID_TOPIC, 'split2_approved' => $split2_approved), $id_board); require_once SUBSDIR . '/FollowUps.subs.php'; // Let's see if we can create a stronger bridge between the two topics // @todo not sure what message from the oldest topic I should link to the new one, so I'll go with the first linkMessages($split1_first_msg, $split2_ID_TOPIC); // Copy log topic entries. // @todo This should really be chunked. $request = $db->query('', ' SELECT id_member, id_msg, unwatched FROM {db_prefix}log_topics WHERE id_topic = {int:id_topic}', array('id_topic' => (int) $split1_ID_TOPIC)); if ($db->num_rows($request) > 0) { $replaceEntries = array(); while ($row = $db->fetch_assoc($request)) { $replaceEntries[] = array($row['id_member'], $split2_ID_TOPIC, $row['id_msg'], $row['unwatched']); } require_once SUBSDIR . '/Topic.subs.php'; markTopicsRead($replaceEntries, false); unset($replaceEntries); } $db->free_result($request); // Housekeeping. updateTopicStats(); updateLastMessages($id_board); logAction('split', array('topic' => $split1_ID_TOPIC, 'new_topic' => $split2_ID_TOPIC, 'board' => $id_board)); // Notify people that this topic has been split? require_once SUBSDIR . '/Notification.subs.php'; sendNotifications($split1_ID_TOPIC, 'split'); // If there's a search index that needs updating, update it... require_once SUBSDIR . '/Search.subs.php'; $searchAPI = findSearchAPI(); if (is_callable(array($searchAPI, 'topicSplit'))) { $searchAPI->topicSplit($split2_ID_TOPIC, $splitMessages); } // Return the ID of the newly created topic. return $split2_ID_TOPIC; }
/** * Trim a string including the HTML space, character 160. Uses two underscores to guard against overloading. * * What it does: * - trims a string or an the var array using html characters as well. * - does not effect keys, only values. * - may call itself recursively if needed. * * @param string[]|string $var * @param int $level = 0 * @return mixed[]|string */ function htmltrim__recursive($var, $level = 0) { // Remove spaces (32), tabs (9), returns (13, 10, and 11), nulls (0), and hard spaces. (160) if (!is_array($var)) { return Util::htmltrim($var); } // Go through all the elements and remove the whitespace. foreach ($var as $k => $v) { $var[$k] = $level > 25 ? null : htmltrim__recursive($v, $level + 1); } return $var; }
/** * Send the emails. * * - Sends off emails to all the moderators. * - Sends to administrators and global moderators. (1 and 2) * - Called by action_reporttm(), and thus has the same permission and setting requirements as it does. * - Accessed through ?action=reporttm when posting. */ public function action_reporttm2() { global $txt, $scripturl, $topic, $board, $user_info, $modSettings, $language, $context; // You must have the proper permissions! isAllowedTo('report_any'); // Make sure they aren't spamming. spamProtection('reporttm'); require_once SUBSDIR . '/Mail.subs.php'; // No errors, yet. $report_errors = Error_Context::context('report', 1); // Check their session. if (checkSession('post', '', false) != '') { $report_errors->addError('session_timeout'); } // Make sure we have a comment and it's clean. if (!isset($_POST['comment']) || Util::htmltrim($_POST['comment']) === '') { $report_errors->addError('no_comment'); } $poster_comment = strtr(Util::htmlspecialchars($_POST['comment']), array("\r" => '', "\t" => '')); if (Util::strlen($poster_comment) > 254) { $report_errors->addError('post_too_long'); } // Guests need to provide their address! if ($user_info['is_guest']) { require_once SUBSDIR . '/DataValidator.class.php'; if (!Data_Validator::is_valid($_POST, array('email' => 'valid_email'), array('email' => 'trim'))) { empty($_POST['email']) ? $report_errors->addError('no_email') : $report_errors->addError('bad_email'); } isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt['guest_title'])); $user_info['email'] = htmlspecialchars($_POST['email'], ENT_COMPAT, 'UTF-8'); } // Could they get the right verification code? if ($user_info['is_guest'] && !empty($modSettings['guests_report_require_captcha'])) { require_once SUBSDIR . '/VerificationControls.class.php'; $verificationOptions = array('id' => 'report'); $context['require_verification'] = create_control_verification($verificationOptions, true); if (is_array($context['require_verification'])) { foreach ($context['require_verification'] as $error) { $report_errors->addError($error, 0); } } } // Any errors? if ($report_errors->hasErrors()) { return $this->action_reporttm(); } // Get the basic topic information, and make sure they can see it. $msg_id = (int) $_POST['msg']; $message = posterDetails($msg_id, $topic); if (empty($message)) { fatal_lang_error('no_board', false); } $poster_name = un_htmlspecialchars($message['real_name']) . ($message['real_name'] != $message['poster_name'] ? ' (' . $message['poster_name'] . ')' : ''); $reporterName = un_htmlspecialchars($user_info['name']) . ($user_info['name'] != $user_info['username'] && $user_info['username'] != '' ? ' (' . $user_info['username'] . ')' : ''); $subject = un_htmlspecialchars($message['subject']); // Get a list of members with the moderate_board permission. require_once SUBSDIR . '/Members.subs.php'; $moderators = membersAllowedTo('moderate_board', $board); $result = getBasicMemberData($moderators, array('preferences' => true, 'sort' => 'lngfile')); $mod_to_notify = array(); foreach ($result as $row) { if ($row['notify_types'] != 4) { $mod_to_notify[] = $row; } } // Check that moderators do exist! if (empty($mod_to_notify)) { fatal_lang_error('no_mods', false); } // If we get here, I believe we should make a record of this, for historical significance, yabber. if (empty($modSettings['disable_log_report'])) { require_once SUBSDIR . '/Messages.subs.php'; $id_report = recordReport($message, $poster_comment); // If we're just going to ignore these, then who gives a monkeys... if ($id_report === false) { redirectexit('topic=' . $topic . '.msg' . $msg_id . '#msg' . $msg_id); } } // Find out who the real moderators are - for mod preferences. require_once SUBSDIR . '/Boards.subs.php'; $real_mods = getBoardModerators($board, true); // Send every moderator an email. foreach ($mod_to_notify as $row) { // Maybe they don't want to know?! if (!empty($row['mod_prefs'])) { list(, , $pref_binary) = explode('|', $row['mod_prefs']); if (!($pref_binary & 1) && (!($pref_binary & 2) || !in_array($row['id_member'], $real_mods))) { continue; } } $replacements = array('TOPICSUBJECT' => $subject, 'POSTERNAME' => $poster_name, 'REPORTERNAME' => $reporterName, 'TOPICLINK' => $scripturl . '?topic=' . $topic . '.msg' . $msg_id . '#msg' . $msg_id, 'REPORTLINK' => !empty($id_report) ? $scripturl . '?action=moderate;area=reports;report=' . $id_report : '', 'COMMENT' => $_POST['comment']); $emaildata = loadEmailTemplate('report_to_moderator', $replacements, empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']); // Send it to the moderator. sendmail($row['email_address'], $emaildata['subject'], $emaildata['body'], $user_info['email'], null, false, 2); } // Keep track of when the mod reports get updated, that way we know when we need to look again. updateSettings(array('last_mod_report_action' => time())); // Back to the post we reported! redirectexit('reportsent;topic=' . $topic . '.msg' . $msg_id . '#msg' . $msg_id); }
/** * Implodes or Expands a set of style attributes * * @param string $action implode or explode * @param string $setting string of style options joined on name~value|name~value * @param boolean $process */ function sportal_parse_style($action, $setting = '', $process = false) { static $process_cache; $style = array(); if ($action === 'implode') { $style = ''; $style_parameters = array('title_default_class', 'title_custom_class', 'title_custom_style', 'body_default_class', 'body_custom_class', 'body_custom_style', 'no_title', 'no_body'); foreach ($style_parameters as $parameter) { if (isset($_POST[$parameter])) { $style .= $parameter . '~' . Util::htmlspecialchars(Util::htmltrim($_POST[$parameter]), ENT_QUOTES) . '|'; } else { $style .= $parameter . '~|'; } } if (!empty($style)) { $style = substr($style, 0, -1); } } elseif ($action === 'explode') { // Supplying a style set or using our defaults if (!empty($setting)) { $temp = explode('|', $setting); foreach ($temp as $item) { list($key, $value) = explode('~', $item); $style[$key] = $value; } } else { $style = array('title_default_class' => 'category_header', 'title_custom_class' => '', 'title_custom_style' => '', 'body_default_class' => 'portalbg', 'body_custom_class' => '', 'body_custom_style' => '', 'no_title' => false, 'no_body' => false); } // Set the style values for use in the templates if ($process && !isset($process_cache[$setting])) { if (empty($style['no_title'])) { $style['title']['class'] = $style['title_default_class']; if (!empty($style['title_custom_class'])) { $style['title']['class'] .= ' ' . $style['title_custom_class']; } $style['title']['style'] = $style['title_custom_style']; } if (empty($style['no_body'])) { $style['body']['class'] = $style['body_default_class']; } else { $style['body']['class'] = ''; } if (!empty($style['body_custom_class'])) { $style['body']['class'] .= ' ' . $style['body_custom_class']; } $style['body']['style'] = $style['body_custom_style']; $process_cache[$setting] = $style; } elseif ($process) { $style = $process_cache[$setting]; } } return $style; }
/** * Edit or add a category */ public function action_sportal_admin_category_edit() { global $context, $txt; loadTemplate('PortalAdminCategories'); $this->_is_new = empty($_REQUEST['category_id']); // Saving the category form if (!empty($_POST['submit'])) { checkSession(); // Clean what was sent // @todo move all this to validator? $name = isset($_POST['name']) ? Util::htmltrim(Util::htmlspecialchars($_POST['name'], ENT_QUOTES)) : ''; $namespace = isset($_POST['namespace']) ? Util::htmltrim(Util::htmlspecialchars($_POST['namespace'], ENT_QUOTES)) : ''; $current = isset($_POST['category_id']) ? (int) $_POST['category_id'] : 0; $description = isset($_POST['description']) ? Util::htmlspecialchars($_POST['description'], ENT_QUOTES) : ''; if (empty($name)) { fatal_lang_error('sp_error_category_name_empty', false); } if (empty($namespace)) { fatal_lang_error('sp_error_category_namespace_empty', false); } if (sp_check_duplicate_category($current, $namespace)) { fatal_lang_error('sp_error_category_namespace_duplicate', false); } if (preg_match('~[^A-Za-z0-9_]+~', $namespace) != 0) { fatal_lang_error('sp_error_category_namespace_invalid_chars', false); } if (preg_replace('~[0-9]+~', '', $namespace) === '') { fatal_lang_error('sp_error_category_namespace_numeric', false); } $category_info = array('id' => (int) $_POST['category_id'], 'namespace' => $namespace, 'name' => $name, 'description' => $description, 'permissions' => (int) $_POST['permissions'], 'status' => !empty($_POST['status']) ? 1 : 0); $category_info['id'] = sp_update_category($category_info, $this->_is_new); redirectexit('action=admin;area=portalcategories'); } // Creating a new category, lets set up some defaults for the form if ($this->_is_new) { $context['category'] = array('id' => 0, 'category_id' => 'category' . mt_rand(1, 5000), 'name' => $txt['sp_categories_default_name'], 'description' => '', 'permissions' => 3, 'groups_allowed' => array(), 'groups_denied' => array(), 'status' => 1); } else { $_REQUEST['category_id'] = (int) $_REQUEST['category_id']; $context['category'] = sportal_get_categories($_REQUEST['category_id']); } $context['is_new'] = $this->_is_new; $context['category']['permission_profiles'] = sportal_get_profiles(null, 1, 'name'); $context['category']['groups'] = sp_load_membergroups(); $context['page_title'] = $this->_is_new ? $txt['sp_admin_categories_add'] : $txt['sp_admin_categories_edit']; $context['sub_template'] = 'categories_edit'; }
/** * Execute the move of a topic. * It is called on the submit of action_movetopic. * This function logs that topics have been moved in the moderation log. * If the member is the topic starter requires the move_own permission, * otherwise requires the move_any permission. * Upon successful completion redirects to message index. * Accessed via ?action=movetopic2. * * @uses subs/Post.subs.php. */ public function action_movetopic2() { global $txt, $board, $topic, $scripturl, $context, $language, $user_info; if (empty($topic)) { fatal_lang_error('no_access', false); } // You can't choose to have a redirection topic and use an empty reason. if (isset($_POST['postRedirect']) && (!isset($_POST['reason']) || trim($_POST['reason']) == '')) { fatal_lang_error('movetopic_no_reason', false); } // You have to tell us were you are moving to if (!isset($_POST['toboard'])) { fatal_lang_error('movetopic_no_board', false); } // We will need this require_once SUBSDIR . '/Topic.subs.php'; moveTopicConcurrence(); // Make sure this form hasn't been submitted before. checkSubmitOnce('check'); // Get the basic details on this topic $topic_info = getTopicInfo($topic); $context['is_approved'] = $topic_info['approved']; // Can they see it? if (!$context['is_approved']) { isAllowedTo('approve_posts'); } // Can they move topics on this board? if (!allowedTo('move_any')) { if ($topic_info['id_member_started'] == $user_info['id']) { isAllowedTo('move_own'); } else { isAllowedTo('move_any'); } } checkSession(); require_once SUBSDIR . '/Post.subs.php'; require_once SUBSDIR . '/Boards.subs.php'; // The destination board must be numeric. $toboard = (int) $_POST['toboard']; // Make sure they can see the board they are trying to move to (and get whether posts count in the target board). $board_info = boardInfo($toboard, $topic); if (empty($board_info)) { fatal_lang_error('no_board'); } // Remember this for later. $_SESSION['move_to_topic'] = array('move_to' => $toboard); // Rename the topic... if (isset($_POST['reset_subject'], $_POST['custom_subject']) && $_POST['custom_subject'] != '') { $custom_subject = strtr(Util::htmltrim(Util::htmlspecialchars($_POST['custom_subject'])), array("\r" => '', "\n" => '', "\t" => '')); // Keep checking the length. if (Util::strlen($custom_subject) > 100) { $custom_subject = Util::substr($custom_subject, 0, 100); } // If it's still valid move onwards and upwards. if ($custom_subject != '') { $all_messages = isset($_POST['enforce_subject']); if ($all_messages) { // Get a response prefix, but in the forum's default language. $context['response_prefix'] = response_prefix(); topicSubject($topic_info, $custom_subject, $context['response_prefix'], $all_messages); } else { topicSubject($topic_info, $custom_subject); } // Fix the subject cache. updateStats('subject', $topic, $custom_subject); } } // Create a link to this in the old board. // @todo Does this make sense if the topic was unapproved before? I'd just about say so. if (isset($_POST['postRedirect'])) { // Should be in the boardwide language. if ($user_info['language'] != $language) { loadLanguage('index', $language); } $reason = Util::htmlspecialchars($_POST['reason'], ENT_QUOTES); preparsecode($reason); // Add a URL onto the message. $reason = strtr($reason, array($txt['movetopic_auto_board'] => '[url=' . $scripturl . '?board=' . $toboard . '.0]' . $board_info['name'] . '[/url]', $txt['movetopic_auto_topic'] => '[iurl]' . $scripturl . '?topic=' . $topic . '.0[/iurl]')); // Auto remove this MOVED redirection topic in the future? $redirect_expires = !empty($_POST['redirect_expires']) ? (int) $_POST['redirect_expires'] : 0; // Redirect to the MOVED topic from topic list? $redirect_topic = isset($_POST['redirect_topic']) ? $topic : 0; // And remember the last expiry period too. $_SESSION['move_to_topic']['redirect_topic'] = $redirect_topic; $_SESSION['move_to_topic']['redirect_expires'] = $redirect_expires; $msgOptions = array('subject' => $txt['moved'] . ': ' . $board_info['subject'], 'body' => $reason, 'icon' => 'moved', 'smileys_enabled' => 1); $topicOptions = array('board' => $board, 'lock_mode' => 1, 'mark_as_read' => true, 'redirect_expires' => empty($redirect_expires) ? 0 : $redirect_expires * 60 + time(), 'redirect_topic' => $redirect_topic); $posterOptions = array('id' => $user_info['id'], 'update_post_count' => empty($board_info['count_posts'])); createPost($msgOptions, $topicOptions, $posterOptions); } $board_from = boardInfo($board); if ($board_from['count_posts'] != $board_info['count_posts']) { $posters = postersCount($topic); foreach ($posters as $id_member => $posts) { // The board we're moving from counted posts, but not to. if (empty($board_from['count_posts'])) { updateMemberData($id_member, array('posts' => 'posts - ' . $posts)); } else { updateMemberData($id_member, array('posts' => 'posts + ' . $posts)); } } } // Do the move (includes statistics update needed for the redirect topic). moveTopics($topic, $toboard); // Log that they moved this topic. if (!allowedTo('move_own') || $topic_info['id_member_started'] != $user_info['id']) { logAction('move', array('topic' => $topic, 'board_from' => $board, 'board_to' => $toboard)); } // Notify people that this topic has been moved? require_once SUBSDIR . '/Notification.subs.php'; sendNotifications($topic, 'move'); // Why not go back to the original board in case they want to keep moving? if (!isset($_REQUEST['goback'])) { redirectexit('board=' . $board . '.0'); } else { redirectexit('topic=' . $topic . '.0'); } }
/** * Show all PM drafts of the current user * Uses the showpmdraft template * Allows for the deleting and loading/editing of PM drafts */ public function action_showPMDrafts() { global $txt, $user_info, $scripturl, $modSettings, $context; require_once SUBSDIR . '/Profile.subs.php'; require_once SUBSDIR . '/Drafts.subs.php'; $memID = currentMemberID(); // Quick check how we got here. if ($memID != $user_info['id']) { // empty($modSettings['drafts_enabled']) || empty($modSettings['drafts_pm_enabled'])) fatal_lang_error('no_access', false); } // Set up what we will need $context['start'] = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0; // If just deleting a draft, do it and then redirect back. if (!empty($_REQUEST['delete'])) { checkSession('get'); $id_delete = (int) $_REQUEST['delete']; deleteDrafts($id_delete, $memID); redirectexit('action=pm;sa=showpmdrafts;start=' . $context['start']); } // Perhaps a draft was selected for editing? if so pass this off if (!empty($_REQUEST['id_draft']) && !empty($context['drafts_pm_save'])) { checkSession('get'); $id_draft = (int) $_REQUEST['id_draft']; redirectexit('action=pm;sa=send;id_draft=' . $id_draft); } // Init $maxIndex = (int) $modSettings['defaultMaxMessages']; // Default to 10. if (empty($_REQUEST['viewscount']) || !is_numeric($_REQUEST['viewscount'])) { $_REQUEST['viewscount'] = 10; } // Get the count of applicable drafts $msgCount = draftsCount($memID, 1); // Make sure the starting place makes sense and construct our friend the page index. $context['page_index'] = constructPageIndex($scripturl . '?action=pm;sa=showpmdrafts', $context['start'], $msgCount, $maxIndex); $context['current_page'] = $context['start'] / $maxIndex; // Reverse the query if we're past 50% of the total for better performance. $start = $context['start']; $reverse = $start > $msgCount / 2; if ($reverse) { $maxIndex = $msgCount < $context['start'] + $modSettings['defaultMaxMessages'] + 1 && $msgCount > $context['start'] ? $msgCount - $context['start'] : (int) $modSettings['defaultMaxMessages']; $start = $msgCount < $context['start'] + $modSettings['defaultMaxMessages'] + 1 || $msgCount < $context['start'] + $modSettings['defaultMaxMessages'] ? 0 : $msgCount - $context['start'] - $modSettings['defaultMaxMessages']; } // Go get em' $order = 'ud.poster_time ' . ($reverse ? 'ASC' : 'DESC'); $limit = $start . ', ' . $maxIndex; $user_drafts = load_user_drafts($memID, 1, false, $order, $limit); // Start counting at the number of the first message displayed. $counter = $reverse ? $context['start'] + $maxIndex + 1 : $context['start']; $context['posts'] = array(); foreach ($user_drafts as $row) { // Censor.... if (empty($row['body'])) { $row['body'] = ''; } $row['subject'] = Util::htmltrim($row['subject']); if (empty($row['subject'])) { $row['subject'] = $txt['no_subject']; } censorText($row['body']); censorText($row['subject']); // BBC-ilize the message. $row['body'] = parse_bbc($row['body'], true, 'draft' . $row['id_draft']); // Have they provided who this will go to? $recipients = array('to' => array(), 'bcc' => array()); $recipient_ids = !empty($row['to_list']) ? unserialize($row['to_list']) : array(); // Get nice names to show the user, the id's are not that great to see! if (!empty($recipient_ids['to']) || !empty($recipient_ids['bcc'])) { $recipient_ids['to'] = array_map('intval', $recipient_ids['to']); $recipient_ids['bcc'] = array_map('intval', $recipient_ids['bcc']); $allRecipients = array_merge($recipient_ids['to'], $recipient_ids['bcc']); $recipients = draftsRecipients($allRecipients, $recipient_ids); } // Add the items to the array for template use $context['drafts'][$counter += $reverse ? -1 : 1] = array('body' => $row['body'], 'counter' => $counter, 'alternate' => $counter % 2, 'subject' => $row['subject'], 'time' => standardTime($row['poster_time']), 'html_time' => htmlTime($row['poster_time']), 'timestamp' => forum_time(true, $row['poster_time']), 'id_draft' => $row['id_draft'], 'recipients' => $recipients, 'age' => floor((time() - $row['poster_time']) / 86400), 'remaining' => !empty($modSettings['drafts_keep_days']) ? floor($modSettings['drafts_keep_days'] - (time() - $row['poster_time']) / 86400) : 0); } // If the drafts were retrieved in reverse order, then put them in the right order again. if ($reverse) { $context['drafts'] = array_reverse($context['drafts'], true); } // Off to the template we go $context['page_title'] = $txt['drafts']; $context['sub_template'] = 'showPMDrafts'; $context['linktree'][] = array('url' => $scripturl . '?action=pm;sa=showpmdrafts', 'name' => $txt['drafts']); }
/** * Calls the necessary functions to extract and format the message so its ready for posting * * What it does: * - Converts an email response (text or html) to a BBC equivalant via pbe_Email_to_bbc * - Formats the email response so it looks structured and not chopped up (via pbe_fix_email_body) * * @package Maillist * @param boolean $html * @param Email_Parse $email_message * @param mixed[] $pbe */ function pbe_load_text(&$html, $email_message, $pbe) { if (!$html || $html && preg_match_all('~<table.*?>~i', $email_message->body, $match) >= 2) { // Some mobile responses wrap everything in a table structure so use plain text $text = $email_message->plain_body; $html = false; } else { $text = un_htmlspecialchars($email_message->body); } // Run filters now, before the data is manipulated $text = pbe_filter_email_message($text); // Convert to BBC and format it so it looks like a post $text = pbe_email_to_bbc($text, $html); $pbe['profile']['real_name'] = isset($pbe['profile']['real_name']) ? $pbe['profile']['real_name'] : ''; $text = pbe_fix_email_body($text, $html, $pbe['profile']['real_name'], empty($email_message->_converted_utf8) ? $email_message->headers['x-parameters']['content-type']['charset'] : 'UTF-8'); // Do we even have a message left to post? $text = Util::htmltrim($text); if (empty($text)) { return; } if ($email_message->message_type !== 'p') { // Prepare it for the database require_once SUBSDIR . '/Post.subs.php'; preparsecode($text); } return $text; }
/** * Used to edit the body or subject of a message inline * called from action=jsmodify from script and topic js */ public function action_jsmodify() { global $modSettings, $board, $topic; global $user_info, $context; $db = database(); // We have to have a topic! if (empty($topic)) { obExit(false); } checkSession('get'); require_once SUBSDIR . '/Post.subs.php'; // Assume the first message if no message ID was given. $request = $db->query('', ' SELECT t.locked, t.num_replies, t.id_member_started, t.id_first_msg, m.id_msg, m.id_member, m.poster_time, m.subject, m.smileys_enabled, m.body, m.icon, m.modified_time, m.modified_name, m.approved FROM {db_prefix}messages AS m INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic}) WHERE m.id_msg = {raw:id_msg} AND m.id_topic = {int:current_topic}' . (allowedTo('modify_any') || allowedTo('approve_posts') ? '' : (!$modSettings['postmod_active'] ? ' AND (m.id_member != {int:guest_id} AND m.id_member = {int:current_member})' : ' AND (m.approved = {int:is_approved} OR (m.id_member != {int:guest_id} AND m.id_member = {int:current_member}))')), array('current_member' => $user_info['id'], 'current_topic' => $topic, 'id_msg' => empty($_REQUEST['msg']) ? 't.id_first_msg' : (int) $_REQUEST['msg'], 'is_approved' => 1, 'guest_id' => 0)); if ($db->num_rows($request) == 0) { fatal_lang_error('no_board', false); } $row = $db->fetch_assoc($request); $db->free_result($request); // Change either body or subject requires permissions to modify messages. if (isset($_POST['message']) || isset($_POST['subject']) || isset($_REQUEST['icon'])) { if (!empty($row['locked'])) { isAllowedTo('moderate_board'); } if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any')) { if ((!$modSettings['postmod_active'] || $row['approved']) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time()) { fatal_lang_error('modify_post_time_passed', false); } elseif ($row['id_member_started'] == $user_info['id'] && !allowedTo('modify_own')) { isAllowedTo('modify_replies'); } else { isAllowedTo('modify_own'); } } elseif ($row['id_member_started'] == $user_info['id'] && !allowedTo('modify_any')) { isAllowedTo('modify_replies'); } else { isAllowedTo('modify_any'); } // Only log this action if it wasn't your message. $moderationAction = $row['id_member'] != $user_info['id']; } $post_errors = Error_Context::context('post', 1); if (isset($_POST['subject']) && Util::htmltrim(Util::htmlspecialchars($_POST['subject'])) !== '') { $_POST['subject'] = strtr(Util::htmlspecialchars($_POST['subject']), array("\r" => '', "\n" => '', "\t" => '')); // Maximum number of characters. if (Util::strlen($_POST['subject']) > 100) { $_POST['subject'] = Util::substr($_POST['subject'], 0, 100); } } elseif (isset($_POST['subject'])) { $post_errors->addError('no_subject'); unset($_POST['subject']); } if (isset($_POST['message'])) { if (Util::htmltrim(Util::htmlspecialchars($_POST['message'])) === '') { $post_errors->addError('no_message'); unset($_POST['message']); } elseif (!empty($modSettings['max_messageLength']) && Util::strlen($_POST['message']) > $modSettings['max_messageLength']) { $post_errors->addError(array('long_message', array($modSettings['max_messageLength']))); unset($_POST['message']); } else { $_POST['message'] = Util::htmlspecialchars($_POST['message'], ENT_QUOTES); preparsecode($_POST['message']); if (Util::htmltrim(strip_tags(parse_bbc($_POST['message'], false), '<img>')) === '') { $post_errors->addError('no_message'); unset($_POST['message']); } } } if (isset($_POST['lock'])) { if (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $user_info['id'] != $row['id_member']) { unset($_POST['lock']); } elseif (!allowedTo('lock_any')) { if ($row['locked'] == 1) { unset($_POST['lock']); } else { $_POST['lock'] = empty($_POST['lock']) ? 0 : 2; } } elseif (!empty($row['locked']) && !empty($_POST['lock']) || $_POST['lock'] == $row['locked']) { unset($_POST['lock']); } else { $_POST['lock'] = empty($_POST['lock']) ? 0 : 1; } } if (isset($_POST['sticky']) && !allowedTo('make_sticky')) { unset($_POST['sticky']); } if (!$post_errors->hasErrors()) { $msgOptions = array('id' => $row['id_msg'], 'subject' => isset($_POST['subject']) ? $_POST['subject'] : null, 'body' => isset($_POST['message']) ? $_POST['message'] : null, 'icon' => isset($_REQUEST['icon']) ? preg_replace('~[\\./\\\\*\':"<>]~', '', $_REQUEST['icon']) : null); $topicOptions = array('id' => $topic, 'board' => $board, 'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null, 'sticky_mode' => isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics']) ? (int) $_POST['sticky'] : null, 'mark_as_read' => false); $posterOptions = array(); // Only consider marking as editing if they have edited the subject, message or icon. if (isset($_POST['subject']) && $_POST['subject'] != $row['subject'] || isset($_POST['message']) && $_POST['message'] != $row['body'] || isset($_REQUEST['icon']) && $_REQUEST['icon'] != $row['icon']) { // And even then only if the time has passed... if (time() - $row['poster_time'] > $modSettings['edit_wait_time'] || $user_info['id'] != $row['id_member']) { $msgOptions['modify_time'] = time(); $msgOptions['modify_name'] = $user_info['name']; } } else { $moderationAction = false; } modifyPost($msgOptions, $topicOptions, $posterOptions); // If we didn't change anything this time but had before put back the old info. if (!isset($msgOptions['modify_time']) && !empty($row['modified_time'])) { $msgOptions['modify_time'] = $row['modified_time']; $msgOptions['modify_name'] = $row['modified_name']; } // Changing the first subject updates other subjects to 'Re: new_subject'. if (isset($_POST['subject']) && isset($_REQUEST['change_all_subjects']) && $row['id_first_msg'] == $row['id_msg'] && !empty($row['num_replies']) && (allowedTo('modify_any') || $row['id_member_started'] == $user_info['id'] && allowedTo('modify_replies'))) { // Get the proper (default language) response prefix first. $context['response_prefix'] = response_prefix(); $db->query('', ' UPDATE {db_prefix}messages SET subject = {string:subject} WHERE id_topic = {int:current_topic} AND id_msg != {int:id_first_msg}', array('current_topic' => $topic, 'id_first_msg' => $row['id_first_msg'], 'subject' => $context['response_prefix'] . $_POST['subject'])); } if (!empty($moderationAction)) { logAction('modify', array('topic' => $topic, 'message' => $row['id_msg'], 'member' => $row['id_member'], 'board' => $board)); } } if (isset($_REQUEST['xml'])) { $context['sub_template'] = 'modifydone'; if (!$post_errors->hasErrors() && isset($msgOptions['subject']) && isset($msgOptions['body'])) { $context['message'] = array('id' => $row['id_msg'], 'modified' => array('time' => isset($msgOptions['modify_time']) ? standardTime($msgOptions['modify_time']) : '', 'html_time' => isset($msgOptions['modify_time']) ? htmlTime($msgOptions['modify_time']) : '', 'timestamp' => isset($msgOptions['modify_time']) ? forum_time(true, $msgOptions['modify_time']) : 0, 'name' => isset($msgOptions['modify_time']) ? $msgOptions['modify_name'] : ''), 'subject' => $msgOptions['subject'], 'first_in_topic' => $row['id_msg'] == $row['id_first_msg'], 'body' => strtr($msgOptions['body'], array(']]>' => ']]]]><![CDATA[>'))); censorText($context['message']['subject']); censorText($context['message']['body']); $context['message']['body'] = parse_bbc($context['message']['body'], $row['smileys_enabled'], $row['id_msg']); } elseif (!$post_errors->hasErrors()) { $context['sub_template'] = 'modifytopicdone'; $context['message'] = array('id' => $row['id_msg'], 'modified' => array('time' => isset($msgOptions['modify_time']) ? standardTime($msgOptions['modify_time']) : '', 'html_time' => isset($msgOptions['modify_time']) ? htmlTime($msgOptions['modify_time']) : '', 'timestamp' => isset($msgOptions['modify_time']) ? forum_time(true, $msgOptions['modify_time']) : 0, 'name' => isset($msgOptions['modify_time']) ? $msgOptions['modify_name'] : ''), 'subject' => isset($msgOptions['subject']) ? $msgOptions['subject'] : ''); censorText($context['message']['subject']); } else { $context['message'] = array('id' => $row['id_msg'], 'errors' => array(), 'error_in_subject' => $post_errors->hasError('no_subject'), 'error_in_body' => $post_errors->hasError('no_message') || $post_errors->hasError('long_message')); $context['message']['errors'] = $post_errors->prepareErrors(); } } else { obExit(false); } }
/** * Send a personal message. */ public function action_send2() { global $txt, $context, $user_info, $modSettings; // All the helpers we need require_once SUBSDIR . '/Auth.subs.php'; require_once SUBSDIR . '/Post.subs.php'; // PM Drafts enabled and needed? if ($context['drafts_pm_save'] && (isset($_POST['save_draft']) || isset($_POST['id_pm_draft']))) { require_once SUBSDIR . '/Drafts.subs.php'; } loadLanguage('PersonalMessage', '', false); // Extract out the spam settings - it saves database space! list($modSettings['max_pm_recipients'], $modSettings['pm_posts_verification'], $modSettings['pm_posts_per_hour']) = explode(',', $modSettings['pm_spam_settings']); // Initialize the errors we're about to make. $post_errors = Error_Context::context('pm', 1); // Check whether we've gone over the limit of messages we can send per hour - fatal error if fails! if (!empty($modSettings['pm_posts_per_hour']) && !allowedTo(array('admin_forum', 'moderate_forum', 'send_mail')) && $user_info['mod_cache']['bq'] == '0=1' && $user_info['mod_cache']['gq'] == '0=1') { // How many have they sent this last hour? $pmCount = pmCount($user_info['id'], 3600); if (!empty($pmCount) && $pmCount >= $modSettings['pm_posts_per_hour']) { if (!isset($_REQUEST['xml'])) { fatal_lang_error('pm_too_many_per_hour', true, array($modSettings['pm_posts_per_hour'])); } else { $post_errors->addError('pm_too_many_per_hour'); } } } // If your session timed out, show an error, but do allow to re-submit. if (!isset($_REQUEST['xml']) && checkSession('post', '', false) != '') { $post_errors->addError('session_timeout'); } $_REQUEST['subject'] = isset($_REQUEST['subject']) ? strtr(Util::htmltrim($_POST['subject']), array("\r" => '', "\n" => '', "\t" => '')) : ''; $_REQUEST['to'] = empty($_POST['to']) ? empty($_GET['to']) ? '' : $_GET['to'] : $_POST['to']; $_REQUEST['bcc'] = empty($_POST['bcc']) ? empty($_GET['bcc']) ? '' : $_GET['bcc'] : $_POST['bcc']; // Route the input from the 'u' parameter to the 'to'-list. if (!empty($_POST['u'])) { $_POST['recipient_to'] = explode(',', $_POST['u']); } // Construct the list of recipients. $recipientList = array(); $namedRecipientList = array(); $namesNotFound = array(); foreach (array('to', 'bcc') as $recipientType) { // First, let's see if there's user ID's given. $recipientList[$recipientType] = array(); if (!empty($_POST['recipient_' . $recipientType]) && is_array($_POST['recipient_' . $recipientType])) { foreach ($_POST['recipient_' . $recipientType] as $recipient) { $recipientList[$recipientType][] = (int) $recipient; } } // Are there also literal names set? if (!empty($_REQUEST[$recipientType])) { // We're going to take out the "s anyway ;). $recipientString = strtr($_REQUEST[$recipientType], array('\\"' => '"')); preg_match_all('~"([^"]+)"~', $recipientString, $matches); $namedRecipientList[$recipientType] = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $recipientString)))); // Clean any literal names entered foreach ($namedRecipientList[$recipientType] as $index => $recipient) { if (strlen(trim($recipient)) > 0) { $namedRecipientList[$recipientType][$index] = Util::htmlspecialchars(Util::strtolower(trim($recipient))); } else { unset($namedRecipientList[$recipientType][$index]); } } // Now see if we can resolove the entered name to an actual user if (!empty($namedRecipientList[$recipientType])) { $foundMembers = findMembers($namedRecipientList[$recipientType]); // Assume all are not found, until proven otherwise. $namesNotFound[$recipientType] = $namedRecipientList[$recipientType]; // Make sure we only have each member listed once, incase they did not use the select list foreach ($foundMembers as $member) { $testNames = array(Util::strtolower($member['username']), Util::strtolower($member['name']), Util::strtolower($member['email'])); if (count(array_intersect($testNames, $namedRecipientList[$recipientType])) !== 0) { $recipientList[$recipientType][] = $member['id']; // Get rid of this username, since we found it. $namesNotFound[$recipientType] = array_diff($namesNotFound[$recipientType], $testNames); } } } } // Selected a recipient to be deleted? Remove them now. if (!empty($_POST['delete_recipient'])) { $recipientList[$recipientType] = array_diff($recipientList[$recipientType], array((int) $_POST['delete_recipient'])); } // Make sure we don't include the same name twice $recipientList[$recipientType] = array_unique($recipientList[$recipientType]); } // Are we changing the recipients some how? $is_recipient_change = !empty($_POST['delete_recipient']) || !empty($_POST['to_submit']) || !empty($_POST['bcc_submit']); // Check if there's at least one recipient. if (empty($recipientList['to']) && empty($recipientList['bcc'])) { $post_errors->addError('no_to'); } // Make sure that we remove the members who did get it from the screen. if (!$is_recipient_change) { foreach (array_keys($recipientList) as $recipientType) { if (!empty($namesNotFound[$recipientType])) { $post_errors->addError('bad_' . $recipientType); // Since we already have a post error, remove the previous one. $post_errors->removeError('no_to'); foreach ($namesNotFound[$recipientType] as $name) { $context['send_log']['failed'][] = sprintf($txt['pm_error_user_not_found'], $name); } } } } // Did they make any mistakes like no subject or message? if ($_REQUEST['subject'] == '') { $post_errors->addError('no_subject'); } if (!isset($_REQUEST['message']) || $_REQUEST['message'] == '') { $post_errors->addError('no_message'); } elseif (!empty($modSettings['max_messageLength']) && Util::strlen($_REQUEST['message']) > $modSettings['max_messageLength']) { $post_errors->addError('long_message'); } else { // Preparse the message. $message = $_REQUEST['message']; preparsecode($message); // Make sure there's still some content left without the tags. if (Util::htmltrim(strip_tags(parse_bbc(Util::htmlspecialchars($message, ENT_QUOTES), false), '<img>')) === '' && (!allowedTo('admin_forum') || strpos($message, '[html]') === false)) { $post_errors->addError('no_message'); } } // Wrong verification code? if (!$user_info['is_admin'] && !isset($_REQUEST['xml']) && !empty($modSettings['pm_posts_verification']) && $user_info['posts'] < $modSettings['pm_posts_verification']) { require_once SUBSDIR . '/VerificationControls.class.php'; $verificationOptions = array('id' => 'pm'); $context['require_verification'] = create_control_verification($verificationOptions, true); if (is_array($context['require_verification'])) { foreach ($context['require_verification'] as $error) { $post_errors->addError($error); } } } // If they made any errors, give them a chance to make amends. if ($post_errors->hasErrors() && !$is_recipient_change && !isset($_REQUEST['preview']) && !isset($_REQUEST['xml'])) { return messagePostError($namedRecipientList, $recipientList); } // Want to take a second glance before you send? if (isset($_REQUEST['preview'])) { // Set everything up to be displayed. $context['preview_subject'] = Util::htmlspecialchars($_REQUEST['subject']); $context['preview_message'] = Util::htmlspecialchars($_REQUEST['message'], ENT_QUOTES, 'UTF-8', true); preparsecode($context['preview_message'], true); // Parse out the BBC if it is enabled. $context['preview_message'] = parse_bbc($context['preview_message']); // Censor, as always. censorText($context['preview_subject']); censorText($context['preview_message']); // Set a descriptive title. $context['page_title'] = $txt['preview'] . ' - ' . $context['preview_subject']; // Pretend they messed up but don't ignore if they really did :P. return messagePostError($namedRecipientList, $recipientList); } elseif ($is_recipient_change) { // Maybe we couldn't find one? foreach ($namesNotFound as $recipientType => $names) { $post_errors->addError('bad_' . $recipientType); foreach ($names as $name) { $context['send_log']['failed'][] = sprintf($txt['pm_error_user_not_found'], $name); } } return messagePostError($namedRecipientList, $recipientList); } // Want to save this as a draft and think about it some more? if ($context['drafts_pm_save'] && isset($_POST['save_draft'])) { savePMDraft($recipientList); return messagePostError($namedRecipientList, $recipientList); } elseif (!empty($modSettings['max_pm_recipients']) && count($recipientList['to']) + count($recipientList['bcc']) > $modSettings['max_pm_recipients'] && !allowedTo(array('moderate_forum', 'send_mail', 'admin_forum'))) { $context['send_log'] = array('sent' => array(), 'failed' => array(sprintf($txt['pm_too_many_recipients'], $modSettings['max_pm_recipients']))); return messagePostError($namedRecipientList, $recipientList); } // Protect from message spamming. spamProtection('pm'); // Prevent double submission of this form. checkSubmitOnce('check'); // Finally do the actual sending of the PM. if (!empty($recipientList['to']) || !empty($recipientList['bcc'])) { $context['send_log'] = sendpm($recipientList, $_REQUEST['subject'], $_REQUEST['message'], true, null, !empty($_REQUEST['pm_head']) ? (int) $_REQUEST['pm_head'] : 0); } else { $context['send_log'] = array('sent' => array(), 'failed' => array()); } // Mark the message as "replied to". if (!empty($context['send_log']['sent']) && !empty($_REQUEST['replied_to']) && isset($_REQUEST['f']) && $_REQUEST['f'] == 'inbox') { require_once SUBSDIR . '/PersonalMessage.subs.php'; setPMRepliedStatus($user_info['id'], (int) $_REQUEST['replied_to']); } // If one or more of the recipients were invalid, go back to the post screen with the failed usernames. if (!empty($context['send_log']['failed'])) { return messagePostError($namesNotFound, array('to' => array_intersect($recipientList['to'], $context['send_log']['failed']), 'bcc' => array_intersect($recipientList['bcc'], $context['send_log']['failed']))); } // Message sent successfully? if (!empty($context['send_log']) && empty($context['send_log']['failed'])) { $context['current_label_redirect'] = $context['current_label_redirect'] . ';done=sent'; // If we had a PM draft for this one, then its time to remove it since it was just sent if ($context['drafts_pm_save'] && !empty($_POST['id_pm_draft'])) { deleteDrafts($_POST['id_pm_draft'], $user_info['id']); } } // Go back to the where they sent from, if possible... redirectexit($context['current_label_redirect']); }
/** * Adding or editing a block. */ public function action_sportal_admin_block_edit() { global $txt, $context, $modSettings, $boards; // Just in case, the admin could be doing something silly like editing a SP block while SP is disabled. ;) require_once SUBSDIR . '/PortalBlocks.subs.php'; $context['SPortal']['is_new'] = empty($_REQUEST['block_id']); // BBC Fix move the parameter to the correct position. if (!empty($_POST['bbc_name'])) { $_POST['parameters'][$_POST['bbc_name']] = !empty($_POST[$_POST['bbc_parameter']]) ? $_POST[$_POST['bbc_parameter']] : ''; // If we came from WYSIWYG then turn it back into BBC regardless. if (!empty($_REQUEST['bbc_' . $_POST['bbc_name'] . '_mode']) && isset($_POST['parameters'][$_POST['bbc_name']])) { require_once SUBSDIR . 'Html2BBC.class.php'; $bbc_converter = new Convert_BBC($_POST['parameters'][$_POST['bbc_name']]); $_POST['parameters'][$_POST['bbc_name']] = $bbc_converter->get_bbc(); // We need to unhtml it now as it gets done shortly. $_POST['parameters'][$_POST['bbc_name']] = un_htmlspecialchars($_POST['parameters'][$_POST['bbc_name']]); } } // Passing the selected type via $_GET instead of $_POST? $start_parameters = array(); if (!empty($_GET['selected_type']) && empty($_POST['selected_type'])) { $_POST['selected_type'] = array($_GET['selected_type']); if (!empty($_GET['parameters'])) { foreach ($_GET['parameters'] as $param) { if (isset($_GET[$param])) { $start_parameters[$param] = $_GET[$param]; } } } } // Want use a block on the portal? if ($context['SPortal']['is_new'] && empty($_POST['selected_type']) && empty($_POST['add_block'])) { // Gather the blocks we have available $context['SPortal']['block_types'] = getFunctionInfo(); // Create a list of the blocks in use $in_use = getBlockInfo(); foreach ($in_use as $block) { $context['SPortal']['block_inuse'][$block['type']] = array('state' => $block['state'], 'column' => $block['column']); } $context['location'] = array(1 => $txt['sp-positionLeft'], $txt['sp-positionTop'], $txt['sp-positionBottom'], $txt['sp-positionRight'], $txt['sp-positionHeader'], $txt['sp-positionFooter']); if (!empty($_REQUEST['col'])) { $context['SPortal']['block']['column'] = $_REQUEST['col']; } $context['sub_template'] = 'block_select_type'; $context['page_title'] = $txt['sp-blocksAdd']; } elseif ($context['SPortal']['is_new'] && !empty($_POST['selected_type'])) { $context['SPortal']['block'] = array('id' => 0, 'label' => $txt['sp-blocksDefaultLabel'], 'type' => $_POST['selected_type'][0], 'type_text' => !empty($txt['sp_function_' . $_POST['selected_type'][0] . '_label']) ? $txt['sp_function_' . $_POST['selected_type'][0] . '_label'] : $txt['sp_function_unknown_label'], 'column' => !empty($_POST['block_column']) ? $_POST['block_column'] : 0, 'row' => 0, 'permissions' => 3, 'state' => 1, 'force_view' => 0, 'mobile_view' => 0, 'display' => '', 'display_custom' => '', 'style' => '', 'parameters' => !empty($start_parameters) ? $start_parameters : array(), 'options' => $_POST['selected_type'][0](array(), false, true), 'list_blocks' => !empty($_POST['block_column']) ? getBlockInfo($_POST['block_column']) : array()); } elseif (!$context['SPortal']['is_new'] && empty($_POST['add_block'])) { $_REQUEST['block_id'] = (int) $_REQUEST['block_id']; $context['SPortal']['block'] = current(getBlockInfo(null, $_REQUEST['block_id'])); $context['SPortal']['block'] += array('options' => $context['SPortal']['block']['type'](array(), false, true), 'list_blocks' => getBlockInfo($context['SPortal']['block']['column'])); } // Want to take a look at how this block will appear, well we try our best if (!empty($_POST['preview_block']) || isset($_SESSION['sp_error'])) { // An error was generated on save, lets set things up like a preview and return to the preview if (isset($_SESSION['sp_error'])) { $context['SPortal']['error'] = $_SESSION['sp_error']; $_POST = $_SESSION['sp_error_post']; $_POST['preview_block'] = true; // Clean up unset($_SESSION['sp_error'], $_SESSION['sp_error_post'], $_POST['add_block']); } // Just in case, the admin could be doing something silly like editing a SP block while SP is disabled. ;) require_once BOARDDIR . '/SSI.php'; sportal_init_headers(); loadTemplate('Portal'); $type_parameters = $_POST['block_type'](array(), 0, true); if (!empty($_POST['parameters']) && is_array($_POST['parameters']) && !empty($type_parameters)) { foreach ($type_parameters as $name => $type) { if (isset($_POST['parameters'][$name])) { $this->_prepare_parameters($type, $name); } } } else { $_POST['parameters'] = array(); } // Simple is clean if (empty($_POST['display_advanced'])) { if (!empty($_POST['display_simple']) && in_array($_POST['display_simple'], array('all', 'sportal', 'sforum', 'allaction', 'allboard', 'allpages'))) { $display = $_POST['display_simple']; } else { $display = ''; } $custom = ''; } else { $display = array(); $custom = array(); if (!empty($_POST['display_actions'])) { foreach ($_POST['display_actions'] as $action) { $display[] = Util::htmlspecialchars($action, ENT_QUOTES); } } if (!empty($_POST['display_boards'])) { foreach ($_POST['display_boards'] as $board) { $display[] = 'b' . (int) substr($board, 1); } } if (!empty($_POST['display_pages'])) { foreach ($_POST['display_pages'] as $page) { $display[] = 'p' . (int) substr($page, 1); } } if (!empty($_POST['display_custom'])) { $temp = explode(',', $_POST['display_custom']); foreach ($temp as $action) { $custom[] = Util::htmlspecialchars(Util::htmltrim($action), ENT_QUOTES); } } $display = empty($display) ? '' : implode(',', $display); $custom = empty($custom) ? '' : implode(',', $custom); } // Create all the information we know about this block $context['SPortal']['block'] = array('id' => $_POST['block_id'], 'label' => Util::htmlspecialchars($_POST['block_name'], ENT_QUOTES), 'type' => $_POST['block_type'], 'type_text' => !empty($txt['sp_function_' . $_POST['block_type'] . '_label']) ? $txt['sp_function_' . $_POST['block_type'] . '_label'] : $txt['sp_function_unknown_label'], 'column' => $_POST['block_column'], 'row' => !empty($_POST['block_row']) ? $_POST['block_row'] : 0, 'placement' => !empty($_POST['placement']) && in_array($_POST['placement'], array('before', 'after')) ? $_POST['placement'] : '', 'permissions' => $_POST['permissions'], 'state' => !empty($_POST['block_active']), 'force_view' => !empty($_POST['block_force']), 'mobile_view' => !empty($_POST['block_mobile']), 'display' => $display, 'display_custom' => $custom, 'style' => sportal_parse_style('implode'), 'parameters' => !empty($_POST['parameters']) ? $_POST['parameters'] : array(), 'options' => $_POST['block_type'](array(), false, true), 'list_blocks' => getBlockInfo($_POST['block_column']), 'collapsed' => false); if (strpos($modSettings['leftwidth'], '%') !== false || strpos($modSettings['leftwidth'], 'px') !== false) { $context['widths'][1] = $modSettings['leftwidth']; } else { $context['widths'][1] = $modSettings['leftwidth'] . 'px'; } if (strpos($modSettings['rightwidth'], '%') !== false || strpos($modSettings['rightwidth'], 'px') !== false) { $context['widths'][4] = $modSettings['rightwidth']; } else { $context['widths'][4] = $modSettings['rightwidth'] . 'px'; } if (strpos($context['widths'][1], '%') !== false) { $context['widths'][2] = $context['widths'][3] = 100 - ($context['widths'][1] + $context['widths'][4]) . '%'; $context['widths'][5] = $context['widths'][6] = '100%'; } elseif (strpos($context['widths'][1], 'px') !== false) { $context['widths'][2] = $context['widths'][3] = 960 - ($context['widths'][1] + $context['widths'][4]) . 'px'; $context['widths'][5] = $context['widths'][6] = '960px'; } $context['SPortal']['preview'] = true; } if (!empty($_POST['selected_type']) || !empty($_POST['preview_block']) || !$context['SPortal']['is_new'] && empty($_POST['add_block'])) { // Only the admin can use PHP blocks if ($context['SPortal']['block']['type'] == 'sp_php' && !allowedTo('admin_forum')) { fatal_lang_error('cannot_admin_forum', false); } loadLanguage('SPortalHelp', sp_languageSelect('SPortalHelp')); // Load up the permissions $context['SPortal']['block']['permission_profiles'] = sportal_get_profiles(null, 1, 'name'); if (empty($context['SPortal']['block']['permission_profiles'])) { fatal_lang_error('error_sp_no_permission_profiles', false); } $context['simple_actions'] = array('sportal' => $txt['sp-portal'], 'sforum' => $txt['sp-forum'], 'allaction' => $txt['sp-blocksOptionAllActions'], 'allboard' => $txt['sp-blocksOptionAllBoards'], 'allpages' => $txt['sp-blocksOptionAllPages'], 'all' => $txt['sp-blocksOptionEverywhere']); $context['display_actions'] = array('portal' => $txt['sp-portal'], 'forum' => $txt['sp-forum'], 'recent' => $txt['recent_posts'], 'unread' => $txt['unread_topics_visit'], 'unreadreplies' => $txt['unread_replies'], 'profile' => $txt['profile'], 'pm' => $txt['pm_short'], 'calendar' => $txt['calendar'], 'admin' => $txt['admin'], 'login' => $txt['login'], 'register' => $txt['register'], 'post' => $txt['post'], 'stats' => $txt['forum_stats'], 'search' => $txt['search'], 'mlist' => $txt['members_list'], 'moderate' => $txt['moderate'], 'help' => $txt['help'], 'who' => $txt['who_title']); // Load up boards and pages for selection in the template sp_block_template_helpers(); if (empty($context['SPortal']['block']['display'])) { $context['SPortal']['block']['display'] = array('0'); } else { $context['SPortal']['block']['display'] = explode(',', $context['SPortal']['block']['display']); } if (in_array($context['SPortal']['block']['display'][0], array('all', 'sportal', 'sforum', 'allaction', 'allboard', 'allpages')) || $context['SPortal']['is_new'] || empty($context['SPortal']['block']['display'][0]) && empty($context['SPortal']['block']['display_custom'])) { $context['SPortal']['block']['display_type'] = 0; } else { $context['SPortal']['block']['display_type'] = 1; } $context['SPortal']['block']['style'] = sportal_parse_style('explode', $context['SPortal']['block']['style'], !empty($context['SPortal']['preview'])); // Prepare the Textcontent for BBC, only the first bbc will be detected correctly! $firstBBCFound = false; foreach ($context['SPortal']['block']['options'] as $name => $type) { // Selectable Boards :D if ($type == 'board_select' || $type == 'boards') { if (empty($boards)) { require_once SUBSDIR . '/Boards.subs.php'; getBoardTree(); } // Merge the array ;) if (!isset($context['SPortal']['block']['parameters'][$name])) { $context['SPortal']['block']['parameters'][$name] = array(); } elseif (!empty($context['SPortal']['block']['parameters'][$name]) && is_array($context['SPortal']['block']['parameters'][$name])) { $context['SPortal']['block']['parameters'][$name] = implode('|', $context['SPortal']['block']['parameters'][$name]); } $context['SPortal']['block']['board_options'][$name] = array(); $config_variable = !empty($context['SPortal']['block']['parameters'][$name]) ? $context['SPortal']['block']['parameters'][$name] : array(); $config_variable = !is_array($config_variable) ? explode('|', $config_variable) : $config_variable; $context['SPortal']['block']['board_options'][$name] = array(); // Create the list for this Item foreach ($boards as $board) { // Ignore the redirected boards :) if (!empty($board['redirect'])) { continue; } $context['SPortal']['block']['board_options'][$name][$board['id']] = array('value' => $board['id'], 'text' => $board['name'], 'selected' => in_array($board['id'], $config_variable)); } } elseif ($type === 'bbc') { // ELK support only one bbc correct, multiple bbc do not work at the moment if (!$firstBBCFound) { $firstBBCFound = true; // Start Elk BBC System :) require_once SUBSDIR . '/Editor.subs.php'; // Prepare the output :D $form_message = !empty($context['SPortal']['block']['parameters'][$name]) ? $context['SPortal']['block']['parameters'][$name] : ''; // But if it's in HTML world, turn them into htmlspecialchar's so they can be edited! if (strpos($form_message, '[html]') !== false) { $parts = preg_split('~(\\[/code\\]|\\[code(?:=[^\\]]+)?\\])~i', $form_message, -1, PREG_SPLIT_DELIM_CAPTURE); for ($i = 0, $n = count($parts); $i < $n; $i++) { // It goes 0 = outside, 1 = begin tag, 2 = inside, 3 = close tag, repeat. if ($i % 4 == 0) { $parts[$i] = preg_replace_callback('~\\[html\\](.+?)\\[/html\\]~is', create_function('$m', 'return "[html]" . preg_replace(\'~<br\\s?/?>~i\', \'<br /><br />\', "$m[1]") . "[/html]";'), $parts[$i]); } } $form_message = implode('', $parts); } $form_message = preg_replace('~<br(?: /)?' . '>~i', "\n", $form_message); // Prepare the data before i want them inside the textarea $form_message = str_replace(array('"', '<', '>', ' '), array('"', '<', '>', ' '), $form_message); $context['SPortal']['bbc'] = 'bbc_' . $name; $message_data = array('id' => $context['SPortal']['bbc'], 'width' => '95%', 'height' => '200px', 'value' => $form_message, 'form' => 'sp_block'); // Run the ELK bbc editor routine create_control_richedit($message_data); // Store the updated data on the parameters $context['SPortal']['block']['parameters'][$name] = $form_message; } else { $context['SPortal']['block']['options'][$name] = 'textarea'; } } } loadJavascriptFile('portal.js?sp24'); $context['sub_template'] = 'block_edit'; $context['page_title'] = $context['SPortal']['is_new'] ? $txt['sp-blocksAdd'] : $txt['sp-blocksEdit']; } // Want to add / edit a block oo the portal if (!empty($_POST['add_block'])) { checkSession(); // Only the admin can do php here if ($_POST['block_type'] == 'sp_php' && !allowedTo('admin_forum')) { fatal_lang_error('cannot_admin_forum', false); } // Make sure the block name is something safe if (!isset($_POST['block_name']) || Util::htmltrim(Util::htmlspecialchars($_POST['block_name']), ENT_QUOTES) === '') { fatal_lang_error('error_sp_name_empty', false); } if ($_POST['block_type'] == 'sp_php' && !empty($_POST['parameters']['content']) && empty($modSettings['sp_disable_php_validation'])) { require_once SUBSDIR . '/DataValidator.class.php'; $validator = new Data_Validator(); $validator->validation_rules(array('content' => 'php_syntax')); $validator->validate(array('content' => $_POST['parameters']['content'])); $error = $validator->validation_errors(); if ($error) { $_SESSION['sp_error'] = $error[0]; $_SESSION['sp_error_post'] = $_POST; redirectexit('action=admin;area=portalblocks;sa=' . $_REQUEST['sa'] . (!empty($_REQUEST['block_id']) ? ';block_id=' . $_REQUEST['block_id'] : '')); } } // If we have a block ID passed, we must be editing, so the the blocks current data if (!empty($_REQUEST['block_id'])) { $current_data = current(getBlockInfo(null, $_REQUEST['block_id'])); } // Where are we going to place this new block, before, after, no change if (!empty($_POST['placement']) && ($_POST['placement'] === 'before' || $_POST['placement'] === 'after')) { if (!empty($current_data)) { $current_row = $current_data['row']; } else { $current_row = null; } // Before or after the chosen block if ($_POST['placement'] === 'before') { $row = (int) $_POST['block_row']; } else { $row = (int) $_POST['block_row'] + 1; } if (!empty($current_row) && $row > $current_row) { sp_update_block_row($current_row, $row - 1, $_POST['block_column'], true); } else { sp_update_block_row($current_row, $row, $_POST['block_column'], false); } } elseif (!empty($_POST['placement']) && $_POST['placement'] == 'nochange') { $row = 0; } else { $block_id = !empty($_REQUEST['block_id']) ? (int) $_REQUEST['block_id'] : 0; $row = sp_block_nextrow($_POST['block_column'], $block_id); } $type_parameters = $_POST['block_type'](array(), 0, true); if (!empty($_POST['parameters']) && is_array($_POST['parameters']) && !empty($type_parameters)) { foreach ($type_parameters as $name => $type) { // Prepare BBC Content for ELK if (isset($_POST['parameters'][$name])) { $this->_prepare_parameters($type, $name); } } } else { $_POST['parameters'] = array(); } // Standard options if (empty($_POST['display_advanced'])) { if (!empty($_POST['display_simple']) && in_array($_POST['display_simple'], array('all', 'sportal', 'sforum', 'allaction', 'allboard', 'allpages'))) { $display = $_POST['display_simple']; } else { $display = ''; } $custom = ''; } else { $display = array(); if (!empty($_POST['display_actions'])) { foreach ($_POST['display_actions'] as $action) { $display[] = Util::htmlspecialchars($action, ENT_QUOTES); } } if (!empty($_POST['display_boards'])) { foreach ($_POST['display_boards'] as $board) { $display[] = 'b' . (int) substr($board, 1); } } if (!empty($_POST['display_pages'])) { foreach ($_POST['display_pages'] as $page) { $display[] = 'p' . (int) substr($page, 1); } } if (!empty($_POST['display_custom'])) { $custom = array(); $temp = explode(',', $_POST['display_custom']); foreach ($temp as $action) { $custom[] = Util::htmlspecialchars(Util::htmltrim($action), ENT_QUOTES); } } $display = empty($display) ? '' : implode(',', $display); if (!allowedTo('admin_forum') && isset($current_data['display_custom']) && substr($current_data['display_custom'], 0, 4) === '$php') { $custom = $current_data['display_custom']; } elseif (!empty($_POST['display_custom'])) { if (allowedTo('admin_forum') && substr($_POST['display_custom'], 0, 4) === '$php') { $custom = Util::htmlspecialchars($_POST['display_custom'], ENT_QUOTES); } else { $custom = array(); $temp = explode(',', $_POST['display_custom']); foreach ($temp as $action) { $custom[] = Util::htmlspecialchars($action, ENT_QUOTES); } $custom = empty($custom) ? '' : implode(',', $custom); } } else { $custom = ''; } } $blockInfo = array('id' => (int) $_POST['block_id'], 'label' => Util::htmlspecialchars($_POST['block_name'], ENT_QUOTES), 'type' => $_POST['block_type'], 'col' => $_POST['block_column'], 'row' => $row, 'permissions' => (int) $_POST['permissions'], 'state' => !empty($_POST['block_active']) ? 1 : 0, 'force_view' => !empty($_POST['block_force']) ? 1 : 0, 'mobile_view' => !empty($_POST['block_mobile']) ? 1 : 0, 'display' => $display, 'display_custom' => $custom, 'style' => sportal_parse_style('implode')); // Insert a new block in to the portal if ($context['SPortal']['is_new']) { unset($blockInfo['id']); $blockInfo['id'] = sp_block_insert($blockInfo); } else { sp_block_update($blockInfo); } // Save any parameters for the block if (!empty($_POST['parameters'])) { sp_block_insert_parameters($_POST['parameters'], $blockInfo['id']); } redirectexit('action=admin;area=portalblocks'); } }
/** * Set merge options and do the actual merge of two or more topics. * * the merge options screen: * * shows topics to be merged and allows to set some merge options. * * is accessed by ?action=mergetopics;sa=options.and can also internally be called by action_quickmod(). * * uses 'merge_extra_options' sub template of the MergeTopics template. * * the actual merge: * * is accessed with ?action=mergetopics;sa=execute. * * updates the statistics to reflect the merge. * * logs the action in the moderation log. * * sends a notification is sent to all users monitoring this topic. * * redirects to ?action=mergetopics;sa=done. * * @param int[] $topics = array() of topic ids */ public function action_mergeExecute($topics = array()) { global $user_info, $txt, $context, $scripturl, $modSettings; $db = database(); // Check the session. checkSession('request'); require_once SUBSDIR . '/Topic.subs.php'; require_once SUBSDIR . '/Post.subs.php'; // Handle URLs from action_mergeIndex. if (!empty($_GET['from']) && !empty($_GET['to'])) { $topics = array((int) $_GET['from'], (int) $_GET['to']); } // If we came from a form, the topic IDs came by post. if (!empty($_POST['topics']) && is_array($_POST['topics'])) { $topics = $_POST['topics']; } // There's nothing to merge with just one topic... if (empty($topics) || !is_array($topics) || count($topics) == 1) { fatal_lang_error('merge_need_more_topics'); } // Make sure every topic is numeric, or some nasty things could be done with the DB. foreach ($topics as $id => $topic) { $topics[$id] = (int) $topic; } // Joy of all joys, make sure they're not pi**ing about with unapproved topics they can't see :P if ($modSettings['postmod_active']) { $can_approve_boards = !empty($user_info['mod_cache']['ap']) ? $user_info['mod_cache']['ap'] : boardsAllowedTo('approve_posts'); } // Get info about the topics and polls that will be merged. $request = $db->query('', ' SELECT t.id_topic, t.id_board, t.id_poll, t.num_views, t.is_sticky, t.approved, t.num_replies, t.unapproved_posts, m1.subject, m1.poster_time AS time_started, IFNULL(mem1.id_member, 0) AS id_member_started, IFNULL(mem1.real_name, m1.poster_name) AS name_started, m2.poster_time AS time_updated, IFNULL(mem2.id_member, 0) AS id_member_updated, IFNULL(mem2.real_name, m2.poster_name) AS name_updated FROM {db_prefix}topics AS t INNER JOIN {db_prefix}messages AS m1 ON (m1.id_msg = t.id_first_msg) INNER JOIN {db_prefix}messages AS m2 ON (m2.id_msg = t.id_last_msg) LEFT JOIN {db_prefix}members AS mem1 ON (mem1.id_member = m1.id_member) LEFT JOIN {db_prefix}members AS mem2 ON (mem2.id_member = m2.id_member) WHERE t.id_topic IN ({array_int:topic_list}) ORDER BY t.id_first_msg LIMIT ' . count($topics), array('topic_list' => $topics)); if ($db->num_rows($request) < 2) { fatal_lang_error('no_topic_id'); } $num_views = 0; $is_sticky = 0; $boardTotals = array(); $topic_data = array(); $boards = array(); $polls = array(); $firstTopic = 0; while ($row = $db->fetch_assoc($request)) { // Make a note for the board counts... if (!isset($boardTotals[$row['id_board']])) { $boardTotals[$row['id_board']] = array('num_posts' => 0, 'num_topics' => 0, 'unapproved_posts' => 0, 'unapproved_topics' => 0); } // We can't see unapproved topics here? if ($modSettings['postmod_active'] && !$row['approved'] && $can_approve_boards != array(0) && in_array($row['id_board'], $can_approve_boards)) { continue; } elseif (!$row['approved']) { $boardTotals[$row['id_board']]['unapproved_topics']++; } else { $boardTotals[$row['id_board']]['num_topics']++; } $boardTotals[$row['id_board']]['unapproved_posts'] += $row['unapproved_posts']; $boardTotals[$row['id_board']]['num_posts'] += $row['num_replies'] + ($row['approved'] ? 1 : 0); $topic_data[$row['id_topic']] = array('id' => $row['id_topic'], 'board' => $row['id_board'], 'poll' => $row['id_poll'], 'num_views' => $row['num_views'], 'subject' => $row['subject'], 'started' => array('time' => standardTime($row['time_started']), 'html_time' => htmlTime($row['time_started']), 'timestamp' => forum_time(true, $row['time_started']), 'href' => empty($row['id_member_started']) ? '' : $scripturl . '?action=profile;u=' . $row['id_member_started'], 'link' => empty($row['id_member_started']) ? $row['name_started'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member_started'] . '">' . $row['name_started'] . '</a>'), 'updated' => array('time' => standardTime($row['time_updated']), 'html_time' => htmlTime($row['time_updated']), 'timestamp' => forum_time(true, $row['time_updated']), 'href' => empty($row['id_member_updated']) ? '' : $scripturl . '?action=profile;u=' . $row['id_member_updated'], 'link' => empty($row['id_member_updated']) ? $row['name_updated'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member_updated'] . '">' . $row['name_updated'] . '</a>')); $num_views += $row['num_views']; $boards[] = $row['id_board']; // If there's no poll, id_poll == 0... if ($row['id_poll'] > 0) { $polls[] = $row['id_poll']; } // Store the id_topic with the lowest id_first_msg. if (empty($firstTopic)) { $firstTopic = $row['id_topic']; } $is_sticky = max($is_sticky, $row['is_sticky']); } $db->free_result($request); // If we didn't get any topics then they've been messing with unapproved stuff. if (empty($topic_data)) { fatal_lang_error('no_topic_id'); } $boards = array_values(array_unique($boards)); // The parameters of action_mergeExecute were set, so this must've been an internal call. if (!empty($topics)) { isAllowedTo('merge_any', $boards); loadTemplate('MergeTopics'); } // Get the boards a user is allowed to merge in. $merge_boards = boardsAllowedTo('merge_any'); if (empty($merge_boards)) { fatal_lang_error('cannot_merge_any', 'user'); } require_once SUBSDIR . '/Boards.subs.php'; // Make sure they can see all boards.... $query_boards = array('boards' => $boards); if (!in_array(0, $merge_boards)) { $query_boards['boards'] = array_merge($query_boards['boards'], $merge_boards); } // Saved in a variable to (potentially) save a query later $boards_info = fetchBoardsInfo($query_boards); // This happens when a member is moderator of a board he cannot see foreach ($boards as $board) { if (!isset($boards_info[$board])) { fatal_lang_error('no_board'); } } if (empty($_REQUEST['sa']) || $_REQUEST['sa'] == 'options') { if (count($polls) > 1) { $request = $db->query('', ' SELECT t.id_topic, t.id_poll, m.subject, p.question FROM {db_prefix}polls AS p INNER JOIN {db_prefix}topics AS t ON (t.id_poll = p.id_poll) INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg) WHERE p.id_poll IN ({array_int:polls}) LIMIT ' . count($polls), array('polls' => $polls)); while ($row = $db->fetch_assoc($request)) { $context['polls'][] = array('id' => $row['id_poll'], 'topic' => array('id' => $row['id_topic'], 'subject' => $row['subject']), 'question' => $row['question'], 'selected' => $row['id_topic'] == $firstTopic); } $db->free_result($request); } if (count($boards) > 1) { foreach ($boards_info as $row) { $context['boards'][] = array('id' => $row['id_board'], 'name' => $row['name'], 'selected' => $row['id_board'] == $topic_data[$firstTopic]['board']); } } $context['topics'] = $topic_data; foreach ($topic_data as $id => $topic) { $context['topics'][$id]['selected'] = $topic['id'] == $firstTopic; } $context['page_title'] = $txt['merge']; $context['sub_template'] = 'merge_extra_options'; return; } // Determine target board. $target_board = count($boards) > 1 ? (int) $_REQUEST['board'] : $boards[0]; if (!in_array($target_board, $boards)) { fatal_lang_error('no_board'); } // Determine which poll will survive and which polls won't. $target_poll = count($polls) > 1 ? (int) $_POST['poll'] : (count($polls) == 1 ? $polls[0] : 0); if ($target_poll > 0 && !in_array($target_poll, $polls)) { fatal_lang_error('no_access', false); } $deleted_polls = empty($target_poll) ? $polls : array_diff($polls, array($target_poll)); // Determine the subject of the newly merged topic - was a custom subject specified? if (empty($_POST['subject']) && isset($_POST['custom_subject']) && $_POST['custom_subject'] != '') { $target_subject = strtr(Util::htmltrim(Util::htmlspecialchars($_POST['custom_subject'])), array("\r" => '', "\n" => '', "\t" => '')); // Keep checking the length. if (Util::strlen($target_subject) > 100) { $target_subject = Util::substr($target_subject, 0, 100); } // Nothing left - odd but pick the first topics subject. if ($target_subject == '') { $target_subject = $topic_data[$firstTopic]['subject']; } } elseif (!empty($topic_data[(int) $_POST['subject']]['subject'])) { $target_subject = $topic_data[(int) $_POST['subject']]['subject']; } else { $target_subject = $topic_data[$firstTopic]['subject']; } // Get the first and last message and the number of messages.... $request = $db->query('', ' SELECT approved, MIN(id_msg) AS first_msg, MAX(id_msg) AS last_msg, COUNT(*) AS message_count FROM {db_prefix}messages WHERE id_topic IN ({array_int:topics}) GROUP BY approved ORDER BY approved DESC', array('topics' => $topics)); $topic_approved = 1; $first_msg = 0; while ($row = $db->fetch_assoc($request)) { // If this is approved, or is fully unapproved. if ($row['approved'] || !isset($first_msg)) { $first_msg = $row['first_msg']; $last_msg = $row['last_msg']; if ($row['approved']) { $num_replies = $row['message_count'] - 1; $num_unapproved = 0; } else { $topic_approved = 0; $num_replies = 0; $num_unapproved = $row['message_count']; } } else { // If this has a lower first_msg then the first post is not approved and hence the number of replies was wrong! if ($first_msg > $row['first_msg']) { $first_msg = $row['first_msg']; $num_replies++; $topic_approved = 0; } $num_unapproved = $row['message_count']; } } $db->free_result($request); // Ensure we have a board stat for the target board. if (!isset($boardTotals[$target_board])) { $boardTotals[$target_board] = array('num_posts' => 0, 'num_topics' => 0, 'unapproved_posts' => 0, 'unapproved_topics' => 0); } // Fix the topic count stuff depending on what the new one counts as. if ($topic_approved) { $boardTotals[$target_board]['num_topics']--; } else { $boardTotals[$target_board]['unapproved_topics']--; } $boardTotals[$target_board]['unapproved_posts'] -= $num_unapproved; $boardTotals[$target_board]['num_posts'] -= $topic_approved ? $num_replies + 1 : $num_replies; // Get the member ID of the first and last message. $request = $db->query('', ' SELECT id_member FROM {db_prefix}messages WHERE id_msg IN ({int:first_msg}, {int:last_msg}) ORDER BY id_msg LIMIT 2', array('first_msg' => $first_msg, 'last_msg' => $last_msg)); list($member_started) = $db->fetch_row($request); list($member_updated) = $db->fetch_row($request); // First and last message are the same, so only row was returned. if ($member_updated === null) { $member_updated = $member_started; } $db->free_result($request); // Obtain all the message ids we are going to affect. $affected_msgs = messagesInTopics($topics); // Assign the first topic ID to be the merged topic. $id_topic = min($topics); // Grab the response prefix (like 'Re: ') in the default forum language. $context['response_prefix'] = response_prefix(); $enforce_subject = isset($_POST['enforce_subject']) ? Util::htmlspecialchars(trim($_POST['enforce_subject'])) : ''; // Merge topic notifications. $notifications = isset($_POST['notifications']) && is_array($_POST['notifications']) ? array_intersect($topics, $_POST['notifications']) : array(); fixMergedTopics($first_msg, $topics, $id_topic, $target_board, $target_subject, $enforce_subject, $notifications); // Asssign the properties of the newly merged topic. $db->query('', ' UPDATE {db_prefix}topics SET id_board = {int:id_board}, id_member_started = {int:id_member_started}, id_member_updated = {int:id_member_updated}, id_first_msg = {int:id_first_msg}, id_last_msg = {int:id_last_msg}, id_poll = {int:id_poll}, num_replies = {int:num_replies}, unapproved_posts = {int:unapproved_posts}, num_views = {int:num_views}, is_sticky = {int:is_sticky}, approved = {int:approved} WHERE id_topic = {int:id_topic}', array('id_board' => $target_board, 'is_sticky' => $is_sticky, 'approved' => $topic_approved, 'id_topic' => $id_topic, 'id_member_started' => $member_started, 'id_member_updated' => $member_updated, 'id_first_msg' => $first_msg, 'id_last_msg' => $last_msg, 'id_poll' => $target_poll, 'num_replies' => $num_replies, 'unapproved_posts' => $num_unapproved, 'num_views' => $num_views)); // Get rid of the redundant polls. if (!empty($deleted_polls)) { require_once SUBSDIR . '/Poll.subs.php'; removePoll($deleted_polls); } // Cycle through each board... foreach ($boardTotals as $id_board => $stats) { decrementBoard($id_board, $stats); } // Determine the board the final topic resides in $topic_info = getTopicInfo($id_topic); $id_board = $topic_info['id_board']; // Update all the statistics. updateStats('topic'); updateStats('subject', $id_topic, $target_subject); updateLastMessages($boards); logAction('merge', array('topic' => $id_topic, 'board' => $id_board)); // Notify people that these topics have been merged? require_once SUBSDIR . '/Notification.subs.php'; sendNotifications($id_topic, 'merge'); // If there's a search index that needs updating, update it... require_once SUBSDIR . '/Search.subs.php'; $searchAPI = findSearchAPI(); if (is_callable(array($searchAPI, 'topicMerge'))) { $searchAPI->topicMerge($id_topic, $topics, $affected_msgs, empty($enforce_subject) ? null : array($context['response_prefix'], $target_subject)); } // Send them to the all done page. redirectexit('action=mergetopics;sa=done;to=' . $id_topic . ';targetboard=' . $target_board); }
/** * Edit an existing shoutbox or add a new one */ public function action_sportal_admin_shoutbox_edit() { global $txt, $context, $modSettings, $editortxt; $context['SPortal']['is_new'] = empty($_REQUEST['shoutbox_id']); if (!empty($_POST['submit'])) { checkSession(); if (!isset($_POST['name']) || Util::htmltrim(Util::htmlspecialchars($_POST['name'], ENT_QUOTES)) === '') { fatal_lang_error('sp_error_shoutbox_name_empty', false); } // No two the same $has_duplicate = sp_check_duplicate_shoutbox($_POST['name'], $_POST['shoutbox_id']); if (!empty($has_duplicate)) { fatal_lang_error('sp_error_shoutbox_name_duplicate', false); } if (isset($_POST['moderator_groups']) && is_array($_POST['moderator_groups']) && count($_POST['moderator_groups']) > 0) { foreach ($_POST['moderator_groups'] as $id => $group) { $_POST['moderator_groups'][$id] = (int) $group; } $_POST['moderator_groups'] = implode(',', $_POST['moderator_groups']); } else { $_POST['moderator_groups'] = ''; } if (!empty($_POST['allowed_bbc']) && is_array($_POST['allowed_bbc'])) { foreach ($_POST['allowed_bbc'] as $id => $tag) { $_POST['allowed_bbc'][$id] = Util::htmlspecialchars($tag, ENT_QUOTES); } $_POST['allowed_bbc'] = implode(',', $_POST['allowed_bbc']); } else { $_POST['allowed_bbc'] = ''; } $shoutbox_info = array('id' => (int) $_POST['shoutbox_id'], 'name' => Util::htmlspecialchars($_POST['name'], ENT_QUOTES), 'permissions' => (int) $_POST['permissions'], 'moderator_groups' => $_POST['moderator_groups'], 'warning' => Util::htmlspecialchars($_POST['warning'], ENT_QUOTES), 'allowed_bbc' => $_POST['allowed_bbc'], 'height' => (int) $_POST['height'], 'num_show' => (int) $_POST['num_show'], 'num_max' => (int) $_POST['num_max'], 'reverse' => !empty($_POST['reverse']) ? 1 : 0, 'caching' => !empty($_POST['caching']) ? 1 : 0, 'refresh' => (int) $_POST['refresh'], 'status' => !empty($_POST['status']) ? 1 : 0); // Update existing or add a new shoutbox $shoutbox_info['id'] = sp_edit_shoutbox($shoutbox_info, $context['SPortal']['is_new']); sportal_update_shoutbox($shoutbox_info['id']); if ($context['SPortal']['is_new'] && allowedTo(array('sp_admin', 'sp_manage_blocks'))) { redirectexit('action=admin;area=portalshoutbox;sa=blockredirect;shoutbox=' . $shoutbox_info['id']); } else { redirectexit('action=admin;area=portalshoutbox'); } } if ($context['SPortal']['is_new']) { $context['SPortal']['shoutbox'] = array('id' => 0, 'name' => $txt['sp_shoutbox_default_name'], 'permissions' => 3, 'moderator_groups' => array(), 'warning' => '', 'allowed_bbc' => array('b', 'i', 'u', 's', 'url', 'code', 'quote', 'me'), 'height' => 200, 'num_show' => 20, 'num_max' => 1000, 'reverse' => 0, 'caching' => 1, 'refresh' => 0, 'status' => 1); } else { $_REQUEST['shoutbox_id'] = (int) $_REQUEST['shoutbox_id']; $context['SPortal']['shoutbox'] = sportal_get_shoutbox($_REQUEST['shoutbox_id']); } loadLanguage('Editor'); $context['SPortal']['shoutbox']['permission_profiles'] = sportal_get_profiles(null, 1, 'name'); sp_loadMemberGroups($context['SPortal']['shoutbox']['moderator_groups'], 'moderator', 'moderator_groups'); if (empty($context['SPortal']['shoutbox']['permission_profiles'])) { fatal_lang_error('error_sp_no_permission_profiles', false); } $context['allowed_bbc'] = array('b' => $editortxt['Bold'], 'i' => $editortxt['Italic'], 'u' => $editortxt['Underline'], 's' => $editortxt['Strikethrough'], 'pre' => $editortxt['Preformatted Text'], 'img' => $editortxt['Insert an image'], 'url' => $editortxt['Insert a link'], 'email' => $editortxt['Insert an email'], 'sup' => $editortxt['Superscript'], 'sub' => $editortxt['Subscript'], 'tt' => $editortxt['Teletype'], 'code' => $editortxt['Code'], 'quote' => $editortxt['Insert a Quote'], 'size' => $editortxt['Font Size'], 'font' => $editortxt['Font Name'], 'color' => $editortxt['Font Color'], 'me' => 'me'); $disabled_tags = array(); if (!empty($modSettings['disabledBBC'])) { $disabled_tags = explode(',', $modSettings['disabledBBC']); } if (empty($modSettings['enableEmbeddedFlash'])) { $disabled_tags[] = 'flash'; } foreach ($disabled_tags as $tag) { if ($tag == 'list') { $context['disabled_tags']['orderlist'] = true; } $context['disabled_tags'][trim($tag)] = true; } $context['page_title'] = $context['SPortal']['is_new'] ? $txt['sp_admin_shoutbox_add'] : $txt['sp_admin_shoutbox_edit']; $context['sub_template'] = 'shoutbox_edit'; }