Advertisement
Guest User

Working 2.1 beta 3 version of post.php

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