Advertisement
Guest User

Clean version of post.php from RC2

a guest
Jun 4th, 2020
61
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 115.61 KB | None | 0 0
  1. <?php
  2.  
  3. /**
  4.  * The job of this file is to handle everything related to posting replies,
  5.  * new topics, quotes, and modifications to existing posts.  It also handles
  6.  * quoting posts by way of javascript.
  7.  * Simple Machines Forum (SMF)
  8.  *
  9.  * @package SMF
  10.  * @author Simple Machines http://www.simplemachines.org
  11.  * @copyright 2019 Simple Machines and individual contributors
  12.  * @license http://www.simplemachines.org/about/smf/license.php BSD
  13.  *
  14.  * @version 2.1 RC2
  15.  */
  16.  
  17. if (!defined('SMF'))
  18.     die('No direct access...');
  19.  
  20. /**
  21.  * Handles showing the post screen, loading the post to be modified, and loading any post quoted.
  22.  *
  23.  * - additionally handles previews of posts.
  24.  * - @uses the Post template and language file, main sub template.
  25.  * - requires different permissions depending on the actions, but most notably post_new, post_reply_own, and post_reply_any.
  26.  * - shows options for the editing and posting of calendar events and attachments, as well as the posting of polls.
  27.  * - accessed from ?action=post.
  28.  *
  29.  * @param array $post_errors Holds any errors found while tyring to post
  30.  */
  31. function Post($post_errors = array())
  32. {
  33.     global $txt, $scripturl, $topic, $modSettings, $board;
  34.     global $user_info, $context, $settings;
  35.     global $sourcedir, $smcFunc, $language;
  36.  
  37.     loadLanguage('Post');
  38.     if (!empty($modSettings['drafts_post_enabled']))
  39.         loadLanguage('Drafts');
  40.  
  41.     // You can't reply with a poll... hacker.
  42.     if (isset($_REQUEST['poll']) && !empty($topic) && !isset($_REQUEST['msg']))
  43.         unset($_REQUEST['poll']);
  44.  
  45.     // Posting an event?
  46.     $context['make_event'] = isset($_REQUEST['calendar']);
  47.     $context['robot_no_index'] = true;
  48.  
  49.     call_integration_hook('integrate_post_start');
  50.  
  51.     // Get notification preferences for later
  52.     require_once($sourcedir . '/Subs-Notify.php');
  53.     // use $temp to get around "Only variables should be passed by reference"
  54.     $temp = getNotifyPrefs($user_info['id']);
  55.     $context['notify_prefs'] = (array) array_pop($temp);
  56.     $context['auto_notify'] = !empty($context['notify_prefs']['msg_auto_notify']);
  57.  
  58.     // Not in a board? Fine, but we'll make them pick one eventually.
  59.     if (empty($board) || $context['make_event'])
  60.     {
  61.         // Get ids of all the boards they can post in.
  62.         $post_permissions = array('post_new');
  63.         if ($modSettings['postmod_active'])
  64.             $post_permissions[] = 'post_unapproved_topics';
  65.  
  66.         $boards = boardsAllowedTo($post_permissions);
  67.         if (empty($boards))
  68.             fatal_lang_error('cannot_post_new', false);
  69.  
  70.         // Get a list of boards for the select menu
  71.         require_once($sourcedir . '/Subs-MessageIndex.php');
  72.         $boardListOptions = array(
  73.             'included_boards' => in_array(0, $boards) ? null : $boards,
  74.             'not_redirection' => true,
  75.             'use_permissions' => true,
  76.             'selected_board' => !empty($board) ? $board : ($context['make_event'] && !empty($modSettings['cal_defaultboard']) ? $modSettings['cal_defaultboard'] : $boards[0]),
  77.         );
  78.         $board_list = getBoardList($boardListOptions);
  79.     }
  80.     // Let's keep things simple for ourselves below
  81.     else
  82.         $boards = array($board);
  83.  
  84.     require_once($sourcedir . '/Subs-Post.php');
  85.  
  86.     if (isset($_REQUEST['xml']))
  87.     {
  88.         $context['sub_template'] = 'post';
  89.  
  90.         // Just in case of an earlier error...
  91.         $context['preview_message'] = '';
  92.         $context['preview_subject'] = '';
  93.     }
  94.  
  95.     // No message is complete without a topic.
  96.     if (empty($topic) && !empty($_REQUEST['msg']))
  97.     {
  98.         $request = $smcFunc['db_query']('', '
  99.             SELECT id_topic
  100.             FROM {db_prefix}messages
  101.             WHERE id_msg = {int:msg}',
  102.             array(
  103.                 'msg' => (int) $_REQUEST['msg'],
  104.             )
  105.         );
  106.         if ($smcFunc['db_num_rows']($request) != 1)
  107.             unset($_REQUEST['msg'], $_POST['msg'], $_GET['msg']);
  108.         else
  109.             list ($topic) = $smcFunc['db_fetch_row']($request);
  110.         $smcFunc['db_free_result']($request);
  111.     }
  112.  
  113.     // Check if it's locked. It isn't locked if no topic is specified.
  114.     if (!empty($topic))
  115.     {
  116.         $request = $smcFunc['db_query']('', '
  117.             SELECT
  118.                 t.locked, t.approved, COALESCE(ln.id_topic, 0) AS notify, t.is_sticky, t.id_poll, t.id_last_msg, mf.id_member,
  119.                 t.id_first_msg, mf.subject, ml.modified_reason,
  120.                 CASE WHEN ml.poster_time > ml.modified_time THEN ml.poster_time ELSE ml.modified_time END AS last_post_time
  121.             FROM {db_prefix}topics AS t
  122.                 LEFT JOIN {db_prefix}log_notify AS ln ON (ln.id_topic = t.id_topic AND ln.id_member = {int:current_member})
  123.                 LEFT JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg)
  124.                 LEFT JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
  125.             WHERE t.id_topic = {int:current_topic}
  126.             LIMIT 1',
  127.             array(
  128.                 'current_member' => $user_info['id'],
  129.                 'current_topic' => $topic,
  130.             )
  131.         );
  132.         list ($locked, $topic_approved, $context['notify'], $sticky, $pollID, $context['topic_last_message'], $id_member_poster, $id_first_msg, $first_subject, $editReason, $lastPostTime) = $smcFunc['db_fetch_row']($request);
  133.         $smcFunc['db_free_result']($request);
  134.  
  135.         // If this topic already has a poll, they sure can't add another.
  136.         if (isset($_REQUEST['poll']) && $pollID > 0)
  137.             unset($_REQUEST['poll']);
  138.  
  139.         if (empty($_REQUEST['msg']))
  140.         {
  141.             if ($user_info['is_guest'] && !allowedTo('post_reply_any') && (!$modSettings['postmod_active'] || !allowedTo('post_unapproved_replies_any')))
  142.                 is_not_guest();
  143.  
  144.             // By default the reply will be approved...
  145.             $context['becomes_approved'] = true;
  146.             if ($id_member_poster != $user_info['id'] || $user_info['is_guest'])
  147.             {
  148.                 if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_any') && !allowedTo('post_reply_any'))
  149.                     $context['becomes_approved'] = false;
  150.                 else
  151.                     isAllowedTo('post_reply_any');
  152.             }
  153.             elseif (!allowedTo('post_reply_any'))
  154.             {
  155.                 if ($modSettings['postmod_active'] && ((allowedTo('post_unapproved_replies_own') && !allowedTo('post_reply_own')) || allowedTo('post_unapproved_replies_any')))
  156.                     $context['becomes_approved'] = false;
  157.                 else
  158.                     isAllowedTo('post_reply_own');
  159.             }
  160.         }
  161.         else
  162.             $context['becomes_approved'] = true;
  163.  
  164.         $context['can_lock'] = allowedTo('lock_any') || ($user_info['id'] == $id_member_poster && allowedTo('lock_own'));
  165.         $context['can_sticky'] = allowedTo('make_sticky');
  166.         $context['can_move'] = allowedTo('move_any');
  167.         // You can only announce topics that will get approved...
  168.         $context['can_announce'] = allowedTo('announce_topic') && $context['becomes_approved'];
  169.         $context['show_approval'] = !allowedTo('approve_posts') ? 0 : ($context['becomes_approved'] ? 2 : 1);
  170.  
  171.         // We don't always want the request vars to override what's in the db...
  172.         $context['already_locked'] = $locked;
  173.         $context['already_sticky'] = $sticky;
  174.         $context['sticky'] = isset($_REQUEST['sticky']) ? !empty($_REQUEST['sticky']) : $sticky;
  175.  
  176.         // Check whether this is a really old post being bumped...
  177.         if (!empty($modSettings['oldTopicDays']) && $lastPostTime + $modSettings['oldTopicDays'] * 86400 < time() && empty($sticky) && !isset($_REQUEST['subject']))
  178.             $post_errors[] = array('old_topic', array($modSettings['oldTopicDays']));
  179.     }
  180.     else
  181.     {
  182.         // @todo Should use JavaScript to hide and show the warning based on the selection in the board select menu
  183.         $context['becomes_approved'] = true;
  184.         if ($modSettings['postmod_active'] && !allowedTo('post_new', $boards, true) && allowedTo('post_unapproved_topics', $boards, true))
  185.             $context['becomes_approved'] = false;
  186.         else
  187.             isAllowedTo('post_new', $boards, true);
  188.  
  189.         $locked = 0;
  190.         $context['already_locked'] = 0;
  191.         $context['already_sticky'] = 0;
  192.         $context['sticky'] = !empty($_REQUEST['sticky']);
  193.  
  194.         // What options should we show?
  195.         $context['can_lock'] = allowedTo(array('lock_any', 'lock_own'), $boards, true);
  196.         $context['can_sticky'] = allowedTo('make_sticky', $boards, true);
  197.         $context['can_move'] = allowedTo('move_any', $boards, true);
  198.         $context['can_announce'] = allowedTo('announce_topic', $boards, true) && $context['becomes_approved'];
  199.         $context['show_approval'] = !allowedTo('approve_posts', $boards, true) ? 0 : ($context['becomes_approved'] ? 2 : 1);
  200.     }
  201.  
  202.     $context['notify'] = !empty($context['notify']);
  203.  
  204.     $context['can_notify'] = !$context['user']['is_guest'];
  205.     $context['move'] = !empty($_REQUEST['move']);
  206.     $context['announce'] = !empty($_REQUEST['announce']);
  207.     $context['locked'] = !empty($locked) || !empty($_REQUEST['lock']);
  208.     $context['can_quote'] = empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC']));
  209.  
  210.     // An array to hold all the attachments for this topic.
  211.     $context['current_attachments'] = array();
  212.  
  213.     // Clear out prior attachment activity when starting afresh
  214.     if (empty($_REQUEST['message']) && empty($_REQUEST['preview']) && !empty($_SESSION['already_attached']))
  215.     {
  216.         require_once($sourcedir . '/ManageAttachments.php');
  217.         foreach ($_SESSION['already_attached'] as $attachID => $attachment)
  218.             removeAttachments(array('id_attach' => $attachID));
  219.  
  220.         unset($_SESSION['already_attached']);
  221.     }
  222.  
  223.     // Don't allow a post if it's locked and you aren't all powerful.
  224.     if ($locked && !allowedTo('moderate_board'))
  225.         fatal_lang_error('topic_locked', false);
  226.     // Check the users permissions - is the user allowed to add or post a poll?
  227.     if (isset($_REQUEST['poll']) && $modSettings['pollMode'] == '1')
  228.     {
  229.         // New topic, new poll.
  230.         if (empty($topic))
  231.             isAllowedTo('poll_post');
  232.         // This is an old topic - but it is yours!  Can you add to it?
  233.         elseif ($user_info['id'] == $id_member_poster && !allowedTo('poll_add_any'))
  234.             isAllowedTo('poll_add_own');
  235.         // If you're not the owner, can you add to any poll?
  236.         else
  237.             isAllowedTo('poll_add_any');
  238.  
  239.         if (!empty($board))
  240.         {
  241.             require_once($sourcedir . '/Subs-Members.php');
  242.             $allowedVoteGroups = groupsAllowedTo('poll_vote', $board);
  243.             $guest_vote_enabled = in_array(-1, $allowedVoteGroups['allowed']);
  244.         }
  245.         // No board, so we'll have to check this again in Post2
  246.         else
  247.             $guest_vote_enabled = true;
  248.  
  249.         // Set up the poll options.
  250.         $context['poll_options'] = array(
  251.             'max_votes' => empty($_POST['poll_max_votes']) ? '1' : max(1, $_POST['poll_max_votes']),
  252.             'hide' => empty($_POST['poll_hide']) ? 0 : $_POST['poll_hide'],
  253.             'expire' => !isset($_POST['poll_expire']) ? '' : $_POST['poll_expire'],
  254.             'change_vote' => isset($_POST['poll_change_vote']),
  255.             'guest_vote' => isset($_POST['poll_guest_vote']),
  256.             'guest_vote_enabled' => $guest_vote_enabled,
  257.         );
  258.  
  259.         // Make all five poll choices empty.
  260.         $context['choices'] = array(
  261.             array('id' => 0, 'number' => 1, 'label' => '', 'is_last' => false),
  262.             array('id' => 1, 'number' => 2, 'label' => '', 'is_last' => false),
  263.             array('id' => 2, 'number' => 3, 'label' => '', 'is_last' => false),
  264.             array('id' => 3, 'number' => 4, 'label' => '', 'is_last' => false),
  265.             array('id' => 4, 'number' => 5, 'label' => '', 'is_last' => true)
  266.         );
  267.         $context['last_choice_id'] = 4;
  268.     }
  269.  
  270.     if ($context['make_event'])
  271.     {
  272.         // They might want to pick a board.
  273.         if (!isset($context['current_board']))
  274.             $context['current_board'] = 0;
  275.  
  276.         // Start loading up the event info.
  277.         $context['event'] = array();
  278.         $context['event']['title'] = isset($_REQUEST['evtitle']) ? $smcFunc['htmlspecialchars'](stripslashes($_REQUEST['evtitle'])) : '';
  279.         $context['event']['location'] = isset($_REQUEST['event_location']) ? $smcFunc['htmlspecialchars'](stripslashes($_REQUEST['event_location'])) : '';
  280.  
  281.         $context['event']['id'] = isset($_REQUEST['eventid']) ? (int) $_REQUEST['eventid'] : -1;
  282.         $context['event']['new'] = $context['event']['id'] == -1;
  283.  
  284.         // Permissions check!
  285.         isAllowedTo('calendar_post');
  286.  
  287.         // We want a fairly compact version of the time, but as close as possible to the user's settings.
  288.         if (preg_match('~%[HkIlMpPrRSTX](?:[^%]*%[HkIlMpPrRSTX])*~', $user_info['time_format'], $matches) == 0 || empty($matches[0]))
  289.             $time_string = '%k:%M';
  290.         else
  291.             $time_string = str_replace(array('%I', '%H', '%S', '%r', '%R', '%T'), array('%l', '%k', '', '%l:%M %p', '%k:%M', '%l:%M'), $matches[0]);
  292.  
  293.         $js_time_string = str_replace(
  294.             array('%H', '%k', '%I', '%l', '%M', '%p', '%P', '%r', '%R', '%S', '%T', '%X'),
  295.             array('H', 'G', 'h', 'g', 'i', 'A', 'a', 'h:i:s A', 'H:i', 's', 'H:i:s', 'H:i:s'),
  296.             $time_string
  297.         );
  298.  
  299.         // Editing an event?  (but NOT previewing!?)
  300.         if (empty($context['event']['new']) && !isset($_REQUEST['subject']))
  301.         {
  302.             // If the user doesn't have permission to edit the post in this topic, redirect them.
  303.             if ((empty($id_member_poster) || $id_member_poster != $user_info['id'] || !allowedTo('modify_own')) && !allowedTo('modify_any'))
  304.             {
  305.                 require_once($sourcedir . '/Calendar.php');
  306.                 return CalendarPost();
  307.             }
  308.  
  309.             // Get the current event information.
  310.             require_once($sourcedir . '/Subs-Calendar.php');
  311.             $eventProperties = getEventProperties($context['event']['id']);
  312.             $context['event'] = array_merge($context['event'], $eventProperties);
  313.         }
  314.         else
  315.         {
  316.             // Get the current event information.
  317.             require_once($sourcedir . '/Subs-Calendar.php');
  318.             $eventProperties = getNewEventDatetimes();
  319.             $context['event'] = array_merge($context['event'], $eventProperties);
  320.  
  321.             // Make sure the year and month are in the valid range.
  322.             if ($context['event']['month'] < 1 || $context['event']['month'] > 12)
  323.                 fatal_lang_error('invalid_month', false);
  324.             if ($context['event']['year'] < $modSettings['cal_minyear'] || $context['event']['year'] > $modSettings['cal_maxyear'])
  325.                 fatal_lang_error('invalid_year', false);
  326.  
  327.             $context['event']['categories'] = $board_list;
  328.         }
  329.  
  330.         // Find the last day of the month.
  331.         $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']));
  332.  
  333.         // An all day event? Set up some nice defaults in case the user wants to change that
  334.         if ($context['event']['allday'] == true)
  335.         {
  336.             $context['event']['tz'] = getUserTimezone();
  337.             $context['event']['start_time'] = timeformat(time(), $time_string);
  338.             $context['event']['end_time'] = timeformat(time() + 3600, $time_string);
  339.         }
  340.         // Otherwise, just adjust these to look nice on the input form
  341.         else
  342.         {
  343.             $context['event']['start_time'] = $context['event']['start_time_orig'];
  344.             $context['event']['end_time'] = $context['event']['end_time_orig'];
  345.         }
  346.  
  347.         // Need this so the user can select a timezone for the event.
  348.         $context['all_timezones'] = smf_list_timezones($context['event']['start_date']);
  349.         unset($context['all_timezones']['']);
  350.  
  351.         // If the event's timezone is not in SMF's standard list of time zones, prepend it to the list
  352.         if (!in_array($context['event']['tz'], array_keys($context['all_timezones'])))
  353.         {
  354.             $d = date_create($context['event']['start_datetime'] . ' ' . $context['event']['tz']);
  355.             $context['all_timezones'] = array($context['event']['tz'] => '[UTC' . date_format($d, 'P') . '] - ' . $context['event']['tz']) + $context['all_timezones'];
  356.         }
  357.  
  358.         loadCSSFile('jquery-ui.datepicker.css', array(), 'smf_datepicker');
  359.         loadCSSFile('jquery.timepicker.css', array(), 'smf_timepicker');
  360.         loadJavaScriptFile('jquery-ui.datepicker.min.js', array('defer' => true), 'smf_datepicker');
  361.         loadJavaScriptFile('jquery.timepicker.min.js', array('defer' => true), 'smf_timepicker');
  362.         loadJavaScriptFile('datepair.min.js', array('defer' => true), 'smf_datepair');
  363.         addInlineJavaScript('
  364.     $("#allday").click(function(){
  365.         $("#start_time").attr("disabled", this.checked);
  366.         $("#end_time").attr("disabled", this.checked);
  367.         $("#tz").attr("disabled", this.checked);
  368.     });
  369.     $("#event_time_input .date_input").datepicker({
  370.         dateFormat: "yy-mm-dd",
  371.         autoSize: true,
  372.         isRTL: ' . ($context['right_to_left'] ? 'true' : 'false') . ',
  373.         constrainInput: true,
  374.         showAnim: "",
  375.         showButtonPanel: false,
  376.         minDate: "' . $modSettings['cal_minyear'] . '-01-01",
  377.         maxDate: "' . $modSettings['cal_maxyear'] . '-12-31",
  378.         yearRange: "' . $modSettings['cal_minyear'] . ':' . $modSettings['cal_maxyear'] . '",
  379.         hideIfNoPrevNext: true,
  380.         monthNames: ["' . implode('", "', $txt['months_titles']) . '"],
  381.         monthNamesShort: ["' . implode('", "', $txt['months_short']) . '"],
  382.         dayNames: ["' . implode('", "', $txt['days']) . '"],
  383.         dayNamesShort: ["' . implode('", "', $txt['days_short']) . '"],
  384.         dayNamesMin: ["' . implode('", "', $txt['days_short']) . '"],
  385.         prevText: "' . $txt['prev_month'] . '",
  386.         nextText: "' . $txt['next_month'] . '",
  387.     });
  388.     $(".time_input").timepicker({
  389.         timeFormat: "' . $js_time_string . '",
  390.         showDuration: true,
  391.         maxTime: "23:59:59",
  392.     });
  393.     var date_entry = document.getElementById("event_time_input");
  394.     var date_entry_pair = new Datepair(date_entry, {
  395.         timeClass: "time_input",
  396.         dateClass: "date_input",
  397.         parseDate: function (el) {
  398.             var utc = new Date($(el).datepicker("getDate"));
  399.             return utc && new Date(utc.getTime() + (utc.getTimezoneOffset() * 60000));
  400.         },
  401.         updateDate: function (el, v) {
  402.             $(el).datepicker("setDate", new Date(v.getTime() - (v.getTimezoneOffset() * 60000)));
  403.         }
  404.     });
  405.     ', true);
  406.  
  407.         $context['event']['board'] = !empty($board) ? $board : $modSettings['cal_defaultboard'];
  408.         $context['event']['topic'] = !empty($topic) ? $topic : 0;
  409.     }
  410.  
  411.     // See if any new replies have come along.
  412.     // Huh, $_REQUEST['msg'] is set upon submit, so this doesn't get executed at submit
  413.     // only at preview
  414.     if (empty($_REQUEST['msg']) && !empty($topic))
  415.     {
  416.         if (isset($_REQUEST['last_msg']) && $context['topic_last_message'] > $_REQUEST['last_msg'])
  417.         {
  418.             $request = $smcFunc['db_query']('', '
  419.                 SELECT COUNT(*)
  420.                 FROM {db_prefix}messages
  421.                 WHERE id_topic = {int:current_topic}
  422.                     AND id_msg > {int:last_msg}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
  423.                     AND approved = {int:approved}') . '
  424.                 LIMIT 1',
  425.                 array(
  426.                     'current_topic' => $topic,
  427.                     'last_msg' => (int) $_REQUEST['last_msg'],
  428.                     'approved' => 1,
  429.                 )
  430.             );
  431.             list ($context['new_replies']) = $smcFunc['db_fetch_row']($request);
  432.             $smcFunc['db_free_result']($request);
  433.  
  434.             if (!empty($context['new_replies']))
  435.             {
  436.                 if ($context['new_replies'] == 1)
  437.                     $txt['error_new_replies'] = isset($_GET['last_msg']) ? $txt['error_new_reply_reading'] : $txt['error_new_reply'];
  438.                 else
  439.                     $txt['error_new_replies'] = sprintf(isset($_GET['last_msg']) ? $txt['error_new_replies_reading'] : $txt['error_new_replies'], $context['new_replies']);
  440.  
  441.                 $post_errors[] = 'new_replies';
  442.  
  443.                 $modSettings['topicSummaryPosts'] = $context['new_replies'] > $modSettings['topicSummaryPosts'] ? max($modSettings['topicSummaryPosts'], 5) : $modSettings['topicSummaryPosts'];
  444.             }
  445.         }
  446.     }
  447.  
  448.     // Get a response prefix (like 'Re:') in the default forum language.
  449.     if (!isset($context['response_prefix']) && !($context['response_prefix'] = cache_get_data('response_prefix')))
  450.     {
  451.         if ($language === $user_info['language'])
  452.             $context['response_prefix'] = $txt['response_prefix'];
  453.         else
  454.         {
  455.             loadLanguage('index', $language, false);
  456.             $context['response_prefix'] = $txt['response_prefix'];
  457.             loadLanguage('index');
  458.         }
  459.         cache_put_data('response_prefix', $context['response_prefix'], 600);
  460.     }
  461.  
  462.     // Previewing, modifying, or posting?
  463.     // Do we have a body, but an error happened.
  464.     if (isset($_REQUEST['message']) || isset($_REQUEST['quickReply']) || !empty($context['post_error']))
  465.     {
  466.         if (isset($_REQUEST['quickReply']))
  467.             $_REQUEST['message'] = $_REQUEST['quickReply'];
  468.  
  469.         // Validate inputs.
  470.         if (empty($context['post_error']))
  471.         {
  472.             // This means they didn't click Post and get an error.
  473.             $really_previewing = true;
  474.         }
  475.         else
  476.         {
  477.             if (!isset($_REQUEST['subject']))
  478.                 $_REQUEST['subject'] = '';
  479.             if (!isset($_REQUEST['message']))
  480.                 $_REQUEST['message'] = '';
  481.             if (!isset($_REQUEST['icon']))
  482.                 $_REQUEST['icon'] = 'xx';
  483.  
  484.             // They are previewing if they asked to preview (i.e. came from quick reply).
  485.             $really_previewing = !empty($_POST['preview']);
  486.         }
  487.  
  488.         // In order to keep the approval status flowing through, we have to pass it through the form...
  489.         $context['becomes_approved'] = empty($_REQUEST['not_approved']);
  490.         $context['show_approval'] = isset($_REQUEST['approve']) ? ($_REQUEST['approve'] ? 2 : 1) : 0;
  491.         $context['can_announce'] &= $context['becomes_approved'];
  492.  
  493.         // Set up the inputs for the form.
  494.         $form_subject = strtr($smcFunc['htmlspecialchars']($_REQUEST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
  495.         $form_message = $smcFunc['htmlspecialchars']($_REQUEST['message'], ENT_QUOTES);
  496.  
  497.         // Make sure the subject isn't too long - taking into account special characters.
  498.         if ($smcFunc['strlen']($form_subject) > 100)
  499.             $form_subject = $smcFunc['substr']($form_subject, 0, 100);
  500.  
  501.         if (isset($_REQUEST['poll']))
  502.         {
  503.             $context['question'] = isset($_REQUEST['question']) ? $smcFunc['htmlspecialchars'](trim($_REQUEST['question'])) : '';
  504.  
  505.             $context['choices'] = array();
  506.             $choice_id = 0;
  507.  
  508.             $_POST['options'] = empty($_POST['options']) ? array() : htmlspecialchars__recursive($_POST['options']);
  509.             foreach ($_POST['options'] as $option)
  510.             {
  511.                 if (trim($option) == '')
  512.                     continue;
  513.  
  514.                 $context['choices'][] = array(
  515.                     'id' => $choice_id++,
  516.                     'number' => $choice_id,
  517.                     'label' => $option,
  518.                     'is_last' => false
  519.                 );
  520.             }
  521.  
  522.             // One empty option for those with js disabled...I know are few... :P
  523.             $context['choices'][] = array(
  524.                 'id' => $choice_id++,
  525.                 'number' => $choice_id,
  526.                 'label' => '',
  527.                 'is_last' => false
  528.             );
  529.  
  530.             if (count($context['choices']) < 2)
  531.             {
  532.                 $context['choices'][] = array(
  533.                     'id' => $choice_id++,
  534.                     'number' => $choice_id,
  535.                     'label' => '',
  536.                     'is_last' => false
  537.                 );
  538.             }
  539.             $context['last_choice_id'] = $choice_id;
  540.             $context['choices'][count($context['choices']) - 1]['is_last'] = true;
  541.         }
  542.  
  543.         // Are you... a guest?
  544.         if ($user_info['is_guest'])
  545.         {
  546.             $_REQUEST['guestname'] = !isset($_REQUEST['guestname']) ? '' : trim($_REQUEST['guestname']);
  547.             $_REQUEST['email'] = !isset($_REQUEST['email']) ? '' : trim($_REQUEST['email']);
  548.  
  549.             $_REQUEST['guestname'] = $smcFunc['htmlspecialchars']($_REQUEST['guestname']);
  550.             $context['name'] = $_REQUEST['guestname'];
  551.             $_REQUEST['email'] = $smcFunc['htmlspecialchars']($_REQUEST['email']);
  552.             $context['email'] = $_REQUEST['email'];
  553.  
  554.             $user_info['name'] = $_REQUEST['guestname'];
  555.         }
  556.  
  557.         // Only show the preview stuff if they hit Preview.
  558.         if (($really_previewing == true || isset($_REQUEST['xml'])) && !isset($_REQUEST['save_draft']))
  559.         {
  560.             // Set up the preview message and subject and censor them...
  561.             $context['preview_message'] = $form_message;
  562.             preparsecode($form_message, true);
  563.             preparsecode($context['preview_message']);
  564.  
  565.             // Do all bulletin board code tags, with or without smileys.
  566.             $context['preview_message'] = parse_bbc($context['preview_message'], isset($_REQUEST['ns']) ? 0 : 1);
  567.             censorText($context['preview_message']);
  568.  
  569.             if ($form_subject != '')
  570.             {
  571.                 $context['preview_subject'] = $form_subject;
  572.  
  573.                 censorText($context['preview_subject']);
  574.             }
  575.             else
  576.                 $context['preview_subject'] = '<em>' . $txt['no_subject'] . '</em>';
  577.  
  578.             // Protect any CDATA blocks.
  579.             if (isset($_REQUEST['xml']))
  580.                 $context['preview_message'] = strtr($context['preview_message'], array(']]>' => ']]]]><![CDATA[>'));
  581.         }
  582.  
  583.         // Set up the checkboxes.
  584.         $context['notify'] = !empty($_REQUEST['notify']);
  585.         $context['use_smileys'] = !isset($_REQUEST['ns']);
  586.  
  587.         $context['icon'] = isset($_REQUEST['icon']) ? preg_replace('~[\./\\\\*\':"<>]~', '', $_REQUEST['icon']) : 'xx';
  588.  
  589.         // Set the destination action for submission.
  590.         $context['destination'] = 'post2;start=' . $_REQUEST['start'] . (isset($_REQUEST['msg']) ? ';msg=' . $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id'] : '') . (isset($_REQUEST['poll']) ? ';poll' : '');
  591.         $context['submit_label'] = isset($_REQUEST['msg']) ? $txt['save'] : $txt['post'];
  592.  
  593.         // Previewing an edit?
  594.         if (isset($_REQUEST['msg']) && !empty($topic))
  595.         {
  596.             // Get the existing message. Previewing.
  597.             $request = $smcFunc['db_query']('', '
  598.                 SELECT
  599.                     m.id_member, m.modified_time, m.smileys_enabled, m.body,
  600.                     m.poster_name, m.poster_email, m.subject, m.icon, m.approved,
  601.                     COALESCE(a.size, -1) AS filesize, a.filename, a.id_attach,
  602.                     a.approved AS attachment_approved, t.id_member_started AS id_member_poster,
  603.                     m.poster_time, log.id_action
  604.                 FROM {db_prefix}messages AS m
  605.                     INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
  606.                     LEFT JOIN {db_prefix}attachments AS a ON (a.id_msg = m.id_msg AND a.attachment_type = {int:attachment_type})
  607.                     LEFT JOIN {db_prefix}log_actions AS log ON (m.id_topic = log.id_topic AND log.action = {string:announce_action})
  608.                 WHERE m.id_msg = {int:id_msg}
  609.                     AND m.id_topic = {int:current_topic}',
  610.                 array(
  611.                     'current_topic' => $topic,
  612.                     'attachment_type' => 0,
  613.                     'id_msg' => $_REQUEST['msg'],
  614.                     'announce_action' => 'announce_topic',
  615.                 )
  616.             );
  617.             // The message they were trying to edit was most likely deleted.
  618.             // @todo Change this error message?
  619.             if ($smcFunc['db_num_rows']($request) == 0)
  620.                 fatal_lang_error('no_board', false);
  621.             $row = $smcFunc['db_fetch_assoc']($request);
  622.  
  623.             $attachment_stuff = array($row);
  624.             while ($row2 = $smcFunc['db_fetch_assoc']($request))
  625.                 $attachment_stuff[] = $row2;
  626.             $smcFunc['db_free_result']($request);
  627.  
  628.             if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any'))
  629.             {
  630.                 // Give an extra five minutes over the disable time threshold, so they can type - assuming the post is public.
  631.                 if ($row['approved'] && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time())
  632.                     fatal_lang_error('modify_post_time_passed', false);
  633.                 elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_own'))
  634.                     isAllowedTo('modify_replies');
  635.                 else
  636.                     isAllowedTo('modify_own');
  637.             }
  638.             elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_any'))
  639.                 isAllowedTo('modify_replies');
  640.             else
  641.                 isAllowedTo('modify_any');
  642.  
  643.             if ($context['can_announce'] && !empty($row['id_action']))
  644.             {
  645.                 loadLanguage('Errors');
  646.                 $context['post_error']['messages'][] = $txt['error_topic_already_announced'];
  647.             }
  648.  
  649.             if (!empty($modSettings['attachmentEnable']))
  650.             {
  651.                 $request = $smcFunc['db_query']('', '
  652.                     SELECT COALESCE(size, -1) AS filesize, filename, id_attach, approved, mime_type, id_thumb
  653.                     FROM {db_prefix}attachments
  654.                     WHERE id_msg = {int:id_msg}
  655.                         AND attachment_type = {int:attachment_type}
  656.                     ORDER BY id_attach',
  657.                     array(
  658.                         'id_msg' => (int) $_REQUEST['msg'],
  659.                         'attachment_type' => 0,
  660.                     )
  661.                 );
  662.  
  663.                 while ($row = $smcFunc['db_fetch_assoc']($request))
  664.                 {
  665.                     if ($row['filesize'] <= 0)
  666.                         continue;
  667.                     $context['current_attachments'][$row['id_attach']] = array(
  668.                         'name' => $smcFunc['htmlspecialchars']($row['filename']),
  669.                         'size' => $row['filesize'],
  670.                         'attachID' => $row['id_attach'],
  671.                         'approved' => $row['approved'],
  672.                         'mime_type' => $row['mime_type'],
  673.                         'thumb' => $row['id_thumb'],
  674.                     );
  675.                 }
  676.                 $smcFunc['db_free_result']($request);
  677.             }
  678.  
  679.             // Allow moderators to change names....
  680.             if (allowedTo('moderate_forum') && !empty($topic))
  681.             {
  682.                 $request = $smcFunc['db_query']('', '
  683.                     SELECT id_member, poster_name, poster_email
  684.                     FROM {db_prefix}messages
  685.                     WHERE id_msg = {int:id_msg}
  686.                         AND id_topic = {int:current_topic}
  687.                     LIMIT 1',
  688.                     array(
  689.                         'current_topic' => $topic,
  690.                         'id_msg' => (int) $_REQUEST['msg'],
  691.                     )
  692.                 );
  693.                 $row = $smcFunc['db_fetch_assoc']($request);
  694.                 $smcFunc['db_free_result']($request);
  695.  
  696.                 if (empty($row['id_member']))
  697.                 {
  698.                     $context['name'] = $smcFunc['htmlspecialchars']($row['poster_name']);
  699.                     $context['email'] = $smcFunc['htmlspecialchars']($row['poster_email']);
  700.                 }
  701.             }
  702.         }
  703.  
  704.         // No check is needed, since nothing is really posted.
  705.         checkSubmitOnce('free');
  706.     }
  707.     // Editing a message...
  708.     elseif (isset($_REQUEST['msg']) && !empty($topic))
  709.     {
  710.         $context['editing'] = true;
  711.  
  712.         $_REQUEST['msg'] = (int) $_REQUEST['msg'];
  713.  
  714.         // Get the existing message. Editing.
  715.         $request = $smcFunc['db_query']('', '
  716.             SELECT
  717.                 m.id_member, m.modified_time, m.modified_name, m.modified_reason, m.smileys_enabled, m.body,
  718.                 m.poster_name, m.poster_email, m.subject, m.icon, m.approved,
  719.                 COALESCE(a.size, -1) AS filesize, a.filename, a.id_attach, a.mime_type, a.id_thumb,
  720.                 a.approved AS attachment_approved, t.id_member_started AS id_member_poster,
  721.                 m.poster_time, log.id_action
  722.             FROM {db_prefix}messages AS m
  723.                 INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
  724.                 LEFT JOIN {db_prefix}attachments AS a ON (a.id_msg = m.id_msg AND a.attachment_type = {int:attachment_type})
  725.                     LEFT JOIN {db_prefix}log_actions AS log ON (m.id_topic = log.id_topic AND log.action = {string:announce_action})
  726.             WHERE m.id_msg = {int:id_msg}
  727.                 AND m.id_topic = {int:current_topic}',
  728.             array(
  729.                 'current_topic' => $topic,
  730.                 'attachment_type' => 0,
  731.                 'id_msg' => $_REQUEST['msg'],
  732.                 'announce_action' => 'announce_topic',
  733.             )
  734.         );
  735.         // The message they were trying to edit was most likely deleted.
  736.         if ($smcFunc['db_num_rows']($request) == 0)
  737.             fatal_lang_error('no_message', false);
  738.         $row = $smcFunc['db_fetch_assoc']($request);
  739.  
  740.         $attachment_stuff = array($row);
  741.         while ($row2 = $smcFunc['db_fetch_assoc']($request))
  742.             $attachment_stuff[] = $row2;
  743.         $smcFunc['db_free_result']($request);
  744.  
  745.         if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any'))
  746.         {
  747.             // Give an extra five minutes over the disable time threshold, so they can type - assuming the post is public.
  748.             if ($row['approved'] && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time())
  749.                 fatal_lang_error('modify_post_time_passed', false);
  750.             elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_own'))
  751.                 isAllowedTo('modify_replies');
  752.             else
  753.                 isAllowedTo('modify_own');
  754.         }
  755.         elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_any'))
  756.             isAllowedTo('modify_replies');
  757.         else
  758.             isAllowedTo('modify_any');
  759.  
  760.         if ($context['can_announce'] && !empty($row['id_action']))
  761.         {
  762.             loadLanguage('Errors');
  763.             $context['post_error']['messages'][] = $txt['error_topic_already_announced'];
  764.         }
  765.  
  766.         // When was it last modified?
  767.         if (!empty($row['modified_time']))
  768.         {
  769.             $context['last_modified'] = timeformat($row['modified_time']);
  770.             $context['last_modified_reason'] = censorText($row['modified_reason']);
  771.             $context['last_modified_text'] = sprintf($txt['last_edit_by'], $context['last_modified'], $row['modified_name']) . empty($row['modified_reason']) ? '' : '&nbsp;' . $txt['last_edit_reason'] . ':&nbsp;' . $row['modified_reason'];
  772.         }
  773.  
  774.         // Get the stuff ready for the form.
  775.         $form_subject = $row['subject'];
  776.         $form_message = un_preparsecode($row['body']);
  777.         censorText($form_message);
  778.         censorText($form_subject);
  779.  
  780.         // Check the boxes that should be checked.
  781.         $context['use_smileys'] = !empty($row['smileys_enabled']);
  782.         $context['icon'] = $row['icon'];
  783.  
  784.         // Leave the approval checkbox unchecked by default for unapproved messages.
  785.         if (!$row['approved'] && !empty($context['show_approval']))
  786.             $context['show_approval'] = 1;
  787.  
  788.         // Sort the attachments so they are in the order saved
  789.         $temp = array();
  790.         foreach ($attachment_stuff as $attachment)
  791.         {
  792.             if ($attachment['filesize'] >= 0 && !empty($modSettings['attachmentEnable']))
  793.                 $temp[$attachment['id_attach']] = $attachment;
  794.         }
  795.         ksort($temp);
  796.  
  797.         // Load up 'em attachments!
  798.         foreach ($temp as $attachment)
  799.         {
  800.             $context['current_attachments'][$attachment['id_attach']] = array(
  801.                 'name' => $smcFunc['htmlspecialchars']($attachment['filename']),
  802.                 'size' => $attachment['filesize'],
  803.                 'attachID' => $attachment['id_attach'],
  804.                 'approved' => $attachment['attachment_approved'],
  805.                 'mime_type' => $attachment['mime_type'],
  806.                 'thumb' => $attachment['id_thumb'],
  807.             );
  808.         }
  809.  
  810.         // Allow moderators to change names....
  811.         if (allowedTo('moderate_forum') && empty($row['id_member']))
  812.         {
  813.             $context['name'] = $smcFunc['htmlspecialchars']($row['poster_name']);
  814.             $context['email'] = $smcFunc['htmlspecialchars']($row['poster_email']);
  815.         }
  816.  
  817.         // Set the destination.
  818.         $context['destination'] = 'post2;start=' . $_REQUEST['start'] . ';msg=' . $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id'] . (isset($_REQUEST['poll']) ? ';poll' : '');
  819.         $context['submit_label'] = $txt['save'];
  820.     }
  821.     // Posting...
  822.     else
  823.     {
  824.         // By default....
  825.         $context['use_smileys'] = true;
  826.         $context['icon'] = 'xx';
  827.  
  828.         if ($user_info['is_guest'])
  829.         {
  830.             $context['name'] = isset($_SESSION['guest_name']) ? $_SESSION['guest_name'] : '';
  831.             $context['email'] = isset($_SESSION['guest_email']) ? $_SESSION['guest_email'] : '';
  832.         }
  833.         $context['destination'] = 'post2;start=' . $_REQUEST['start'] . (isset($_REQUEST['poll']) ? ';poll' : '');
  834.  
  835.         $context['submit_label'] = $txt['post'];
  836.  
  837.         // Posting a quoted reply?
  838.         if (!empty($topic) && !empty($_REQUEST['quote']))
  839.         {
  840.             // Make sure they _can_ quote this post, and if so get it.
  841.             $request = $smcFunc['db_query']('', '
  842.                 SELECT m.subject, COALESCE(mem.real_name, m.poster_name) AS poster_name, m.poster_time, m.body
  843.                 FROM {db_prefix}messages AS m
  844.                     INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board AND {query_see_board})
  845.                     LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
  846.                 WHERE m.id_msg = {int:id_msg}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
  847.                     AND m.approved = {int:is_approved}') . '
  848.                 LIMIT 1',
  849.                 array(
  850.                     'id_msg' => (int) $_REQUEST['quote'],
  851.                     'is_approved' => 1,
  852.                 )
  853.             );
  854.             if ($smcFunc['db_num_rows']($request) == 0)
  855.                 fatal_lang_error('quoted_post_deleted', false);
  856.             list ($form_subject, $mname, $mdate, $form_message) = $smcFunc['db_fetch_row']($request);
  857.             $smcFunc['db_free_result']($request);
  858.  
  859.             // Add 'Re: ' to the front of the quoted subject.
  860.             if (trim($context['response_prefix']) != '' && $smcFunc['strpos']($form_subject, trim($context['response_prefix'])) !== 0)
  861.                 $form_subject = $context['response_prefix'] . $form_subject;
  862.  
  863.             // Censor the message and subject.
  864.             censorText($form_message);
  865.             censorText($form_subject);
  866.  
  867.             // But if it's in HTML world, turn them into htmlspecialchar's so they can be edited!
  868.             if (strpos($form_message, '[html]') !== false)
  869.             {
  870.                 $parts = preg_split('~(\[/code\]|\[code(?:=[^\]]+)?\])~i', $form_message, -1, PREG_SPLIT_DELIM_CAPTURE);
  871.                 for ($i = 0, $n = count($parts); $i < $n; $i++)
  872.                 {
  873.                     // It goes 0 = outside, 1 = begin tag, 2 = inside, 3 = close tag, repeat.
  874.                     if ($i % 4 == 0)
  875.                         $parts[$i] = preg_replace_callback('~\[html\](.+?)\[/html\]~is', function($m)
  876.                         {
  877.                             return '[html]' . preg_replace('~<br\s?/?' . '>~i', '&lt;br /&gt;<br>', "$m[1]") . '[/html]';
  878.                         }, $parts[$i]);
  879.                 }
  880.                 $form_message = implode('', $parts);
  881.             }
  882.  
  883.             $form_message = preg_replace('~<br ?/?' . '>~i', "\n", $form_message);
  884.  
  885.             // Remove any nested quotes, if necessary.
  886.             if (!empty($modSettings['removeNestedQuotes']))
  887.                 $form_message = preg_replace(array('~\n?\[quote.*?\].+?\[/quote\]\n?~is', '~^\n~', '~\[/quote\]~'), '', $form_message);
  888.  
  889.             // Add a quote string on the front and end.
  890.             $form_message = '[quote author=' . $mname . ' link=msg=' . (int) $_REQUEST['quote'] . ' date=' . $mdate . ']' . "\n" . rtrim($form_message) . "\n" . '[/quote]';
  891.         }
  892.         // Posting a reply without a quote?
  893.         elseif (!empty($topic) && empty($_REQUEST['quote']))
  894.         {
  895.             // Get the first message's subject.
  896.             $form_subject = $first_subject;
  897.  
  898.             // Add 'Re: ' to the front of the subject.
  899.             if (trim($context['response_prefix']) != '' && $form_subject != '' && $smcFunc['strpos']($form_subject, trim($context['response_prefix'])) !== 0)
  900.                 $form_subject = $context['response_prefix'] . $form_subject;
  901.  
  902.             // Censor the subject.
  903.             censorText($form_subject);
  904.  
  905.             $form_message = '';
  906.         }
  907.         else
  908.         {
  909.             $form_subject = isset($_GET['subject']) ? $_GET['subject'] : '';
  910.             $form_message = '';
  911.         }
  912.     }
  913.  
  914.     $context['can_post_attachment'] = !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1 && (allowedTo('post_attachment', $boards, true) || ($modSettings['postmod_active'] && allowedTo('post_unapproved_attachments', $boards, true)));
  915.  
  916.     if ($context['can_post_attachment'])
  917.     {
  918.         // If there are attachments, calculate the total size and how many.
  919.         $context['attachments']['total_size'] = 0;
  920.         $context['attachments']['quantity'] = 0;
  921.  
  922.         // If this isn't a new post, check the current attachments.
  923.         if (isset($_REQUEST['msg']))
  924.         {
  925.             $context['attachments']['quantity'] = count($context['current_attachments']);
  926.             foreach ($context['current_attachments'] as $attachment)
  927.                 $context['attachments']['total_size'] += $attachment['size'];
  928.         }
  929.  
  930.         // A bit of house keeping first.
  931.         if (!empty($_SESSION['temp_attachments']) && count($_SESSION['temp_attachments']) == 1)
  932.             unset($_SESSION['temp_attachments']);
  933.  
  934.         if (!empty($_SESSION['temp_attachments']))
  935.         {
  936.             // Is this a request to delete them?
  937.             if (isset($_GET['delete_temp']))
  938.             {
  939.                 foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
  940.                 {
  941.                     if (strpos($attachID, 'post_tmp_' . $user_info['id']) !== false)
  942.                         if (file_exists($attachment['tmp_name']))
  943.                             unlink($attachment['tmp_name']);
  944.                 }
  945.                 $post_errors[] = 'temp_attachments_gone';
  946.                 $_SESSION['temp_attachments'] = array();
  947.             }
  948.             // Hmm, coming in fresh and there are files in session.
  949.             elseif ($context['current_action'] != 'post2' || !empty($_POST['from_qr']))
  950.             {
  951.                 // Let's be nice and see if they belong here first.
  952.                 if ((empty($_REQUEST['msg']) && empty($_SESSION['temp_attachments']['post']['msg']) && $_SESSION['temp_attachments']['post']['board'] == (!empty($board) ? $board : 0)) || (!empty($_REQUEST['msg']) && $_SESSION['temp_attachments']['post']['msg'] == $_REQUEST['msg']))
  953.                 {
  954.                     // See if any files still exist before showing the warning message and the files attached.
  955.                     foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
  956.                     {
  957.                         if (strpos($attachID, 'post_tmp_' . $user_info['id']) === false)
  958.                             continue;
  959.  
  960.                         if (file_exists($attachment['tmp_name']))
  961.                         {
  962.                             $post_errors[] = 'temp_attachments_new';
  963.                             $context['files_in_session_warning'] = $txt['attached_files_in_session'];
  964.                             unset($_SESSION['temp_attachments']['post']['files']);
  965.                             break;
  966.                         }
  967.                     }
  968.                 }
  969.                 else
  970.                 {
  971.                     // Since, they don't belong here. Let's inform the user that they exist..
  972.                     if (!empty($topic))
  973.                         $delete_url = $scripturl . '?action=post' . (!empty($_REQUEST['msg']) ? (';msg=' . $_REQUEST['msg']) : '') . (!empty($_REQUEST['last_msg']) ? (';last_msg=' . $_REQUEST['last_msg']) : '') . ';topic=' . $topic . ';delete_temp';
  974.                     else
  975.                         $delete_url = $scripturl . '?action=post' . (!empty($board) ? ';board=' . $board : '') . ';delete_temp';
  976.  
  977.                     // Compile a list of the files to show the user.
  978.                     $file_list = array();
  979.                     foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
  980.                         if (strpos($attachID, 'post_tmp_' . $user_info['id']) !== false)
  981.                             $file_list[] = $attachment['name'];
  982.  
  983.                     $_SESSION['temp_attachments']['post']['files'] = $file_list;
  984.                     $file_list = '<div class="attachments">' . implode('<br>', $file_list) . '</div>';
  985.  
  986.                     if (!empty($_SESSION['temp_attachments']['post']['msg']))
  987.                     {
  988.                         // We have a message id, so we can link back to the old topic they were trying to edit..
  989.                         $goback_url = $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';
  990.  
  991.                         $post_errors[] = array('temp_attachments_found', array($delete_url, $goback_url, $file_list));
  992.                         $context['ignore_temp_attachments'] = true;
  993.                     }
  994.                     else
  995.                     {
  996.                         $post_errors[] = array('temp_attachments_lost', array($delete_url, $file_list));
  997.                         $context['ignore_temp_attachments'] = true;
  998.                     }
  999.                 }
  1000.             }
  1001.  
  1002.             if (!empty($context['we_are_history']))
  1003.                 $post_errors[] = $context['we_are_history'];
  1004.  
  1005.             foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
  1006.             {
  1007.                 if (isset($context['ignore_temp_attachments']) || isset($_SESSION['temp_attachments']['post']['files']))
  1008.                     break;
  1009.  
  1010.                 if ($attachID != 'initial_error' && strpos($attachID, 'post_tmp_' . $user_info['id']) === false)
  1011.                     continue;
  1012.  
  1013.                 if ($attachID == 'initial_error')
  1014.                 {
  1015.                     $txt['error_attach_initial_error'] = $txt['attach_no_upload'] . '<div style="padding: 0 1em;">' . (is_array($attachment) ? vsprintf($txt[$attachment[0]], $attachment[1]) : $txt[$attachment]) . '</div>';
  1016.                     $post_errors[] = 'attach_initial_error';
  1017.                     unset($_SESSION['temp_attachments']);
  1018.                     break;
  1019.                 }
  1020.  
  1021.                 // Show any errors which might have occurred.
  1022.                 if (!empty($attachment['errors']))
  1023.                 {
  1024.                     $txt['error_attach_errors'] = empty($txt['error_attach_errors']) ? '<br>' : '';
  1025.                     $txt['error_attach_errors'] .= vsprintf($txt['attach_warning'], $attachment['name']) . '<div style="padding: 0 1em;">';
  1026.                     foreach ($attachment['errors'] as $error)
  1027.                         $txt['error_attach_errors'] .= (is_array($error) ? vsprintf($txt[$error[0]], $error[1]) : $txt[$error]) . '<br >';
  1028.                     $txt['error_attach_errors'] .= '</div>';
  1029.                     $post_errors[] = 'attach_errors';
  1030.  
  1031.                     // Take out the trash.
  1032.                     unset($_SESSION['temp_attachments'][$attachID]);
  1033.                     if (file_exists($attachment['tmp_name']))
  1034.                         unlink($attachment['tmp_name']);
  1035.                     continue;
  1036.                 }
  1037.  
  1038.                 // More house keeping.
  1039.                 if (!file_exists($attachment['tmp_name']))
  1040.                 {
  1041.                     unset($_SESSION['temp_attachments'][$attachID]);
  1042.                     continue;
  1043.                 }
  1044.  
  1045.                 $context['attachments']['quantity']++;
  1046.                 $context['attachments']['total_size'] += $attachment['size'];
  1047.                 if (!isset($context['files_in_session_warning']))
  1048.                     $context['files_in_session_warning'] = $txt['attached_files_in_session'];
  1049.  
  1050.                 $context['current_attachments'][$attachID] = array(
  1051.                     'name' => $smcFunc['htmlspecialchars']($attachment['name']),
  1052.                     'size' => $attachment['size'],
  1053.                     'attachID' => $attachID,
  1054.                     'unchecked' => false,
  1055.                     'approved' => 1,
  1056.                     'mime_type' => '',
  1057.                     'thumb' => 0,
  1058.                 );
  1059.             }
  1060.         }
  1061.     }
  1062.  
  1063.     // Do we need to show the visual verification image?
  1064.     $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));
  1065.     if ($context['require_verification'])
  1066.     {
  1067.         require_once($sourcedir . '/Subs-Editor.php');
  1068.         $verificationOptions = array(
  1069.             'id' => 'post',
  1070.         );
  1071.         $context['require_verification'] = create_control_verification($verificationOptions);
  1072.         $context['visual_verification_id'] = $verificationOptions['id'];
  1073.     }
  1074.  
  1075.     // If they came from quick reply, and have to enter verification details, give them some notice.
  1076.     if (!empty($_REQUEST['from_qr']) && !empty($context['require_verification']))
  1077.         $post_errors[] = 'need_qr_verification';
  1078.  
  1079.     /*
  1080.      * There are two error types: serious and minor. Serious errors
  1081.      * actually tell the user that a real error has occurred, while minor
  1082.      * errors are like warnings that let them know that something with
  1083.      * their post isn't right.
  1084.      */
  1085.     $minor_errors = array('not_approved', 'new_replies', 'old_topic', 'need_qr_verification', 'no_subject', 'topic_locked', 'topic_unlocked', 'topic_stickied', 'topic_unstickied', 'cannot_post_attachment');
  1086.  
  1087.     call_integration_hook('integrate_post_errors', array(&$post_errors, &$minor_errors));
  1088.  
  1089.     // Any errors occurred?
  1090.     if (!empty($post_errors))
  1091.     {
  1092.         loadLanguage('Errors');
  1093.         $context['error_type'] = 'minor';
  1094.         foreach ($post_errors as $post_error)
  1095.             if (is_array($post_error))
  1096.             {
  1097.                 $post_error_id = $post_error[0];
  1098.                 $context['post_error'][$post_error_id] = vsprintf($txt['error_' . $post_error_id], $post_error[1]);
  1099.  
  1100.                 // If it's not a minor error flag it as such.
  1101.                 if (!in_array($post_error_id, $minor_errors))
  1102.                     $context['error_type'] = 'serious';
  1103.             }
  1104.             else
  1105.             {
  1106.                 $context['post_error'][$post_error] = $txt['error_' . $post_error];
  1107.  
  1108.                 // If it's not a minor error flag it as such.
  1109.                 if (!in_array($post_error, $minor_errors))
  1110.                     $context['error_type'] = 'serious';
  1111.             }
  1112.     }
  1113.  
  1114.     // What are you doing? Posting a poll, modifying, previewing, new post, or reply...
  1115.     if (isset($_REQUEST['poll']))
  1116.         $context['page_title'] = $txt['new_poll'];
  1117.     elseif ($context['make_event'])
  1118.         $context['page_title'] = $context['event']['id'] == -1 ? $txt['calendar_post_event'] : $txt['calendar_edit'];
  1119.     elseif (isset($_REQUEST['msg']))
  1120.         $context['page_title'] = $txt['modify_msg'];
  1121.     elseif (isset($_REQUEST['subject'], $context['preview_subject']))
  1122.         $context['page_title'] = $txt['preview'] . ' - ' . strip_tags($context['preview_subject']);
  1123.     elseif (empty($topic))
  1124.         $context['page_title'] = $txt['start_new_topic'];
  1125.     else
  1126.         $context['page_title'] = $txt['post_reply'];
  1127.  
  1128.     // Build the link tree.
  1129.     if (empty($topic))
  1130.         $context['linktree'][] = array(
  1131.             'name' => '<em>' . $txt['start_new_topic'] . '</em>'
  1132.         );
  1133.     else
  1134.         $context['linktree'][] = array(
  1135.             'url' => $scripturl . '?topic=' . $topic . '.' . $_REQUEST['start'],
  1136.             'name' => $form_subject,
  1137.             'extra_before' => '<span><strong class="nav">' . $context['page_title'] . ' (</strong></span>',
  1138.             'extra_after' => '<span><strong class="nav">)</strong></span>'
  1139.         );
  1140.  
  1141.     $context['subject'] = addcslashes($form_subject, '"');
  1142.     $context['message'] = str_replace(array('"', '<', '>', '&nbsp;'), array('&quot;', '&lt;', '&gt;', ' '), $form_message);
  1143.  
  1144.     // Are post drafts enabled?
  1145.     $context['drafts_save'] = !empty($modSettings['drafts_post_enabled']) && allowedTo('post_draft');
  1146.     $context['drafts_autosave'] = !empty($context['drafts_save']) && !empty($modSettings['drafts_autosave_enabled']) && allowedTo('post_autosave_draft');
  1147.  
  1148.     // Build a list of drafts that they can load in to the editor
  1149.     if (!empty($context['drafts_save']))
  1150.     {
  1151.         require_once($sourcedir . '/Drafts.php');
  1152.         ShowDrafts($user_info['id'], $topic);
  1153.     }
  1154.  
  1155.     // Needed for the editor and message icons.
  1156.     require_once($sourcedir . '/Subs-Editor.php');
  1157.  
  1158.     // Now create the editor.
  1159.     $editorOptions = array(
  1160.         'id' => 'message',
  1161.         'value' => $context['message'],
  1162.         'labels' => array(
  1163.             'post_button' => $context['submit_label'],
  1164.         ),
  1165.         // add height and width for the editor
  1166.         'height' => '275px',
  1167.         'width' => '100%',
  1168.         // We do XML preview here.
  1169.         'preview_type' => 2,
  1170.         'required' => true,
  1171.     );
  1172.     create_control_richedit($editorOptions);
  1173.  
  1174.     // Store the ID.
  1175.     $context['post_box_name'] = $editorOptions['id'];
  1176.  
  1177.     $context['attached'] = '';
  1178.     $context['make_poll'] = isset($_REQUEST['poll']);
  1179.  
  1180.     // Message icons - customized icons are off?
  1181.     $context['icons'] = getMessageIcons(!empty($board) ? $board : 0);
  1182.  
  1183.     if (!empty($context['icons']))
  1184.         $context['icons'][count($context['icons']) - 1]['is_last'] = true;
  1185.  
  1186.     // Are we starting a poll? if set the poll icon as selected if its available
  1187.     if (isset($_REQUEST['poll']))
  1188.     {
  1189.         foreach ($context['icons'] as $icons)
  1190.         {
  1191.             if (isset($icons['value']) && $icons['value'] == 'poll')
  1192.             {
  1193.                 // if found we are done
  1194.                 $context['icon'] = 'poll';
  1195.                 break;
  1196.             }
  1197.         }
  1198.     }
  1199.  
  1200.     $context['icon_url'] = '';
  1201.     for ($i = 0, $n = count($context['icons']); $i < $n; $i++)
  1202.     {
  1203.         $context['icons'][$i]['selected'] = $context['icon'] == $context['icons'][$i]['value'];
  1204.         if ($context['icons'][$i]['selected'])
  1205.             $context['icon_url'] = $context['icons'][$i]['url'];
  1206.     }
  1207.     if (empty($context['icon_url']))
  1208.     {
  1209.         $context['icon_url'] = $settings[file_exists($settings['theme_dir'] . '/images/post/' . $context['icon'] . '.png') ? 'images_url' : 'default_images_url'] . '/post/' . $context['icon'] . '.png';
  1210.         array_unshift($context['icons'], array(
  1211.             'value' => $context['icon'],
  1212.             'name' => $txt['current_icon'],
  1213.             'url' => $context['icon_url'],
  1214.             'is_last' => empty($context['icons']),
  1215.             'selected' => true,
  1216.         ));
  1217.     }
  1218.  
  1219.     if (!empty($topic) && !empty($modSettings['topicSummaryPosts']))
  1220.         getTopic();
  1221.  
  1222.     // If the user can post attachments prepare the warning labels.
  1223.     if ($context['can_post_attachment'])
  1224.     {
  1225.         // 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.
  1226.         $context['num_allowed_attachments'] = empty($modSettings['attachmentNumPerPostLimit']) ? 50 : min($modSettings['attachmentNumPerPostLimit'] - count($context['current_attachments']), $modSettings['attachmentNumPerPostLimit']);
  1227.         $context['can_post_attachment_unapproved'] = allowedTo('post_attachment');
  1228.         $context['attachment_restrictions'] = array();
  1229.         $context['allowed_extensions'] = strtr(strtolower($modSettings['attachmentExtensions']), array(',' => ', '));
  1230.         $attachmentRestrictionTypes = array('attachmentNumPerPostLimit', 'attachmentPostLimit', 'attachmentSizeLimit');
  1231.         foreach ($attachmentRestrictionTypes as $type)
  1232.             if (!empty($modSettings[$type]))
  1233.             {
  1234.                 // Show the max number of attachments if not 0.
  1235.                 if ($type == 'attachmentNumPerPostLimit')
  1236.                     $context['attachment_restrictions'][] = sprintf($txt['attach_remaining'], $modSettings['attachmentNumPerPostLimit'] - $context['attachments']['quantity']);
  1237.             }
  1238.     }
  1239.  
  1240.     $context['back_to_topic'] = isset($_REQUEST['goback']) || (isset($_REQUEST['msg']) && !isset($_REQUEST['subject']));
  1241.     $context['show_additional_options'] = !empty($_POST['additional_options']) || isset($_SESSION['temp_attachments']['post']) || isset($_GET['additionalOptions']);
  1242.  
  1243.     $context['is_new_topic'] = empty($topic);
  1244.     $context['is_new_post'] = !isset($_REQUEST['msg']);
  1245.     $context['is_first_post'] = $context['is_new_topic'] || (isset($_REQUEST['msg']) && $_REQUEST['msg'] == $id_first_msg);
  1246.  
  1247.     // WYSIWYG only works if BBC is enabled
  1248.     $modSettings['disable_wysiwyg'] = !empty($modSettings['disable_wysiwyg']) || empty($modSettings['enableBBC']);
  1249.  
  1250.     // Register this form in the session variables.
  1251.     checkSubmitOnce('register');
  1252.  
  1253.     // Mentions
  1254.     if (!empty($modSettings['enable_mentions']) && allowedTo('mention'))
  1255.     {
  1256.         loadJavaScriptFile('jquery.caret.min.js', array('defer' => true), 'smf_caret');
  1257.         loadJavaScriptFile('jquery.atwho.min.js', array('defer' => true), 'smf_atwho');
  1258.         loadJavaScriptFile('mentions.js', array('defer' => true, 'minimize' => true), 'smf_mentions');
  1259.     }
  1260.  
  1261.     // quotedText.js
  1262.     loadJavaScriptFile('quotedText.js', array('defer' => true, 'minimize' => true), 'smf_quotedText');
  1263.  
  1264.     // Mock files to show already attached files.
  1265.     addInlineJavaScript('
  1266.     var current_attachments = [];');
  1267.  
  1268.     if (!empty($context['current_attachments']))
  1269.     {
  1270.         foreach ($context['current_attachments'] as $key => $mock)
  1271.             addInlineJavaScript('
  1272.     current_attachments.push({
  1273.         name: ' . JavaScriptEscape($mock['name']) . ',
  1274.         size: ' . $mock['size'] . ',
  1275.         attachID: ' . $mock['attachID'] . ',
  1276.         approved: ' . $mock['approved'] . ',
  1277.         type: ' . JavaScriptEscape(!empty($mock['mime_type']) ? $mock['mime_type'] : '') . ',
  1278.         thumbID: ' . (!empty($mock['thumb']) ? $mock['thumb'] : 0) . '
  1279.     });');
  1280.     }
  1281.  
  1282.     // File Upload.
  1283.     if ($context['can_post_attachment'])
  1284.     {
  1285.         $acceptedFiles = implode(',', array_map(function($val) use ($smcFunc)
  1286.         {
  1287.             return '.' . $smcFunc['htmltrim']($val);
  1288.         }, explode(',', $context['allowed_extensions'])));
  1289.  
  1290.         loadJavaScriptFile('dropzone.min.js', array('defer' => true), 'smf_dropzone');
  1291.         loadJavaScriptFile('smf_fileUpload.js', array('defer' => true, 'minimize' => true), 'smf_fileUpload');
  1292.         addInlineJavaScript('
  1293.     $(function() {
  1294.         smf_fileUpload({
  1295.             dictDefaultMessage : ' . JavaScriptEscape($txt['attach_drop_zone']) . ',
  1296.             dictFallbackMessage : ' . JavaScriptEscape($txt['attach_drop_zone_no']) . ',
  1297.             dictCancelUpload : ' . JavaScriptEscape($txt['modify_cancel']) . ',
  1298.             genericError: ' . JavaScriptEscape($txt['attach_php_error']) . ',
  1299.             text_attachLeft: ' . JavaScriptEscape($txt['attachments_left']) . ',
  1300.             text_deleteAttach: ' . JavaScriptEscape($txt['attached_file_delete']) . ',
  1301.             text_attachDeleted: ' . JavaScriptEscape($txt['attached_file_deleted']) . ',
  1302.             text_insertBBC: ' . JavaScriptEscape($txt['attached_insert_bbc']) . ',
  1303.             text_attachUploaded: ' . JavaScriptEscape($txt['attached_file_uploaded']) . ',
  1304.             text_attach_unlimited: ' . JavaScriptEscape($txt['attach_drop_unlimited']) . ',
  1305.             text_totalMaxSize: ' . JavaScriptEscape($txt['attach_max_total_file_size_current']) . ',
  1306.             text_max_size_progress: ' . JavaScriptEscape($txt['attach_max_size_progress']) . ',
  1307.             dictMaxFilesExceeded: ' . JavaScriptEscape($txt['more_attachments_error']) . ',
  1308.             dictInvalidFileType: ' . JavaScriptEscape(sprintf($txt['cant_upload_type'], $context['allowed_extensions'])) . ',
  1309.             dictFileTooBig: ' . JavaScriptEscape(sprintf($txt['file_too_big'], comma_format($modSettings['attachmentSizeLimit'], 0))) . ',
  1310.             acceptedFiles: ' . JavaScriptEscape($acceptedFiles) . ',
  1311.             thumbnailWidth: ' . (!empty($modSettings['attachmentThumbWidth']) ? $modSettings['attachmentThumbWidth'] : 'null') . ',
  1312.             thumbnailHeight: ' . (!empty($modSettings['attachmentThumbHeight']) ? $modSettings['attachmentThumbHeight'] : 'null') . ',
  1313.             limitMultiFileUploadSize:' . round(max($modSettings['attachmentPostLimit'] - ($context['attachments']['total_size'] / 1024), 0)) * 1024 . ',
  1314.             maxFileAmount: ' . (!empty($context['num_allowed_attachments']) ? $context['num_allowed_attachments'] : 'null') . ',
  1315.             maxTotalSize: ' . (!empty($modSettings['attachmentPostLimit']) ? $modSettings['attachmentPostLimit'] : '0') . ',
  1316.             maxFileSize: ' . (!empty($modSettings['attachmentSizeLimit']) ? $modSettings['attachmentSizeLimit'] : '0') . ',
  1317.         });
  1318.     });', true);
  1319.     }
  1320.  
  1321.     // Knowing the current board ID might be handy.
  1322.     addInlineJavaScript('
  1323.     var current_board = ' . (empty($context['current_board']) ? 'null' : $context['current_board']) . ';', false);
  1324.  
  1325.     // Now let's set up the fields for the posting form header...
  1326.     $context['posting_fields'] = array();
  1327.  
  1328.     // Guests must supply their name and email.
  1329.     if (isset($context['name']) && isset($context['email']))
  1330.     {
  1331.         $context['posting_fields']['guestname'] = array(
  1332.             'label' => array(
  1333.                 'text' => $txt['name'],
  1334.                 'class' => isset($context['post_error']['long_name']) || isset($context['post_error']['no_name']) || isset($context['post_error']['bad_name']) ? 'error' : '',
  1335.             ),
  1336.             'input' => array(
  1337.                 'type' => 'text',
  1338.                 'attributes' => array(
  1339.                     'size' => 25,
  1340.                     'value' => $context['name'],
  1341.                     'required' => true,
  1342.                 ),
  1343.             ),
  1344.         );
  1345.  
  1346.         if (empty($modSettings['guest_post_no_email']))
  1347.         {
  1348.             $context['posting_fields']['email'] = array(
  1349.                 'label' => array(
  1350.                     'text' => $txt['email'],
  1351.                     'class' => isset($context['post_error']['no_email']) || isset($context['post_error']['bad_email']) ? 'error' : '',
  1352.                 ),
  1353.                 'input' => array(
  1354.                     'type' => 'email',
  1355.                     'attributes' => array(
  1356.                         'size' => 25,
  1357.                         'value' => $context['email'],
  1358.                         'required' => true,
  1359.                     ),
  1360.                 ),
  1361.             );
  1362.         }
  1363.     }
  1364.  
  1365.     // Gotta post it somewhere.
  1366.     if (empty($board) && !$context['make_event'])
  1367.     {
  1368.         $context['posting_fields']['board'] = array(
  1369.             'label' => array(
  1370.                 'text' => $txt['calendar_post_in'],
  1371.             ),
  1372.             'input' => array(
  1373.                 'type' => 'select',
  1374.                 'options' => array(),
  1375.             ),
  1376.         );
  1377.         foreach ($board_list as $category)
  1378.         {
  1379.             $context['posting_fields']['board']['input']['options'][$category['name']] = array('options' => array());
  1380.  
  1381.             foreach ($category['boards'] as $brd)
  1382.                 $context['posting_fields']['board']['input']['options'][$category['name']]['options'][$brd['name']]['attributes'] = array(
  1383.                     'value' => $brd['id'],
  1384.                     'selected' => (bool) $brd['selected'],
  1385.                     'label' => ($brd['child_level'] > 0 ? str_repeat('==', $brd['child_level'] - 1) . '=&gt;' : '') . ' ' . $brd['name'],
  1386.                 );
  1387.         }
  1388.     }
  1389.  
  1390.     // Gotta have a subject.
  1391.     $context['posting_fields']['subject'] = array(
  1392.         'label' => array(
  1393.             'text' => $txt['subject'],
  1394.             'class' => isset($context['post_error']['no_subject']) ? 'error' : '',
  1395.         ),
  1396.         'input' => array(
  1397.             'type' => 'text',
  1398.             'attributes' => array(
  1399.                 'size' => 80,
  1400.                 'maxlength' => !empty($topic) ? 84 : 80,
  1401.                 'value' => $context['subject'],
  1402.                 'required' => true,
  1403.             ),
  1404.         ),
  1405.     );
  1406.  
  1407.     // Icons are fun.
  1408.     $context['posting_fields']['icon'] = array(
  1409.         'label' => array(
  1410.             'text' => $txt['message_icon'],
  1411.         ),
  1412.         'input' => array(
  1413.             'type' => 'select',
  1414.             'attributes' => array(
  1415.                 'id' => 'icon',
  1416.                 'onchange' => 'showimage();',
  1417.             ),
  1418.             'options' => array(),
  1419.             'after' => ' <img id="icons" src="' . $context['icon_url'] . '">',
  1420.         ),
  1421.     );
  1422.     foreach ($context['icons'] as $icon)
  1423.     {
  1424.         $context['posting_fields']['icon']['input']['options'][$icon['name']]['attributes'] = array(
  1425.             'value' => $icon['value'],
  1426.             'selected' => $icon['value'] == $context['icon'],
  1427.         );
  1428.     }
  1429.  
  1430.     // Finally, load the template.
  1431.     if (!isset($_REQUEST['xml']))
  1432.         loadTemplate('Post');
  1433.  
  1434.     call_integration_hook('integrate_post_end');
  1435. }
  1436.  
  1437. /**
  1438.  * Posts or saves the message composed with Post().
  1439.  *
  1440.  * requires various permissions depending on the action.
  1441.  * handles attachment, post, and calendar saving.
  1442.  * sends off notifications, and allows for announcements and moderation.
  1443.  * accessed from ?action=post2.
  1444.  */
  1445. function Post2()
  1446. {
  1447.     global $board, $topic, $txt, $modSettings, $sourcedir, $context;
  1448.     global $user_info, $board_info, $smcFunc, $settings;
  1449.  
  1450.     // Sneaking off, are we?
  1451.     if (empty($_POST) && empty($topic))
  1452.     {
  1453.         if (empty($_SERVER['CONTENT_LENGTH']))
  1454.             redirectexit('action=post;board=' . $board . '.0');
  1455.         else
  1456.             fatal_lang_error('post_upload_error', false);
  1457.     }
  1458.     elseif (empty($_POST) && !empty($topic))
  1459.         redirectexit('action=post;topic=' . $topic . '.0');
  1460.  
  1461.     // No need!
  1462.     $context['robot_no_index'] = true;
  1463.  
  1464.     // Prevent double submission of this form.
  1465.     checkSubmitOnce('check');
  1466.  
  1467.     // No errors as yet.
  1468.     $post_errors = array();
  1469.  
  1470.     // If the session has timed out, let the user re-submit their form.
  1471.     if (checkSession('post', '', false) != '')
  1472.         $post_errors[] = 'session_timeout';
  1473.  
  1474.     // Wrong verification code?
  1475.     if (!$user_info['is_admin'] && !$user_info['is_mod'] && !empty($modSettings['posts_require_captcha']) && ($user_info['posts'] < $modSettings['posts_require_captcha'] || ($user_info['is_guest'] && $modSettings['posts_require_captcha'] == -1)))
  1476.     {
  1477.         require_once($sourcedir . '/Subs-Editor.php');
  1478.         $verificationOptions = array(
  1479.             'id' => 'post',
  1480.         );
  1481.         $context['require_verification'] = create_control_verification($verificationOptions, true);
  1482.         if (is_array($context['require_verification']))
  1483.             $post_errors = array_merge($post_errors, $context['require_verification']);
  1484.     }
  1485.  
  1486.     require_once($sourcedir . '/Subs-Post.php');
  1487.     loadLanguage('Post');
  1488.  
  1489.     call_integration_hook('integrate_post2_start');
  1490.  
  1491.     // Drafts enabled and needed?
  1492.     if (!empty($modSettings['drafts_post_enabled']) && (isset($_POST['save_draft']) || isset($_POST['id_draft'])))
  1493.         require_once($sourcedir . '/Drafts.php');
  1494.  
  1495.     // First check to see if they are trying to delete any current attachments.
  1496.     if (isset($_POST['attach_del']))
  1497.     {
  1498.         $keep_temp = array();
  1499.         $keep_ids = array();
  1500.         foreach ($_POST['attach_del'] as $dummy)
  1501.             if (strpos($dummy, 'post_tmp_' . $user_info['id']) !== false)
  1502.                 $keep_temp[] = $dummy;
  1503.             else
  1504.                 $keep_ids[] = (int) $dummy;
  1505.  
  1506.         if (isset($_SESSION['temp_attachments']))
  1507.             foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
  1508.             {
  1509.                 if ((isset($_SESSION['temp_attachments']['post']['files'], $attachment['name']) && in_array($attachment['name'], $_SESSION['temp_attachments']['post']['files'])) || in_array($attachID, $keep_temp) || strpos($attachID, 'post_tmp_' . $user_info['id']) === false)
  1510.                     continue;
  1511.  
  1512.                 unset($_SESSION['temp_attachments'][$attachID]);
  1513.                 unlink($attachment['tmp_name']);
  1514.             }
  1515.  
  1516.         if (!empty($_REQUEST['msg']))
  1517.         {
  1518.             require_once($sourcedir . '/ManageAttachments.php');
  1519.             $attachmentQuery = array(
  1520.                 'attachment_type' => 0,
  1521.                 'id_msg' => (int) $_REQUEST['msg'],
  1522.                 'not_id_attach' => $keep_ids,
  1523.             );
  1524.             removeAttachments($attachmentQuery);
  1525.         }
  1526.     }
  1527.  
  1528.     // Then try to upload any attachments.
  1529.     $context['can_post_attachment'] = !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1 && (allowedTo('post_attachment') || ($modSettings['postmod_active'] && allowedTo('post_unapproved_attachments')));
  1530.     if ($context['can_post_attachment'] && empty($_POST['from_qr']))
  1531.     {
  1532.         require_once($sourcedir . '/Subs-Attachments.php');
  1533.         processAttachments();
  1534.     }
  1535.  
  1536.     // They've already uploaded some attachments, but they don't have permission to post them
  1537.     // This can sometimes happen when they came from ?action=calendar;sa=post
  1538.     if (!$context['can_post_attachment'] && !empty($_SESSION['already_attached']))
  1539.     {
  1540.         require_once($sourcedir . '/ManageAttachments.php');
  1541.  
  1542.         foreach ($_SESSION['already_attached'] as $attachID => $attachment)
  1543.             removeAttachments(array('id_attach' => $attachID));
  1544.  
  1545.         unset($_SESSION['already_attached']);
  1546.  
  1547.         $post_errors[] = array('cannot_post_attachment', array($board_info['name']));
  1548.     }
  1549.  
  1550.     $can_approve = allowedTo('approve_posts');
  1551.  
  1552.     // If this isn't a new topic load the topic info that we need.
  1553.     if (!empty($topic))
  1554.     {
  1555.         $request = $smcFunc['db_query']('', '
  1556.             SELECT locked, is_sticky, id_poll, approved, id_first_msg, id_last_msg, id_member_started, id_board
  1557.             FROM {db_prefix}topics
  1558.             WHERE id_topic = {int:current_topic}
  1559.             LIMIT 1',
  1560.             array(
  1561.                 'current_topic' => $topic,
  1562.             )
  1563.         );
  1564.         $topic_info = $smcFunc['db_fetch_assoc']($request);
  1565.         $smcFunc['db_free_result']($request);
  1566.  
  1567.         // Though the topic should be there, it might have vanished.
  1568.         if (!is_array($topic_info))
  1569.             fatal_lang_error('topic_doesnt_exist', 404);
  1570.  
  1571.         // Did this topic suddenly move? Just checking...
  1572.         if ($topic_info['id_board'] != $board)
  1573.             fatal_lang_error('not_a_topic');
  1574.  
  1575.         // Do the permissions and approval stuff...
  1576.         $becomesApproved = true;
  1577.  
  1578.         // Replies to unapproved topics are unapproved by default (but not for moderators)
  1579.         if (empty($topic_info['approved']) && !$can_approve)
  1580.         {
  1581.             $becomesApproved = false;
  1582.  
  1583.             // Set a nice session var...
  1584.             $_SESSION['becomesUnapproved'] = true;
  1585.         }
  1586.     }
  1587.  
  1588.     // Replying to a topic?
  1589.     if (!empty($topic) && !isset($_REQUEST['msg']))
  1590.     {
  1591.         // Don't allow a post if it's locked.
  1592.         if ($topic_info['locked'] != 0 && !allowedTo('moderate_board'))
  1593.             fatal_lang_error('topic_locked', false);
  1594.  
  1595.         // Sorry, multiple polls aren't allowed... yet.  You should stop giving me ideas :P.
  1596.         if (isset($_REQUEST['poll']) && $topic_info['id_poll'] > 0)
  1597.             unset($_REQUEST['poll']);
  1598.  
  1599.         elseif ($topic_info['id_member_started'] != $user_info['id'])
  1600.         {
  1601.             if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_any') && !allowedTo('post_reply_any'))
  1602.                 $becomesApproved = false;
  1603.  
  1604.             else
  1605.                 isAllowedTo('post_reply_any');
  1606.         }
  1607.         elseif (!allowedTo('post_reply_any'))
  1608.         {
  1609.             if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_own') && !allowedTo('post_reply_own'))
  1610.                 $becomesApproved = false;
  1611.  
  1612.             else
  1613.                 isAllowedTo('post_reply_own');
  1614.         }
  1615.  
  1616.         if (isset($_POST['lock']))
  1617.         {
  1618.             // Nothing is changed to the lock.
  1619.             if (empty($topic_info['locked']) == empty($_POST['lock']))
  1620.                 unset($_POST['lock']);
  1621.  
  1622.             // You're have no permission to lock this topic.
  1623.             elseif (!allowedTo(array('lock_any', 'lock_own')) || (!allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']))
  1624.                 unset($_POST['lock']);
  1625.  
  1626.             // You are allowed to (un)lock your own topic only.
  1627.             elseif (!allowedTo('lock_any'))
  1628.             {
  1629.                 // You cannot override a moderator lock.
  1630.                 if ($topic_info['locked'] == 1)
  1631.                     unset($_POST['lock']);
  1632.  
  1633.                 else
  1634.                     $_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
  1635.             }
  1636.             // Hail mighty moderator, (un)lock this topic immediately.
  1637.             else
  1638.             {
  1639.                 $_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
  1640.  
  1641.                 // Did someone (un)lock this while you were posting?
  1642.                 if (isset($_POST['already_locked']) && $_POST['already_locked'] != $topic_info['locked'])
  1643.                     $post_errors[] = 'topic_' . (empty($topic_info['locked']) ? 'un' : '') . 'locked';
  1644.             }
  1645.         }
  1646.  
  1647.         // So you wanna (un)sticky this...let's see.
  1648.         if (isset($_POST['sticky']) && ($_POST['sticky'] == $topic_info['is_sticky'] || !allowedTo('make_sticky')))
  1649.             unset($_POST['sticky']);
  1650.         elseif (isset($_POST['sticky']))
  1651.         {
  1652.             // Did someone (un)sticky this while you were posting?
  1653.             if (isset($_POST['already_sticky']) && $_POST['already_sticky'] != $topic_info['is_sticky'])
  1654.                 $post_errors[] = 'topic_' . (empty($topic_info['is_sticky']) ? 'un' : '') . 'sticky';
  1655.         }
  1656.  
  1657.         // If drafts are enabled, then pass this off
  1658.         if (!empty($modSettings['drafts_post_enabled']) && isset($_POST['save_draft']))
  1659.         {
  1660.             SaveDraft($post_errors);
  1661.             return Post();
  1662.         }
  1663.  
  1664.         // If the number of replies has changed, if the setting is enabled, go back to Post() - which handles the error.
  1665.         if (isset($_POST['last_msg']) && $topic_info['id_last_msg'] > $_POST['last_msg'])
  1666.         {
  1667.             $_REQUEST['preview'] = true;
  1668.             return Post();
  1669.         }
  1670.  
  1671.         $posterIsGuest = $user_info['is_guest'];
  1672.     }
  1673.     // Posting a new topic.
  1674.     elseif (empty($topic))
  1675.     {
  1676.         // Now don't be silly, new topics will get their own id_msg soon enough.
  1677.         unset($_REQUEST['msg'], $_POST['msg'], $_GET['msg']);
  1678.  
  1679.         // Do like, the permissions, for safety and stuff...
  1680.         $becomesApproved = true;
  1681.         if ($modSettings['postmod_active'] && !allowedTo('post_new') && allowedTo('post_unapproved_topics'))
  1682.             $becomesApproved = false;
  1683.         else
  1684.             isAllowedTo('post_new');
  1685.  
  1686.         if (isset($_POST['lock']))
  1687.         {
  1688.             // New topics are by default not locked.
  1689.             if (empty($_POST['lock']))
  1690.                 unset($_POST['lock']);
  1691.             // Besides, you need permission.
  1692.             elseif (!allowedTo(array('lock_any', 'lock_own')))
  1693.                 unset($_POST['lock']);
  1694.             // A moderator-lock (1) can override a user-lock (2).
  1695.             else
  1696.                 $_POST['lock'] = allowedTo('lock_any') ? 1 : 2;
  1697.         }
  1698.  
  1699.         if (isset($_POST['sticky']) && (empty($_POST['sticky']) || !allowedTo('make_sticky')))
  1700.             unset($_POST['sticky']);
  1701.  
  1702.         // Saving your new topic as a draft first?
  1703.         if (!empty($modSettings['drafts_post_enabled']) && isset($_POST['save_draft']))
  1704.         {
  1705.             SaveDraft($post_errors);
  1706.             return Post();
  1707.         }
  1708.  
  1709.         $posterIsGuest = $user_info['is_guest'];
  1710.     }
  1711.     // Modifying an existing message?
  1712.     elseif (isset($_REQUEST['msg']) && !empty($topic))
  1713.     {
  1714.         $_REQUEST['msg'] = (int) $_REQUEST['msg'];
  1715.  
  1716.         $request = $smcFunc['db_query']('', '
  1717.             SELECT id_member, poster_name, poster_email, poster_time, approved
  1718.             FROM {db_prefix}messages
  1719.             WHERE id_msg = {int:id_msg}
  1720.             LIMIT 1',
  1721.             array(
  1722.                 'id_msg' => $_REQUEST['msg'],
  1723.             )
  1724.         );
  1725.         if ($smcFunc['db_num_rows']($request) == 0)
  1726.             fatal_lang_error('cant_find_messages', false);
  1727.         $row = $smcFunc['db_fetch_assoc']($request);
  1728.         $smcFunc['db_free_result']($request);
  1729.  
  1730.         if (!empty($topic_info['locked']) && !allowedTo('moderate_board'))
  1731.             fatal_lang_error('topic_locked', false);
  1732.  
  1733.         if (isset($_POST['lock']))
  1734.         {
  1735.             // Nothing changes to the lock status.
  1736.             if ((empty($_POST['lock']) && empty($topic_info['locked'])) || (!empty($_POST['lock']) && !empty($topic_info['locked'])))
  1737.                 unset($_POST['lock']);
  1738.             // You're simply not allowed to (un)lock this.
  1739.             elseif (!allowedTo(array('lock_any', 'lock_own')) || (!allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']))
  1740.                 unset($_POST['lock']);
  1741.             // You're only allowed to lock your own topics.
  1742.             elseif (!allowedTo('lock_any'))
  1743.             {
  1744.                 // You're not allowed to break a moderator's lock.
  1745.                 if ($topic_info['locked'] == 1)
  1746.                     unset($_POST['lock']);
  1747.                 // Lock it with a soft lock or unlock it.
  1748.                 else
  1749.                     $_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
  1750.             }
  1751.             // You must be the moderator.
  1752.             else
  1753.             {
  1754.                 $_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
  1755.  
  1756.                 // Did someone (un)lock this while you were posting?
  1757.                 if (isset($_POST['already_locked']) && $_POST['already_locked'] != $topic_info['locked'])
  1758.                     $post_errors[] = 'topic_' . (empty($topic_info['locked']) ? 'un' : '') . 'locked';
  1759.             }
  1760.         }
  1761.  
  1762.         // Change the sticky status of this topic?
  1763.         if (isset($_POST['sticky']) && (!allowedTo('make_sticky') || $_POST['sticky'] == $topic_info['is_sticky']))
  1764.             unset($_POST['sticky']);
  1765.         elseif (isset($_POST['sticky']))
  1766.         {
  1767.             // Did someone (un)sticky this while you were posting?
  1768.             if (isset($_POST['already_sticky']) && $_POST['already_sticky'] != $topic_info['is_sticky'])
  1769.                 $post_errors[] = 'topic_' . (empty($topic_info['locked']) ? 'un' : '') . 'stickied';
  1770.         }
  1771.  
  1772.         if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any'))
  1773.         {
  1774.             if ((!$modSettings['postmod_active'] || $row['approved']) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time())
  1775.                 fatal_lang_error('modify_post_time_passed', false);
  1776.             elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_own'))
  1777.                 isAllowedTo('modify_replies');
  1778.             else
  1779.                 isAllowedTo('modify_own');
  1780.         }
  1781.         elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_any'))
  1782.         {
  1783.             isAllowedTo('modify_replies');
  1784.  
  1785.             // If you're modifying a reply, I say it better be logged...
  1786.             $moderationAction = true;
  1787.         }
  1788.         else
  1789.         {
  1790.             isAllowedTo('modify_any');
  1791.  
  1792.             // Log it, assuming you're not modifying your own post.
  1793.             if ($row['id_member'] != $user_info['id'])
  1794.                 $moderationAction = true;
  1795.         }
  1796.  
  1797.         // If drafts are enabled, then lets send this off to save
  1798.         if (!empty($modSettings['drafts_post_enabled']) && isset($_POST['save_draft']))
  1799.         {
  1800.             SaveDraft($post_errors);
  1801.             return Post();
  1802.         }
  1803.  
  1804.         $posterIsGuest = empty($row['id_member']);
  1805.  
  1806.         // Can they approve it?
  1807.         $approve_checked = (!empty($REQUEST['approve']) ? 1 : 0);
  1808.         $becomesApproved = $modSettings['postmod_active'] ? ($can_approve && !$row['approved'] ? $approve_checked : $row['approved']) : 1;
  1809.         $approve_has_changed = $row['approved'] != $becomesApproved;
  1810.  
  1811.         if (!allowedTo('moderate_forum') || !$posterIsGuest)
  1812.         {
  1813.             $_POST['guestname'] = $row['poster_name'];
  1814.             $_POST['email'] = $row['poster_email'];
  1815.         }
  1816.  
  1817.         // Update search api
  1818.         require_once($sourcedir . '/Search.php');
  1819.         $searchAPI = findSearchAPI();
  1820.         if ($searchAPI->supportsMethod('postRemoved'))
  1821.             $searchAPI->postRemoved($_REQUEST['msg']);
  1822.  
  1823.     }
  1824.  
  1825.     // In case we have approval permissions and want to override.
  1826.     if ($can_approve && $modSettings['postmod_active'])
  1827.     {
  1828.         $becomesApproved = isset($_POST['quickReply']) || !empty($_REQUEST['approve']) ? 1 : 0;
  1829.         $approve_has_changed = isset($row['approved']) ? $row['approved'] != $becomesApproved : false;
  1830.     }
  1831.  
  1832.     // If the poster is a guest evaluate the legality of name and email.
  1833.     if ($posterIsGuest)
  1834.     {
  1835.         $_POST['guestname'] = !isset($_POST['guestname']) ? '' : trim($_POST['guestname']);
  1836.         $_POST['email'] = !isset($_POST['email']) ? '' : trim($_POST['email']);
  1837.  
  1838.         if ($_POST['guestname'] == '' || $_POST['guestname'] == '_')
  1839.             $post_errors[] = 'no_name';
  1840.         if ($smcFunc['strlen']($_POST['guestname']) > 25)
  1841.             $post_errors[] = 'long_name';
  1842.  
  1843.         if (empty($modSettings['guest_post_no_email']))
  1844.         {
  1845.             // Only check if they changed it!
  1846.             if (!isset($row) || $row['poster_email'] != $_POST['email'])
  1847.             {
  1848.                 if (!allowedTo('moderate_forum') && (!isset($_POST['email']) || $_POST['email'] == ''))
  1849.                     $post_errors[] = 'no_email';
  1850.                 if (!allowedTo('moderate_forum') && !filter_var($_POST['email'], FILTER_VALIDATE_EMAIL))
  1851.                     $post_errors[] = 'bad_email';
  1852.             }
  1853.  
  1854.             // Now make sure this email address is not banned from posting.
  1855.             isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt['guest_title']));
  1856.         }
  1857.  
  1858.         // In case they are making multiple posts this visit, help them along by storing their name.
  1859.         if (empty($post_errors))
  1860.         {
  1861.             $_SESSION['guest_name'] = $_POST['guestname'];
  1862.             $_SESSION['guest_email'] = $_POST['email'];
  1863.         }
  1864.     }
  1865.  
  1866.     // Coming from the quickReply?
  1867.     if (isset($_POST['quickReply']))
  1868.         $_POST['message'] = $_POST['quickReply'];
  1869.  
  1870.     // Check the subject and message.
  1871.     if (!isset($_POST['subject']) || $smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['subject'])) === '')
  1872.         $post_errors[] = 'no_subject';
  1873.     if (!isset($_POST['message']) || $smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['message']), ENT_QUOTES) === '')
  1874.         $post_errors[] = 'no_message';
  1875.     elseif (!empty($modSettings['max_messageLength']) && $smcFunc['strlen']($_POST['message']) > $modSettings['max_messageLength'])
  1876.         $post_errors[] = array('long_message', array($modSettings['max_messageLength']));
  1877.     else
  1878.     {
  1879.         // Prepare the message a bit for some additional testing.
  1880.         $_POST['message'] = $smcFunc['htmlspecialchars']($_POST['message'], ENT_QUOTES);
  1881.  
  1882.         // Preparse code. (Zef)
  1883.         if ($user_info['is_guest'])
  1884.             $user_info['name'] = $_POST['guestname'];
  1885.         preparsecode($_POST['message']);
  1886.  
  1887.         // Let's see if there's still some content left without the tags.
  1888.         if ($smcFunc['htmltrim'](strip_tags(parse_bbc($_POST['message'], false), implode('', $context['allowed_html_tags']))) === '' && (!allowedTo('bbc_html') || strpos($_POST['message'], '[html]') === false))
  1889.             $post_errors[] = 'no_message';
  1890.  
  1891.     }
  1892.     if (isset($_POST['calendar']) && !isset($_REQUEST['deleteevent']) && $smcFunc['htmltrim']($_POST['evtitle']) === '')
  1893.         $post_errors[] = 'no_event';
  1894.     // You are not!
  1895.     if (isset($_POST['message']) && strtolower($_POST['message']) == 'i am the administrator.' && !$user_info['is_admin'])
  1896.         fatal_error('Knave! Masquerader! Charlatan!', false);
  1897.  
  1898.     // Validate the poll...
  1899.     if (isset($_REQUEST['poll']) && $modSettings['pollMode'] == '1')
  1900.     {
  1901.         if (!empty($topic) && !isset($_REQUEST['msg']))
  1902.             fatal_lang_error('no_access', false);
  1903.  
  1904.         // This is a new topic... so it's a new poll.
  1905.         if (empty($topic))
  1906.             isAllowedTo('poll_post');
  1907.         // Can you add to your own topics?
  1908.         elseif ($user_info['id'] == $topic_info['id_member_started'] && !allowedTo('poll_add_any'))
  1909.             isAllowedTo('poll_add_own');
  1910.         // Can you add polls to any topic, then?
  1911.         else
  1912.             isAllowedTo('poll_add_any');
  1913.  
  1914.         if (!isset($_POST['question']) || trim($_POST['question']) == '')
  1915.             $post_errors[] = 'no_question';
  1916.  
  1917.         $_POST['options'] = empty($_POST['options']) ? array() : htmltrim__recursive($_POST['options']);
  1918.  
  1919.         // Get rid of empty ones.
  1920.         foreach ($_POST['options'] as $k => $option)
  1921.             if ($option == '')
  1922.                 unset($_POST['options'][$k], $_POST['options'][$k]);
  1923.  
  1924.         // What are you going to vote between with one choice?!?
  1925.         if (count($_POST['options']) < 2)
  1926.             $post_errors[] = 'poll_few';
  1927.         elseif (count($_POST['options']) > 256)
  1928.             $post_errors[] = 'poll_many';
  1929.     }
  1930.  
  1931.     if ($posterIsGuest)
  1932.     {
  1933.         // If user is a guest, make sure the chosen name isn't taken.
  1934.         require_once($sourcedir . '/Subs-Members.php');
  1935.         if (isReservedName($_POST['guestname'], 0, true, false) && (!isset($row['poster_name']) || $_POST['guestname'] != $row['poster_name']))
  1936.             $post_errors[] = 'bad_name';
  1937.     }
  1938.     // If the user isn't a guest, get his or her name and email.
  1939.     elseif (!isset($_REQUEST['msg']))
  1940.     {
  1941.         $_POST['guestname'] = $user_info['username'];
  1942.         $_POST['email'] = $user_info['email'];
  1943.     }
  1944.  
  1945.     // Any mistakes?
  1946.     if (!empty($post_errors))
  1947.     {
  1948.         // Previewing.
  1949.         $_REQUEST['preview'] = true;
  1950.  
  1951.         return Post($post_errors);
  1952.     }
  1953.  
  1954.     // Previewing? Go back to start.
  1955.     if (isset($_REQUEST['preview']))
  1956.     {
  1957.         if (checkSession('post', '', false) != '')
  1958.         {
  1959.             loadLanguage('Errors');
  1960.             $post_errors[] = 'session_timeout';
  1961.             unset ($_POST['preview'], $_REQUEST['xml']); // just in case
  1962.         }
  1963.         return Post($post_errors);
  1964.     }
  1965.  
  1966.     // Make sure the user isn't spamming the board.
  1967.     if (!isset($_REQUEST['msg']))
  1968.         spamProtection('post');
  1969.  
  1970.     // At about this point, we're posting and that's that.
  1971.     ignore_user_abort(true);
  1972.     @set_time_limit(300);
  1973.  
  1974.     // Add special html entities to the subject, name, and email.
  1975.     $_POST['subject'] = strtr($smcFunc['htmlspecialchars']($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
  1976.     $_POST['guestname'] = $smcFunc['htmlspecialchars']($_POST['guestname']);
  1977.     $_POST['email'] = $smcFunc['htmlspecialchars']($_POST['email']);
  1978.     $_POST['modify_reason'] = empty($_POST['modify_reason']) ? '' : strtr($smcFunc['htmlspecialchars']($_POST['modify_reason']), array("\r" => '', "\n" => '', "\t" => ''));
  1979.  
  1980.     // At this point, we want to make sure the subject isn't too long.
  1981.     if ($smcFunc['strlen']($_POST['subject']) > 100)
  1982.         $_POST['subject'] = $smcFunc['substr']($_POST['subject'], 0, 100);
  1983.  
  1984.     // Same with the "why did you edit this" text.
  1985.     if ($smcFunc['strlen']($_POST['modify_reason']) > 100)
  1986.         $_POST['modify_reason'] = $smcFunc['substr']($_POST['modify_reason'], 0, 100);
  1987.  
  1988.     // Make the poll...
  1989.     if (isset($_REQUEST['poll']))
  1990.     {
  1991.         // Make sure that the user has not entered a ridiculous number of options..
  1992.         if (empty($_POST['poll_max_votes']) || $_POST['poll_max_votes'] <= 0)
  1993.             $_POST['poll_max_votes'] = 1;
  1994.         elseif ($_POST['poll_max_votes'] > count($_POST['options']))
  1995.             $_POST['poll_max_votes'] = count($_POST['options']);
  1996.         else
  1997.             $_POST['poll_max_votes'] = (int) $_POST['poll_max_votes'];
  1998.  
  1999.         $_POST['poll_expire'] = (int) $_POST['poll_expire'];
  2000.         $_POST['poll_expire'] = $_POST['poll_expire'] > 9999 ? 9999 : ($_POST['poll_expire'] < 0 ? 0 : $_POST['poll_expire']);
  2001.  
  2002.         // Just set it to zero if it's not there..
  2003.         if (!isset($_POST['poll_hide']))
  2004.             $_POST['poll_hide'] = 0;
  2005.         else
  2006.             $_POST['poll_hide'] = (int) $_POST['poll_hide'];
  2007.         $_POST['poll_change_vote'] = isset($_POST['poll_change_vote']) ? 1 : 0;
  2008.  
  2009.         $_POST['poll_guest_vote'] = isset($_POST['poll_guest_vote']) ? 1 : 0;
  2010.         // Make sure guests are actually allowed to vote generally.
  2011.         if ($_POST['poll_guest_vote'])
  2012.         {
  2013.             require_once($sourcedir . '/Subs-Members.php');
  2014.             $allowedVoteGroups = groupsAllowedTo('poll_vote', $board);
  2015.             if (!in_array(-1, $allowedVoteGroups['allowed']))
  2016.                 $_POST['poll_guest_vote'] = 0;
  2017.         }
  2018.  
  2019.         // If the user tries to set the poll too far in advance, don't let them.
  2020.         if (!empty($_POST['poll_expire']) && $_POST['poll_expire'] < 1)
  2021.             fatal_lang_error('poll_range_error', false);
  2022.         // Don't allow them to select option 2 for hidden results if it's not time limited.
  2023.         elseif (empty($_POST['poll_expire']) && $_POST['poll_hide'] == 2)
  2024.             $_POST['poll_hide'] = 1;
  2025.  
  2026.         // Clean up the question and answers.
  2027.         $_POST['question'] = $smcFunc['htmlspecialchars']($_POST['question']);
  2028.         $_POST['question'] = $smcFunc['truncate']($_POST['question'], 255);
  2029.         $_POST['question'] = preg_replace('~&amp;#(\d{4,5}|[2-9]\d{2,4}|1[2-9]\d);~', '&#$1;', $_POST['question']);
  2030.         $_POST['options'] = htmlspecialchars__recursive($_POST['options']);
  2031.     }
  2032.  
  2033.     // ...or attach a new file...
  2034.     if ($context['can_post_attachment'] && !empty($_SESSION['temp_attachments']) && empty($_POST['from_qr']))
  2035.     {
  2036.         $attachIDs = array();
  2037.         $attach_errors = array();
  2038.         if (!empty($context['we_are_history']))
  2039.             $attach_errors[] = '<dd>' . $txt['error_temp_attachments_flushed'] . '<br><br></dd>';
  2040.  
  2041.         foreach ($_SESSION['temp_attachments'] as $attachID => $attachment)
  2042.         {
  2043.             if ($attachID != 'initial_error' && strpos($attachID, 'post_tmp_' . $user_info['id']) === false)
  2044.                 continue;
  2045.  
  2046.             // If there was an initial error just show that message.
  2047.             if ($attachID == 'initial_error')
  2048.             {
  2049.                 $attach_errors[] = '<dt>' . $txt['attach_no_upload'] . '</dt>';
  2050.                 $attach_errors[] = '<dd>' . (is_array($attachment) ? vsprintf($txt[$attachment[0]], $attachment[1]) : $txt[$attachment]) . '</dd>';
  2051.  
  2052.                 unset($_SESSION['temp_attachments']);
  2053.                 break;
  2054.             }
  2055.  
  2056.             $attachmentOptions = array(
  2057.                 'post' => isset($_REQUEST['msg']) ? $_REQUEST['msg'] : 0,
  2058.                 'poster' => $user_info['id'],
  2059.                 'name' => $attachment['name'],
  2060.                 'tmp_name' => $attachment['tmp_name'],
  2061.                 'size' => isset($attachment['size']) ? $attachment['size'] : 0,
  2062.                 'mime_type' => isset($attachment['type']) ? $attachment['type'] : '',
  2063.                 'id_folder' => isset($attachment['id_folder']) ? $attachment['id_folder'] : $modSettings['currentAttachmentUploadDir'],
  2064.                 'approved' => !$modSettings['postmod_active'] || allowedTo('post_attachment'),
  2065.                 'errors' => $attachment['errors'],
  2066.             );
  2067.  
  2068.             if (empty($attachment['errors']))
  2069.             {
  2070.                 if (createAttachment($attachmentOptions))
  2071.                 {
  2072.                     $attachIDs[] = $attachmentOptions['id'];
  2073.                     if (!empty($attachmentOptions['thumb']))
  2074.                         $attachIDs[] = $attachmentOptions['thumb'];
  2075.                 }
  2076.             }
  2077.             else
  2078.                 $attach_errors[] = '<dt>&nbsp;</dt>';
  2079.  
  2080.             if (!empty($attachmentOptions['errors']))
  2081.             {
  2082.                 // Sort out the errors for display and delete any associated files.
  2083.                 $attach_errors[] = '<dt>' . vsprintf($txt['attach_warning'], $attachment['name']) . '</dt>';
  2084.                 $log_these = array('attachments_no_create', 'attachments_no_write', 'attach_timeout', 'ran_out_of_space', 'cant_access_upload_path', 'attach_0_byte_file');
  2085.                 foreach ($attachmentOptions['errors'] as $error)
  2086.                 {
  2087.                     if (!is_array($error))
  2088.                     {
  2089.                         $attach_errors[] = '<dd>' . $txt[$error] . '</dd>';
  2090.                         if (in_array($error, $log_these))
  2091.                             log_error($attachment['name'] . ': ' . $txt[$error], 'critical');
  2092.                     }
  2093.                     else
  2094.                         $attach_errors[] = '<dd>' . vsprintf($txt[$error[0]], $error[1]) . '</dd>';
  2095.                 }
  2096.                 if (file_exists($attachment['tmp_name']))
  2097.                     unlink($attachment['tmp_name']);
  2098.             }
  2099.         }
  2100.         unset($_SESSION['temp_attachments']);
  2101.     }
  2102.  
  2103.     // Make the poll...
  2104.     if (isset($_REQUEST['poll']))
  2105.     {
  2106.         // Create the poll.
  2107.         $id_poll = $smcFunc['db_insert']('',
  2108.             '{db_prefix}polls',
  2109.             array(
  2110.                 'question' => 'string-255', 'hide_results' => 'int', 'max_votes' => 'int', 'expire_time' => 'int', 'id_member' => 'int',
  2111.                 'poster_name' => 'string-255', 'change_vote' => 'int', 'guest_vote' => 'int'
  2112.             ),
  2113.             array(
  2114.                 $_POST['question'], $_POST['poll_hide'], $_POST['poll_max_votes'], (empty($_POST['poll_expire']) ? 0 : time() + $_POST['poll_expire'] * 3600 * 24), $user_info['id'],
  2115.                 $_POST['guestname'], $_POST['poll_change_vote'], $_POST['poll_guest_vote'],
  2116.             ),
  2117.             array('id_poll'),
  2118.             1
  2119.         );
  2120.  
  2121.         // Create each answer choice.
  2122.         $i = 0;
  2123.         $pollOptions = array();
  2124.         foreach ($_POST['options'] as $option)
  2125.         {
  2126.             $pollOptions[] = array($id_poll, $i, $option);
  2127.             $i++;
  2128.         }
  2129.  
  2130.         $smcFunc['db_insert']('insert',
  2131.             '{db_prefix}poll_choices',
  2132.             array('id_poll' => 'int', 'id_choice' => 'int', 'label' => 'string-255'),
  2133.             $pollOptions,
  2134.             array('id_poll', 'id_choice')
  2135.         );
  2136.  
  2137.         call_integration_hook('integrate_poll_add_edit', array($id_poll, false));
  2138.     }
  2139.     else
  2140.         $id_poll = 0;
  2141.  
  2142.     // Creating a new topic?
  2143.     $newTopic = empty($_REQUEST['msg']) && empty($topic);
  2144.  
  2145.     // Check the icon.
  2146.     if (!isset($_POST['icon']))
  2147.         $_POST['icon'] = 'xx';
  2148.  
  2149.     else
  2150.     {
  2151.         $_POST['icon'] = $smcFunc['htmlspecialchars']($_POST['icon']);
  2152.  
  2153.         // Need to figure it out if this is a valid icon name.
  2154.         if ((!file_exists($settings['theme_dir'] . '/images/post/' . $_POST['icon'] . '.png')) && (!file_exists($settings['default_theme_dir'] . '/images/post/' . $_POST['icon'] . '.png')))
  2155.             $_POST['icon'] = 'xx';
  2156.     }
  2157.  
  2158.     // Collect all parameters for the creation or modification of a post.
  2159.     $msgOptions = array(
  2160.         'id' => empty($_REQUEST['msg']) ? 0 : (int) $_REQUEST['msg'],
  2161.         'subject' => $_POST['subject'],
  2162.         'body' => $_POST['message'],
  2163.         'icon' => preg_replace('~[\./\\\\*:"\'<>]~', '', $_POST['icon']),
  2164.         'smileys_enabled' => !isset($_POST['ns']),
  2165.         'attachments' => empty($attachIDs) ? array() : $attachIDs,
  2166.         'approved' => $becomesApproved,
  2167.     );
  2168.     $topicOptions = array(
  2169.         'id' => empty($topic) ? 0 : $topic,
  2170.         'board' => $board,
  2171.         'poll' => isset($_REQUEST['poll']) ? $id_poll : null,
  2172.         'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null,
  2173.         'sticky_mode' => isset($_POST['sticky']) ? (int) $_POST['sticky'] : null,
  2174.         'mark_as_read' => true,
  2175.         'is_approved' => !$modSettings['postmod_active'] || empty($topic) || !empty($board_info['cur_topic_approved']),
  2176.     );
  2177.     $posterOptions = array(
  2178.         'id' => $user_info['id'],
  2179.         'name' => $_POST['guestname'],
  2180.         'email' => $_POST['email'],
  2181.         'update_post_count' => !$user_info['is_guest'] && !isset($_REQUEST['msg']) && $board_info['posts_count'],
  2182.     );
  2183.  
  2184.     // This is an already existing message. Edit it.
  2185.     if (!empty($_REQUEST['msg']))
  2186.     {
  2187.         // Have admins allowed people to hide their screwups?
  2188.         if (time() - $row['poster_time'] > $modSettings['edit_wait_time'] || $user_info['id'] != $row['id_member'])
  2189.         {
  2190.             $msgOptions['modify_time'] = time();
  2191.             $msgOptions['modify_name'] = $user_info['name'];
  2192.             $msgOptions['modify_reason'] = $_POST['modify_reason'];
  2193.         }
  2194.  
  2195.         // This will save some time...
  2196.         if (empty($approve_has_changed))
  2197.             unset($msgOptions['approved']);
  2198.  
  2199.         modifyPost($msgOptions, $topicOptions, $posterOptions);
  2200.     }
  2201.     // This is a new topic or an already existing one. Save it.
  2202.     else
  2203.     {
  2204.         createPost($msgOptions, $topicOptions, $posterOptions);
  2205.  
  2206.         if (isset($topicOptions['id']))
  2207.             $topic = $topicOptions['id'];
  2208.     }
  2209.  
  2210.     // Are there attachments already uploaded and waiting to be assigned?
  2211.     if (!empty($msgOptions['id']) && !empty($_SESSION['already_attached']))
  2212.     {
  2213.         require_once($sourcedir . '/Subs-Attachments.php');
  2214.         assignAttachments($_SESSION['already_attached'], $msgOptions['id']);
  2215.         unset($_SESSION['already_attached']);
  2216.     }
  2217.  
  2218.     // If we had a draft for this, its time to remove it since it was just posted
  2219.     if (!empty($modSettings['drafts_post_enabled']) && !empty($_POST['id_draft']))
  2220.         DeleteDraft($_POST['id_draft']);
  2221.  
  2222.     // Editing or posting an event?
  2223.     if (isset($_POST['calendar']) && (!isset($_REQUEST['eventid']) || $_REQUEST['eventid'] == -1))
  2224.     {
  2225.         require_once($sourcedir . '/Subs-Calendar.php');
  2226.  
  2227.         // Make sure they can link an event to this post.
  2228.         canLinkEvent();
  2229.  
  2230.         // Insert the event.
  2231.         $eventOptions = array(
  2232.             'board' => $board,
  2233.             'topic' => $topic,
  2234.             'title' => $_POST['evtitle'],
  2235.             'location' => $_POST['event_location'],
  2236.             'member' => $user_info['id'],
  2237.         );
  2238.         insertEvent($eventOptions);
  2239.     }
  2240.     elseif (isset($_POST['calendar']))
  2241.     {
  2242.         $_REQUEST['eventid'] = (int) $_REQUEST['eventid'];
  2243.  
  2244.         // Validate the post...
  2245.         require_once($sourcedir . '/Subs-Calendar.php');
  2246.         validateEventPost();
  2247.  
  2248.         // If you're not allowed to edit any events, you have to be the poster.
  2249.         if (!allowedTo('calendar_edit_any'))
  2250.         {
  2251.             // Get the event's poster.
  2252.             $request = $smcFunc['db_query']('', '
  2253.                 SELECT id_member
  2254.                 FROM {db_prefix}calendar
  2255.                 WHERE id_event = {int:id_event}',
  2256.                 array(
  2257.                     'id_event' => $_REQUEST['eventid'],
  2258.                 )
  2259.             );
  2260.             $row2 = $smcFunc['db_fetch_assoc']($request);
  2261.             $smcFunc['db_free_result']($request);
  2262.  
  2263.             // Silly hacker, Trix are for kids. ...probably trademarked somewhere, this is FAIR USE! (parody...)
  2264.             isAllowedTo('calendar_edit_' . ($row2['id_member'] == $user_info['id'] ? 'own' : 'any'));
  2265.         }
  2266.  
  2267.         // Delete it?
  2268.         if (isset($_REQUEST['deleteevent']))
  2269.             $smcFunc['db_query']('', '
  2270.                 DELETE FROM {db_prefix}calendar
  2271.                 WHERE id_event = {int:id_event}',
  2272.                 array(
  2273.                     'id_event' => $_REQUEST['eventid'],
  2274.                 )
  2275.             );
  2276.         // ... or just update it?
  2277.         else
  2278.         {
  2279.             // Set up our options
  2280.             $eventOptions = array(
  2281.                 'board' => $board,
  2282.                 'topic' => $topic,
  2283.                 'title' => $_POST['evtitle'],
  2284.                 'location' => $_POST['event_location'],
  2285.                 'member' => $user_info['id'],
  2286.             );
  2287.             modifyEvent($_REQUEST['eventid'], $eventOptions);
  2288.         }
  2289.     }
  2290.  
  2291.     // Marking read should be done even for editing messages....
  2292.     // Mark all the parents read.  (since you just posted and they will be unread.)
  2293.     if (!$user_info['is_guest'] && !empty($board_info['parent_boards']))
  2294.     {
  2295.         $smcFunc['db_query']('', '
  2296.             UPDATE {db_prefix}log_boards
  2297.             SET id_msg = {int:id_msg}
  2298.             WHERE id_member = {int:current_member}
  2299.                 AND id_board IN ({array_int:board_list})',
  2300.             array(
  2301.                 'current_member' => $user_info['id'],
  2302.                 'board_list' => array_keys($board_info['parent_boards']),
  2303.                 'id_msg' => $modSettings['maxMsgID'],
  2304.             )
  2305.         );
  2306.     }
  2307.  
  2308.     // Turn notification on or off.  (note this just blows smoke if it's already on or off.)
  2309.     if (!empty($_POST['notify']) && !$context['user']['is_guest'])
  2310.     {
  2311.         $smcFunc['db_insert']('ignore',
  2312.             '{db_prefix}log_notify',
  2313.             array('id_member' => 'int', 'id_topic' => 'int', 'id_board' => 'int'),
  2314.             array($user_info['id'], $topic, 0),
  2315.             array('id_member', 'id_topic', 'id_board')
  2316.         );
  2317.     }
  2318.     elseif (!$newTopic)
  2319.         $smcFunc['db_query']('', '
  2320.             DELETE FROM {db_prefix}log_notify
  2321.             WHERE id_member = {int:current_member}
  2322.                 AND id_topic = {int:current_topic}',
  2323.             array(
  2324.                 'current_member' => $user_info['id'],
  2325.                 'current_topic' => $topic,
  2326.             )
  2327.         );
  2328.  
  2329.     // Log an act of moderation - modifying.
  2330.     if (!empty($moderationAction))
  2331.         logAction('modify', array('topic' => $topic, 'message' => (int) $_REQUEST['msg'], 'member' => $row['id_member'], 'board' => $board));
  2332.  
  2333.     if (isset($_POST['lock']) && $_POST['lock'] != 2)
  2334.         logAction(empty($_POST['lock']) ? 'unlock' : 'lock', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board']));
  2335.  
  2336.     if (isset($_POST['sticky']))
  2337.         logAction(empty($_POST['sticky']) ? 'unsticky' : 'sticky', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board']));
  2338.  
  2339.     // Returning to the topic?
  2340.     if (!empty($_REQUEST['goback']))
  2341.     {
  2342.         // Mark the board as read.... because it might get confusing otherwise.
  2343.         $smcFunc['db_query']('', '
  2344.             UPDATE {db_prefix}log_boards
  2345.             SET id_msg = {int:maxMsgID}
  2346.             WHERE id_member = {int:current_member}
  2347.                 AND id_board = {int:current_board}',
  2348.             array(
  2349.                 'current_board' => $board,
  2350.                 'current_member' => $user_info['id'],
  2351.                 'maxMsgID' => $modSettings['maxMsgID'],
  2352.             )
  2353.         );
  2354.     }
  2355.  
  2356.     if ($board_info['num_topics'] == 0)
  2357.         cache_put_data('board-' . $board, null, 120);
  2358.  
  2359.     call_integration_hook('integrate_post2_end');
  2360.  
  2361.     if (!empty($_POST['announce_topic']) && allowedTo('announce_topic'))
  2362.         redirectexit('action=announce;sa=selectgroup;topic=' . $topic . (!empty($_POST['move']) && allowedTo('move_any') ? ';move' : '') . (empty($_REQUEST['goback']) ? '' : ';goback'));
  2363.  
  2364.     if (!empty($_POST['move']) && allowedTo('move_any'))
  2365.         redirectexit('action=movetopic;topic=' . $topic . '.0' . (empty($_REQUEST['goback']) ? '' : ';goback'));
  2366.  
  2367.     // Return to post if the mod is on.
  2368.     if (isset($_REQUEST['msg']) && !empty($_REQUEST['goback']))
  2369.         redirectexit('topic=' . $topic . '.msg' . $_REQUEST['msg'] . '#msg' . $_REQUEST['msg'], isBrowser('ie'));
  2370.     elseif (!empty($_REQUEST['goback']))
  2371.         redirectexit('topic=' . $topic . '.new#new', isBrowser('ie'));
  2372.     // Dut-dut-duh-duh-DUH-duh-dut-duh-duh!  *dances to the Final Fantasy Fanfare...*
  2373.     else
  2374.         redirectexit('board=' . $board . '.0');
  2375. }
  2376.  
  2377. /**
  2378.  * Handle the announce topic function (action=announce).
  2379.  *
  2380.  * checks the topic announcement permissions and loads the announcement template.
  2381.  * requires the announce_topic permission.
  2382.  * uses the ManageMembers template and Post language file.
  2383.  * call the right function based on the sub-action.
  2384.  */
  2385. function AnnounceTopic()
  2386. {
  2387.     global $context, $txt, $topic;
  2388.  
  2389.     isAllowedTo('announce_topic');
  2390.  
  2391.     validateSession();
  2392.  
  2393.     if (empty($topic))
  2394.         fatal_lang_error('topic_gone', false);
  2395.  
  2396.     loadLanguage('Post');
  2397.     loadTemplate('Post');
  2398.  
  2399.     $subActions = array(
  2400.         'selectgroup' => 'AnnouncementSelectMembergroup',
  2401.         'send' => 'AnnouncementSend',
  2402.     );
  2403.  
  2404.     $context['page_title'] = $txt['announce_topic'];
  2405.  
  2406.     // Call the function based on the sub-action.
  2407.     $call = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'selectgroup';
  2408.     call_helper($subActions[$call]);
  2409. }
  2410.  
  2411. /**
  2412.  * Allow a user to chose the membergroups to send the announcement to.
  2413.  *
  2414.  * lets the user select the membergroups that will receive the topic announcement.
  2415.  */
  2416. function AnnouncementSelectMembergroup()
  2417. {
  2418.     global $txt, $context, $topic, $board_info, $smcFunc;
  2419.  
  2420.     $groups = array_merge($board_info['groups'], array(1));
  2421.     foreach ($groups as $id => $group)
  2422.         $groups[$id] = (int) $group;
  2423.  
  2424.     $context['groups'] = array();
  2425.     if (in_array(0, $groups))
  2426.     {
  2427.         $context['groups'][0] = array(
  2428.             'id' => 0,
  2429.             'name' => $txt['announce_regular_members'],
  2430.             'member_count' => 'n/a',
  2431.         );
  2432.     }
  2433.  
  2434.     // Get all membergroups that have access to the board the announcement was made on.
  2435.     $request = $smcFunc['db_query']('', '
  2436.         SELECT mg.id_group, COUNT(mem.id_member) AS num_members
  2437.         FROM {db_prefix}membergroups AS mg
  2438.             LEFT JOIN {db_prefix}members AS mem ON (mem.id_group = mg.id_group OR FIND_IN_SET(mg.id_group, mem.additional_groups) != 0 OR mg.id_group = mem.id_post_group)
  2439.         WHERE mg.id_group IN ({array_int:group_list})
  2440.         GROUP BY mg.id_group',
  2441.         array(
  2442.             'group_list' => $groups,
  2443.             'newbie_id_group' => 4,
  2444.         )
  2445.     );
  2446.     while ($row = $smcFunc['db_fetch_assoc']($request))
  2447.     {
  2448.         $context['groups'][$row['id_group']] = array(
  2449.             'id' => $row['id_group'],
  2450.             'name' => '',
  2451.             'member_count' => $row['num_members'],
  2452.         );
  2453.     }
  2454.     $smcFunc['db_free_result']($request);
  2455.  
  2456.     // Now get the membergroup names.
  2457.     $request = $smcFunc['db_query']('', '
  2458.         SELECT id_group, group_name
  2459.         FROM {db_prefix}membergroups
  2460.         WHERE id_group IN ({array_int:group_list})',
  2461.         array(
  2462.             'group_list' => $groups,
  2463.         )
  2464.     );
  2465.     while ($row = $smcFunc['db_fetch_assoc']($request))
  2466.         $context['groups'][$row['id_group']]['name'] = $row['group_name'];
  2467.     $smcFunc['db_free_result']($request);
  2468.  
  2469.     // Get the subject of the topic we're about to announce.
  2470.     $request = $smcFunc['db_query']('', '
  2471.         SELECT m.subject
  2472.         FROM {db_prefix}topics AS t
  2473.             INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)
  2474.         WHERE t.id_topic = {int:current_topic}',
  2475.         array(
  2476.             'current_topic' => $topic,
  2477.         )
  2478.     );
  2479.     list ($context['topic_subject']) = $smcFunc['db_fetch_row']($request);
  2480.     $smcFunc['db_free_result']($request);
  2481.  
  2482.     censorText($context['announce_topic']['subject']);
  2483.  
  2484.     $context['move'] = isset($_REQUEST['move']) ? 1 : 0;
  2485.     $context['go_back'] = isset($_REQUEST['goback']) ? 1 : 0;
  2486.  
  2487.     $context['sub_template'] = 'announce';
  2488. }
  2489.  
  2490. /**
  2491.  * Send the announcement in chunks.
  2492.  *
  2493.  * splits the members to be sent a topic announcement into chunks.
  2494.  * composes notification messages in all languages needed.
  2495.  * does the actual sending of the topic announcements in chunks.
  2496.  * calculates a rough estimate of the percentage items sent.
  2497.  */
  2498. function AnnouncementSend()
  2499. {
  2500.     global $topic, $board, $board_info, $context, $modSettings;
  2501.     global $language, $scripturl, $sourcedir, $smcFunc;
  2502.  
  2503.     checkSession();
  2504.  
  2505.     $context['start'] = empty($_REQUEST['start']) ? 0 : (int) $_REQUEST['start'];
  2506.     $groups = array_merge($board_info['groups'], array(1));
  2507.  
  2508.     if (isset($_POST['membergroups']))
  2509.         $_POST['who'] = explode(',', $_POST['membergroups']);
  2510.  
  2511.     // Check whether at least one membergroup was selected.
  2512.     if (empty($_POST['who']))
  2513.         fatal_lang_error('no_membergroup_selected');
  2514.  
  2515.     // Make sure all membergroups are integers and can access the board of the announcement.
  2516.     foreach ($_POST['who'] as $id => $mg)
  2517.         $_POST['who'][$id] = in_array((int) $mg, $groups) ? (int) $mg : 0;
  2518.  
  2519.     // Get the topic subject and censor it.
  2520.     $request = $smcFunc['db_query']('', '
  2521.         SELECT m.id_msg, m.subject, m.body
  2522.         FROM {db_prefix}topics AS t
  2523.             INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)
  2524.         WHERE t.id_topic = {int:current_topic}',
  2525.         array(
  2526.             'current_topic' => $topic,
  2527.         )
  2528.     );
  2529.     list ($id_msg, $context['topic_subject'], $message) = $smcFunc['db_fetch_row']($request);
  2530.     $smcFunc['db_free_result']($request);
  2531.  
  2532.     censorText($context['topic_subject']);
  2533.     censorText($message);
  2534.  
  2535.     $message = trim(un_htmlspecialchars(strip_tags(strtr(parse_bbc($message, false, $id_msg), array('<br>' => "\n", '</div>' => "\n", '</li>' => "\n", '&#91;' => '[', '&#93;' => ']')))));
  2536.  
  2537.     // We need this in order to be able send emails.
  2538.     require_once($sourcedir . '/Subs-Post.php');
  2539.  
  2540.     // Select the email addresses for this batch.
  2541.     $request = $smcFunc['db_query']('', '
  2542.         SELECT mem.id_member, mem.email_address, mem.lngfile
  2543.         FROM {db_prefix}members AS mem
  2544.         WHERE (mem.id_group IN ({array_int:group_list}) OR mem.id_post_group IN ({array_int:group_list}) OR FIND_IN_SET({raw:additional_group_list}, mem.additional_groups) != 0)
  2545.             AND mem.is_activated = {int:is_activated}
  2546.             AND mem.id_member > {int:start}
  2547.         ORDER BY mem.id_member
  2548.         LIMIT {int:chunk_size}',
  2549.         array(
  2550.             'group_list' => $_POST['who'],
  2551.             'is_activated' => 1,
  2552.             'start' => $context['start'],
  2553.             'additional_group_list' => implode(', mem.additional_groups) != 0 OR FIND_IN_SET(', $_POST['who']),
  2554.             // @todo Might need an interface?
  2555.             'chunk_size' => 500,
  2556.         )
  2557.     );
  2558.  
  2559.     // All members have received a mail. Go to the next screen.
  2560.     if ($smcFunc['db_num_rows']($request) == 0)
  2561.     {
  2562.         logAction('announce_topic', array('topic' => $topic), 'user');
  2563.         if (!empty($_REQUEST['move']) && allowedTo('move_any'))
  2564.             redirectexit('action=movetopic;topic=' . $topic . '.0' . (empty($_REQUEST['goback']) ? '' : ';goback'));
  2565.         elseif (!empty($_REQUEST['goback']))
  2566.             redirectexit('topic=' . $topic . '.new;boardseen#new', isBrowser('ie'));
  2567.         else
  2568.             redirectexit('board=' . $board . '.0');
  2569.     }
  2570.  
  2571.     $announcements = array();
  2572.     // Loop through all members that'll receive an announcement in this batch.
  2573.     $rows = array();
  2574.     while ($row = $smcFunc['db_fetch_assoc']($request))
  2575.     {
  2576.         $rows[$row['id_member']] = $row;
  2577.     }
  2578.     $smcFunc['db_free_result']($request);
  2579.  
  2580.     // Load their alert preferences
  2581.     require_once($sourcedir . '/Subs-Notify.php');
  2582.     $prefs = getNotifyPrefs(array_keys($rows), 'announcements', true);
  2583.  
  2584.     foreach ($rows as $row)
  2585.     {
  2586.         // Force them to have it?
  2587.         if (empty($prefs[$row['id_member']]['announcements']))
  2588.             continue;
  2589.  
  2590.         $cur_language = empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile'];
  2591.  
  2592.         // If the language wasn't defined yet, load it and compose a notification message.
  2593.         if (!isset($announcements[$cur_language]))
  2594.         {
  2595.             $replacements = array(
  2596.                 'TOPICSUBJECT' => $context['topic_subject'],
  2597.                 'MESSAGE' => $message,
  2598.                 'TOPICLINK' => $scripturl . '?topic=' . $topic . '.0',
  2599.             );
  2600.  
  2601.             $emaildata = loadEmailTemplate('new_announcement', $replacements, $cur_language);
  2602.  
  2603.             $announcements[$cur_language] = array(
  2604.                 'subject' => $emaildata['subject'],
  2605.                 'body' => $emaildata['body'],
  2606.                 'is_html' => $emaildata['is_html'],
  2607.                 'recipients' => array(),
  2608.             );
  2609.         }
  2610.  
  2611.         $announcements[$cur_language]['recipients'][$row['id_member']] = $row['email_address'];
  2612.         $context['start'] = $row['id_member'];
  2613.     }
  2614.  
  2615.     // For each language send a different mail - low priority...
  2616.     foreach ($announcements as $lang => $mail)
  2617.         sendmail($mail['recipients'], $mail['subject'], $mail['body'], null, 'ann-' . $lang, $mail['is_html'], 5);
  2618.  
  2619.     $context['percentage_done'] = round(100 * $context['start'] / $modSettings['latestMember'], 1);
  2620.  
  2621.     $context['move'] = empty($_REQUEST['move']) ? 0 : 1;
  2622.     $context['go_back'] = empty($_REQUEST['goback']) ? 0 : 1;
  2623.     $context['membergroups'] = implode(',', $_POST['who']);
  2624.     $context['sub_template'] = 'announcement_send';
  2625.  
  2626.     // Go back to the correct language for the user ;).
  2627.     if (!empty($modSettings['userLanguage']))
  2628.         loadLanguage('Post');
  2629. }
  2630.  
  2631. /**
  2632.  * Get the topic for display purposes.
  2633.  *
  2634.  * gets a summary of the most recent posts in a topic.
  2635.  * depends on the topicSummaryPosts setting.
  2636.  * if you are editing a post, only shows posts previous to that post.
  2637.  */
  2638. function getTopic()
  2639. {
  2640.     global $topic, $modSettings, $context, $smcFunc, $counter, $options;
  2641.  
  2642.     if (isset($_REQUEST['xml']))
  2643.         $limit = '
  2644.         LIMIT ' . (empty($context['new_replies']) ? '0' : $context['new_replies']);
  2645.     else
  2646.         $limit = empty($modSettings['topicSummaryPosts']) ? '' : '
  2647.         LIMIT ' . (int) $modSettings['topicSummaryPosts'];
  2648.  
  2649.     // If you're modifying, get only those posts before the current one. (otherwise get all.)
  2650.     $request = $smcFunc['db_query']('', '
  2651.         SELECT
  2652.             COALESCE(mem.real_name, m.poster_name) AS poster_name, m.poster_time,
  2653.             m.body, m.smileys_enabled, m.id_msg, m.id_member
  2654.         FROM {db_prefix}messages AS m
  2655.             LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
  2656.         WHERE m.id_topic = {int:current_topic}' . (isset($_REQUEST['msg']) ? '
  2657.             AND m.id_msg < {int:id_msg}' : '') . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
  2658.             AND m.approved = {int:approved}') . '
  2659.         ORDER BY m.id_msg DESC' . $limit,
  2660.         array(
  2661.             'current_topic' => $topic,
  2662.             'id_msg' => isset($_REQUEST['msg']) ? (int) $_REQUEST['msg'] : 0,
  2663.             'approved' => 1,
  2664.         )
  2665.     );
  2666.     $context['previous_posts'] = array();
  2667.     while ($row = $smcFunc['db_fetch_assoc']($request))
  2668.     {
  2669.         // Censor, BBC, ...
  2670.         censorText($row['body']);
  2671.         $row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']);
  2672.  
  2673.         // ...and store.
  2674.         $context['previous_posts'][] = array(
  2675.             'counter' => $counter++,
  2676.             'poster' => $row['poster_name'],
  2677.             'message' => $row['body'],
  2678.             'time' => timeformat($row['poster_time']),
  2679.             'timestamp' => forum_time(true, $row['poster_time']),
  2680.             'id' => $row['id_msg'],
  2681.             'is_new' => !empty($context['new_replies']),
  2682.             'is_ignored' => !empty($modSettings['enable_buddylist']) && !empty($options['posts_apply_ignore_list']) && in_array($row['id_member'], $context['user']['ignoreusers']),
  2683.         );
  2684.  
  2685.         if (!empty($context['new_replies']))
  2686.             $context['new_replies']--;
  2687.     }
  2688.     $smcFunc['db_free_result']($request);
  2689. }
  2690.  
  2691. /**
  2692.  * Loads a post an inserts it into the current editing text box.
  2693.  * uses the Post language file.
  2694.  * uses special (sadly browser dependent) javascript to parse entities for internationalization reasons.
  2695.  * accessed with ?action=quotefast.
  2696.  */
  2697. function QuoteFast()
  2698. {
  2699.     global $modSettings, $user_info, $context;
  2700.     global $sourcedir, $smcFunc;
  2701.  
  2702.     loadLanguage('Post');
  2703.     if (!isset($_REQUEST['xml']))
  2704.         loadTemplate('Post');
  2705.  
  2706.     include_once($sourcedir . '/Subs-Post.php');
  2707.  
  2708.     $moderate_boards = boardsAllowedTo('moderate_board');
  2709.  
  2710.     // Where we going if we need to?
  2711.     $context['post_box_name'] = isset($_GET['pb']) ? $_GET['pb'] : '';
  2712.  
  2713.     $request = $smcFunc['db_query']('', '
  2714.         SELECT COALESCE(mem.real_name, m.poster_name) AS poster_name, m.poster_time, m.body, m.id_topic, m.subject,
  2715.             m.id_board, m.id_member, m.approved, m.modified_time, m.modified_name, m.modified_reason
  2716.         FROM {db_prefix}messages AS m
  2717.             INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)
  2718.             INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board AND {query_see_board})
  2719.             LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
  2720.         WHERE m.id_msg = {int:id_msg}' . (isset($_REQUEST['modify']) || (!empty($moderate_boards) && $moderate_boards[0] == 0) ? '' : '
  2721.             AND (t.locked = {int:not_locked}' . (empty($moderate_boards) ? '' : ' OR b.id_board IN ({array_int:moderation_board_list})') . ')') . '
  2722.         LIMIT 1',
  2723.         array(
  2724.             'current_member' => $user_info['id'],
  2725.             'moderation_board_list' => $moderate_boards,
  2726.             'id_msg' => (int) $_REQUEST['quote'],
  2727.             'not_locked' => 0,
  2728.         )
  2729.     );
  2730.     $context['close_window'] = $smcFunc['db_num_rows']($request) == 0;
  2731.     $row = $smcFunc['db_fetch_assoc']($request);
  2732.     $smcFunc['db_free_result']($request);
  2733.  
  2734.     $context['sub_template'] = 'quotefast';
  2735.     if (!empty($row))
  2736.         $can_view_post = $row['approved'] || ($row['id_member'] != 0 && $row['id_member'] == $user_info['id']) || allowedTo('approve_posts', $row['id_board']);
  2737.  
  2738.     if (!empty($can_view_post))
  2739.     {
  2740.         // Remove special formatting we don't want anymore.
  2741.         $row['body'] = un_preparsecode($row['body']);
  2742.  
  2743.         // Censor the message!
  2744.         censorText($row['body']);
  2745.  
  2746.         // Want to modify a single message by double clicking it?
  2747.         if (isset($_REQUEST['modify']))
  2748.         {
  2749.             censorText($row['subject']);
  2750.  
  2751.             $context['sub_template'] = 'modifyfast';
  2752.             $context['message'] = array(
  2753.                 'id' => $_REQUEST['quote'],
  2754.                 'body' => $row['body'],
  2755.                 'subject' => addcslashes($row['subject'], '"'),
  2756.                 'reason' => array(
  2757.                     'name' => $row['modified_name'],
  2758.                     'text' => $row['modified_reason'],
  2759.                     'time' => $row['modified_time'],
  2760.                 ),
  2761.             );
  2762.  
  2763.             return;
  2764.         }
  2765.  
  2766.         // Remove any nested quotes.
  2767.         if (!empty($modSettings['removeNestedQuotes']))
  2768.             $row['body'] = preg_replace(array('~\n?\[quote.*?\].+?\[/quote\]\n?~is', '~^\n~', '~\[/quote\]~'), '', $row['body']);
  2769.  
  2770.         $lb = "\n";
  2771.  
  2772.         // Add a quote string on the front and end.
  2773.         $context['quote']['xml'] = '[quote author=' . $row['poster_name'] . ' link=msg=' . (int) $_REQUEST['quote'] . ' date=' . $row['poster_time'] . ']' . $lb . $row['body'] . $lb . '[/quote]';
  2774.         $context['quote']['text'] = strtr(un_htmlspecialchars($context['quote']['xml']), array('\'' => '\\\'', '\\' => '\\\\', "\n" => '\\n', '</script>' => '</\' + \'script>'));
  2775.         $context['quote']['xml'] = strtr($context['quote']['xml'], array('&nbsp;' => '&#160;', '<' => '&lt;', '>' => '&gt;'));
  2776.  
  2777.         $context['quote']['mozilla'] = strtr($smcFunc['htmlspecialchars']($context['quote']['text']), array('&quot;' => '"'));
  2778.     }
  2779.     //@todo Needs a nicer interface.
  2780.     // In case our message has been removed in the meantime.
  2781.     elseif (isset($_REQUEST['modify']))
  2782.     {
  2783.         $context['sub_template'] = 'modifyfast';
  2784.         $context['message'] = array(
  2785.             'id' => 0,
  2786.             'body' => '',
  2787.             'subject' => '',
  2788.             'reason' => array(
  2789.                 'name' => '',
  2790.                 'text' => '',
  2791.                 'time' => '',
  2792.             ),
  2793.         );
  2794.     }
  2795.     else
  2796.         $context['quote'] = array(
  2797.             'xml' => '',
  2798.             'mozilla' => '',
  2799.             'text' => '',
  2800.         );
  2801. }
  2802.  
  2803. /**
  2804.  * Used to edit the body or subject of a message inline
  2805.  * called from action=jsmodify from script and topic js
  2806.  */
  2807. function JavaScriptModify()
  2808. {
  2809.     global $sourcedir, $modSettings, $board, $topic, $txt;
  2810.     global $user_info, $context, $smcFunc, $language, $board_info;
  2811.  
  2812.     // We have to have a topic!
  2813.     if (empty($topic))
  2814.         obExit(false);
  2815.  
  2816.     checkSession('get');
  2817.     require_once($sourcedir . '/Subs-Post.php');
  2818.  
  2819.     // Assume the first message if no message ID was given.
  2820.     $request = $smcFunc['db_query']('', '
  2821.         SELECT
  2822.             t.locked, t.num_replies, t.id_member_started, t.id_first_msg,
  2823.             m.id_msg, m.id_member, m.poster_time, m.subject, m.smileys_enabled, m.body, m.icon,
  2824.             m.modified_time, m.modified_name, m.modified_reason, m.approved,
  2825.             m.poster_name, m.poster_email
  2826.         FROM {db_prefix}messages AS m
  2827.             INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
  2828.         WHERE m.id_msg = {raw:id_msg}
  2829.             AND m.id_topic = {int:current_topic}' . (allowedTo('modify_any') || allowedTo('approve_posts') ? '' : (!$modSettings['postmod_active'] ? '
  2830.             AND (m.id_member != {int:guest_id} AND m.id_member = {int:current_member})' : '
  2831.             AND (m.approved = {int:is_approved} OR (m.id_member != {int:guest_id} AND m.id_member = {int:current_member}))')),
  2832.         array(
  2833.             'current_member' => $user_info['id'],
  2834.             'current_topic' => $topic,
  2835.             'id_msg' => empty($_REQUEST['msg']) ? 't.id_first_msg' : (int) $_REQUEST['msg'],
  2836.             'is_approved' => 1,
  2837.             'guest_id' => 0,
  2838.         )
  2839.     );
  2840.     if ($smcFunc['db_num_rows']($request) == 0)
  2841.         fatal_lang_error('no_board', false);
  2842.     $row = $smcFunc['db_fetch_assoc']($request);
  2843.     $smcFunc['db_free_result']($request);
  2844.  
  2845.     // Change either body or subject requires permissions to modify messages.
  2846.     if (isset($_POST['message']) || isset($_POST['subject']) || isset($_REQUEST['icon']))
  2847.     {
  2848.         if (!empty($row['locked']))
  2849.             isAllowedTo('moderate_board');
  2850.  
  2851.         if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any'))
  2852.         {
  2853.             if ((!$modSettings['postmod_active'] || $row['approved']) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time())
  2854.                 fatal_lang_error('modify_post_time_passed', false);
  2855.             elseif ($row['id_member_started'] == $user_info['id'] && !allowedTo('modify_own'))
  2856.                 isAllowedTo('modify_replies');
  2857.             else
  2858.                 isAllowedTo('modify_own');
  2859.         }
  2860.         // Otherwise, they're locked out; someone who can modify the replies is needed.
  2861.         elseif ($row['id_member_started'] == $user_info['id'] && !allowedTo('modify_any'))
  2862.             isAllowedTo('modify_replies');
  2863.         else
  2864.             isAllowedTo('modify_any');
  2865.  
  2866.         // Only log this action if it wasn't your message.
  2867.         $moderationAction = $row['id_member'] != $user_info['id'];
  2868.     }
  2869.  
  2870.     $post_errors = array();
  2871.     if (isset($_POST['subject']) && $smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['subject'])) !== '')
  2872.     {
  2873.         $_POST['subject'] = strtr($smcFunc['htmlspecialchars']($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
  2874.  
  2875.         // Maximum number of characters.
  2876.         if ($smcFunc['strlen']($_POST['subject']) > 100)
  2877.             $_POST['subject'] = $smcFunc['substr']($_POST['subject'], 0, 100);
  2878.     }
  2879.     elseif (isset($_POST['subject']))
  2880.     {
  2881.         $post_errors[] = 'no_subject';
  2882.         unset($_POST['subject']);
  2883.     }
  2884.  
  2885.     if (isset($_POST['message']))
  2886.     {
  2887.         if ($smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['message'])) === '')
  2888.         {
  2889.             $post_errors[] = 'no_message';
  2890.             unset($_POST['message']);
  2891.         }
  2892.         elseif (!empty($modSettings['max_messageLength']) && $smcFunc['strlen']($_POST['message']) > $modSettings['max_messageLength'])
  2893.         {
  2894.             $post_errors[] = 'long_message';
  2895.             unset($_POST['message']);
  2896.         }
  2897.         else
  2898.         {
  2899.             $_POST['message'] = $smcFunc['htmlspecialchars']($_POST['message'], ENT_QUOTES);
  2900.  
  2901.             preparsecode($_POST['message']);
  2902.  
  2903.             if ($smcFunc['htmltrim'](strip_tags(parse_bbc($_POST['message'], false), implode('', $context['allowed_html_tags']))) === '')
  2904.             {
  2905.                 $post_errors[] = 'no_message';
  2906.                 unset($_POST['message']);
  2907.             }
  2908.         }
  2909.     }
  2910.  
  2911.     if (isset($_POST['lock']))
  2912.     {
  2913.         if (!allowedTo(array('lock_any', 'lock_own')) || (!allowedTo('lock_any') && $user_info['id'] != $row['id_member']))
  2914.             unset($_POST['lock']);
  2915.         elseif (!allowedTo('lock_any'))
  2916.         {
  2917.             if ($row['locked'] == 1)
  2918.                 unset($_POST['lock']);
  2919.             else
  2920.                 $_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
  2921.         }
  2922.         elseif (!empty($row['locked']) && !empty($_POST['lock']) || $_POST['lock'] == $row['locked'])
  2923.             unset($_POST['lock']);
  2924.         else
  2925.             $_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
  2926.     }
  2927.  
  2928.     if (isset($_POST['sticky']) && !allowedTo('make_sticky'))
  2929.         unset($_POST['sticky']);
  2930.  
  2931.     if (isset($_POST['modify_reason']))
  2932.     {
  2933.         $_POST['modify_reason'] = strtr($smcFunc['htmlspecialchars']($_POST['modify_reason']), array("\r" => '', "\n" => '', "\t" => ''));
  2934.  
  2935.         // Maximum number of characters.
  2936.         if ($smcFunc['strlen']($_POST['modify_reason']) > 100)
  2937.             $_POST['modify_reason'] = $smcFunc['substr']($_POST['modify_reason'], 0, 100);
  2938.     }
  2939.  
  2940.     if (empty($post_errors))
  2941.     {
  2942.         $msgOptions = array(
  2943.             'id' => $row['id_msg'],
  2944.             'subject' => isset($_POST['subject']) ? $_POST['subject'] : null,
  2945.             'body' => isset($_POST['message']) ? $_POST['message'] : null,
  2946.             'icon' => isset($_REQUEST['icon']) ? preg_replace('~[\./\\\\*\':"<>]~', '', $_REQUEST['icon']) : null,
  2947.             'modify_reason' => (isset($_POST['modify_reason']) ? $_POST['modify_reason'] : ''),
  2948.         );
  2949.         $topicOptions = array(
  2950.             'id' => $topic,
  2951.             'board' => $board,
  2952.             'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null,
  2953.             'sticky_mode' => isset($_POST['sticky']) ? (int) $_POST['sticky'] : null,
  2954.             'mark_as_read' => true,
  2955.         );
  2956.         $posterOptions = array(
  2957.             'id' => $user_info['id'],
  2958.             'name' => $row['poster_name'],
  2959.             'email' => $row['poster_email'],
  2960.             'update_post_count' => !$user_info['is_guest'] && !isset($_REQUEST['msg']) && $board_info['posts_count'],
  2961.         );
  2962.  
  2963.         // Only consider marking as editing if they have edited the subject, message or icon.
  2964.         if ((isset($_POST['subject']) && $_POST['subject'] != $row['subject']) || (isset($_POST['message']) && $_POST['message'] != $row['body']) || (isset($_REQUEST['icon']) && $_REQUEST['icon'] != $row['icon']))
  2965.         {
  2966.             // And even then only if the time has passed...
  2967.             if (time() - $row['poster_time'] > $modSettings['edit_wait_time'] || $user_info['id'] != $row['id_member'])
  2968.             {
  2969.                 $msgOptions['modify_time'] = time();
  2970.                 $msgOptions['modify_name'] = $user_info['name'];
  2971.             }
  2972.         }
  2973.         // If nothing was changed there's no need to add an entry to the moderation log.
  2974.         else
  2975.             $moderationAction = false;
  2976.  
  2977.         modifyPost($msgOptions, $topicOptions, $posterOptions);
  2978.  
  2979.         // If we didn't change anything this time but had before put back the old info.
  2980.         if (!isset($msgOptions['modify_time']) && !empty($row['modified_time']))
  2981.         {
  2982.             $msgOptions['modify_time'] = $row['modified_time'];
  2983.             $msgOptions['modify_name'] = $row['modified_name'];
  2984.             $msgOptions['modify_reason'] = $row['modified_reason'];
  2985.         }
  2986.  
  2987.         // Changing the first subject updates other subjects to 'Re: new_subject'.
  2988.         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'))))
  2989.         {
  2990.             // Get the proper (default language) response prefix first.
  2991.             if (!isset($context['response_prefix']) && !($context['response_prefix'] = cache_get_data('response_prefix')))
  2992.             {
  2993.                 if ($language === $user_info['language'])
  2994.                     $context['response_prefix'] = $txt['response_prefix'];
  2995.                 else
  2996.                 {
  2997.                     loadLanguage('index', $language, false);
  2998.                     $context['response_prefix'] = $txt['response_prefix'];
  2999.                     loadLanguage('index');
  3000.                 }
  3001.                 cache_put_data('response_prefix', $context['response_prefix'], 600);
  3002.             }
  3003.  
  3004.             $smcFunc['db_query']('', '
  3005.                 UPDATE {db_prefix}messages
  3006.                 SET subject = {string:subject}
  3007.                 WHERE id_topic = {int:current_topic}
  3008.                     AND id_msg != {int:id_first_msg}',
  3009.                 array(
  3010.                     'current_topic' => $topic,
  3011.                     'id_first_msg' => $row['id_first_msg'],
  3012.                     'subject' => $context['response_prefix'] . $_POST['subject'],
  3013.                 )
  3014.             );
  3015.         }
  3016.  
  3017.         if (!empty($moderationAction))
  3018.             logAction('modify', array('topic' => $topic, 'message' => $row['id_msg'], 'member' => $row['id_member'], 'board' => $board));
  3019.     }
  3020.  
  3021.     if (isset($_REQUEST['xml']))
  3022.     {
  3023.         $context['sub_template'] = 'modifydone';
  3024.         if (empty($post_errors) && isset($msgOptions['subject']) && isset($msgOptions['body']))
  3025.         {
  3026.             $context['message'] = array(
  3027.                 'id' => $row['id_msg'],
  3028.                 'modified' => array(
  3029.                     'time' => isset($msgOptions['modify_time']) ? timeformat($msgOptions['modify_time']) : '',
  3030.                     'timestamp' => isset($msgOptions['modify_time']) ? forum_time(true, $msgOptions['modify_time']) : 0,
  3031.                     'name' => isset($msgOptions['modify_time']) ? $msgOptions['modify_name'] : '',
  3032.                     'reason' => $msgOptions['modify_reason'],
  3033.                 ),
  3034.                 'subject' => $msgOptions['subject'],
  3035.                 'first_in_topic' => $row['id_msg'] == $row['id_first_msg'],
  3036.                 'body' => strtr($msgOptions['body'], array(']]>' => ']]]]><![CDATA[>')),
  3037.             );
  3038.  
  3039.             censorText($context['message']['subject']);
  3040.             censorText($context['message']['body']);
  3041.  
  3042.             $context['message']['body'] = parse_bbc($context['message']['body'], $row['smileys_enabled'], $row['id_msg']);
  3043.         }
  3044.         // Topic?
  3045.         elseif (empty($post_errors))
  3046.         {
  3047.             $context['sub_template'] = 'modifytopicdone';
  3048.             $context['message'] = array(
  3049.                 'id' => $row['id_msg'],
  3050.                 'modified' => array(
  3051.                     'time' => isset($msgOptions['modify_time']) ? timeformat($msgOptions['modify_time']) : '',
  3052.                     'timestamp' => isset($msgOptions['modify_time']) ? forum_time(true, $msgOptions['modify_time']) : 0,
  3053.                     'name' => isset($msgOptions['modify_time']) ? $msgOptions['modify_name'] : '',
  3054.                 ),
  3055.                 'subject' => isset($msgOptions['subject']) ? $msgOptions['subject'] : '',
  3056.             );
  3057.  
  3058.             censorText($context['message']['subject']);
  3059.         }
  3060.         else
  3061.         {
  3062.             $context['message'] = array(
  3063.                 'id' => $row['id_msg'],
  3064.                 'errors' => array(),
  3065.                 'error_in_subject' => in_array('no_subject', $post_errors),
  3066.                 'error_in_body' => in_array('no_message', $post_errors) || in_array('long_message', $post_errors),
  3067.             );
  3068.  
  3069.             loadLanguage('Errors');
  3070.             foreach ($post_errors as $post_error)
  3071.             {
  3072.                 if ($post_error == 'long_message')
  3073.                     $context['message']['errors'][] = sprintf($txt['error_' . $post_error], $modSettings['max_messageLength']);
  3074.                 else
  3075.                     $context['message']['errors'][] = $txt['error_' . $post_error];
  3076.             }
  3077.         }
  3078.     }
  3079.     else
  3080.         obExit(false);
  3081. }
  3082.  
  3083. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement