PageRenderTime 62ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/php/Sources/Post.php

https://github.com/dekoza/openshift-smf-2.0.7
PHP | 2894 lines | 2160 code | 381 blank | 353 comment | 656 complexity | 44f251ac3da3176cfb7752a5429b6936 MD5 | raw file
Possible License(s): BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * Simple Machines Forum (SMF)
  4. *
  5. * @package SMF
  6. * @author Simple Machines http://www.simplemachines.org
  7. * @copyright 2011 Simple Machines
  8. * @license http://www.simplemachines.org/about/smf/license.php BSD
  9. *
  10. * @version 2.0.7
  11. */
  12. if (!defined('SMF'))
  13. die('Hacking attempt...');
  14. /* The job of this file is to handle everything related to posting replies,
  15. new topics, quotes, and modifications to existing posts. It also handles
  16. quoting posts by way of javascript.
  17. void Post()
  18. - handles showing the post screen, loading the post to be modified, and
  19. loading any post quoted.
  20. - additionally handles previews of posts.
  21. - uses the Post template and language file, main sub template.
  22. - allows wireless access using the protocol_post sub template.
  23. - requires different permissions depending on the actions, but most
  24. notably post_new, post_reply_own, and post_reply_any.
  25. - shows options for the editing and posting of calendar events and
  26. attachments, as well as the posting of polls.
  27. - accessed from ?action=post.
  28. void Post2()
  29. - actually posts or saves the message composed with Post().
  30. - requires various permissions depending on the action.
  31. - handles attachment, post, and calendar saving.
  32. - sends off notifications, and allows for announcements and moderation.
  33. - accessed from ?action=post2.
  34. void AnnounceTopic()
  35. - handle the announce topic function (action=announce).
  36. - checks the topic announcement permissions and loads the announcement
  37. template.
  38. - requires the announce_topic permission.
  39. - uses the ManageMembers template and Post language file.
  40. - call the right function based on the sub-action.
  41. void AnnouncementSelectMembergroup()
  42. - lets the user select the membergroups that will receive the topic
  43. announcement.
  44. void AnnouncementSend()
  45. - splits the members to be sent a topic announcement into chunks.
  46. - composes notification messages in all languages needed.
  47. - does the actual sending of the topic announcements in chunks.
  48. - calculates a rough estimate of the percentage items sent.
  49. void notifyMembersBoard(notifyData)
  50. - notifies members who have requested notification for new topics
  51. posted on a board of said posts.
  52. - receives data on the topics to send out notifications to by the passed in array.
  53. - only sends notifications to those who can *currently* see the topic
  54. (it doesn't matter if they could when they requested notification.)
  55. - loads the Post language file multiple times for each language if the
  56. userLanguage setting is set.
  57. void getTopic()
  58. - gets a summary of the most recent posts in a topic.
  59. - depends on the topicSummaryPosts setting.
  60. - if you are editing a post, only shows posts previous to that post.
  61. void QuoteFast()
  62. - loads a post an inserts it into the current editing text box.
  63. - uses the Post language file.
  64. - uses special (sadly browser dependent) javascript to parse entities
  65. for internationalization reasons.
  66. - accessed with ?action=quotefast.
  67. void JavaScriptModify()
  68. // !!!
  69. */
  70. function Post()
  71. {
  72. global $txt, $scripturl, $topic, $modSettings, $board;
  73. global $user_info, $sc, $board_info, $context, $settings;
  74. global $sourcedir, $options, $smcFunc, $language;
  75. loadLanguage('Post');
  76. // You can't reply with a poll... hacker.
  77. if (isset($_REQUEST['poll']) && !empty($topic) && !isset($_REQUEST['msg']))
  78. unset($_REQUEST['poll']);
  79. // Posting an event?
  80. $context['make_event'] = isset($_REQUEST['calendar']);
  81. $context['robot_no_index'] = true;
  82. // You must be posting to *some* board.
  83. if (empty($board) && !$context['make_event'])
  84. fatal_lang_error('no_board', false);
  85. require_once($sourcedir . '/Subs-Post.php');
  86. if (isset($_REQUEST['xml']))
  87. {
  88. $context['sub_template'] = 'post';
  89. // Just in case of an earlier error...
  90. $context['preview_message'] = '';
  91. $context['preview_subject'] = '';
  92. }
  93. // No message is complete without a topic.
  94. if (empty($topic) && !empty($_REQUEST['msg']))
  95. {
  96. $request = $smcFunc['db_query']('', '
  97. SELECT id_topic
  98. FROM {db_prefix}messages
  99. WHERE id_msg = {int:msg}',
  100. array(
  101. 'msg' => (int) $_REQUEST['msg'],
  102. ));
  103. if ($smcFunc['db_num_rows']($request) != 1)
  104. unset($_REQUEST['msg'], $_POST['msg'], $_GET['msg']);
  105. else
  106. list ($topic) = $smcFunc['db_fetch_row']($request);
  107. $smcFunc['db_free_result']($request);
  108. }
  109. // Check if it's locked. It isn't locked if no topic is specified.
  110. if (!empty($topic))
  111. {
  112. $request = $smcFunc['db_query']('', '
  113. SELECT
  114. t.locked, IFNULL(ln.id_topic, 0) AS notify, t.is_sticky, t.id_poll, t.id_last_msg, mf.id_member,
  115. t.id_first_msg, mf.subject,
  116. CASE WHEN ml.poster_time > ml.modified_time THEN ml.poster_time ELSE ml.modified_time END AS last_post_time
  117. FROM {db_prefix}topics AS t
  118. LEFT JOIN {db_prefix}log_notify AS ln ON (ln.id_topic = t.id_topic AND ln.id_member = {int:current_member})
  119. LEFT JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg)
  120. LEFT JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
  121. WHERE t.id_topic = {int:current_topic}
  122. LIMIT 1',
  123. array(
  124. 'current_member' => $user_info['id'],
  125. 'current_topic' => $topic,
  126. )
  127. );
  128. list ($locked, $context['notify'], $sticky, $pollID, $context['topic_last_message'], $id_member_poster, $id_first_msg, $first_subject, $lastPostTime) = $smcFunc['db_fetch_row']($request);
  129. $smcFunc['db_free_result']($request);
  130. // If this topic already has a poll, they sure can't add another.
  131. if (isset($_REQUEST['poll']) && $pollID > 0)
  132. unset($_REQUEST['poll']);
  133. if (empty($_REQUEST['msg']))
  134. {
  135. if ($user_info['is_guest'] && !allowedTo('post_reply_any') && (!$modSettings['postmod_active'] || !allowedTo('post_unapproved_replies_any')))
  136. is_not_guest();
  137. // By default the reply will be approved...
  138. $context['becomes_approved'] = true;
  139. if ($id_member_poster != $user_info['id'])
  140. {
  141. if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_any') && !allowedTo('post_reply_any'))
  142. $context['becomes_approved'] = false;
  143. else
  144. isAllowedTo('post_reply_any');
  145. }
  146. elseif (!allowedTo('post_reply_any'))
  147. {
  148. if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_own') && !allowedTo('post_reply_own'))
  149. $context['becomes_approved'] = false;
  150. else
  151. isAllowedTo('post_reply_own');
  152. }
  153. }
  154. else
  155. $context['becomes_approved'] = true;
  156. $context['can_lock'] = allowedTo('lock_any') || ($user_info['id'] == $id_member_poster && allowedTo('lock_own'));
  157. $context['can_sticky'] = allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']);
  158. $context['notify'] = !empty($context['notify']);
  159. $context['sticky'] = isset($_REQUEST['sticky']) ? !empty($_REQUEST['sticky']) : $sticky;
  160. }
  161. else
  162. {
  163. $context['becomes_approved'] = true;
  164. if ((!$context['make_event'] || !empty($board)))
  165. {
  166. if ($modSettings['postmod_active'] && !allowedTo('post_new') && allowedTo('post_unapproved_topics'))
  167. $context['becomes_approved'] = false;
  168. else
  169. isAllowedTo('post_new');
  170. }
  171. $locked = 0;
  172. // !!! These won't work if you're making an event.
  173. $context['can_lock'] = allowedTo(array('lock_any', 'lock_own'));
  174. $context['can_sticky'] = allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']);
  175. $context['notify'] = !empty($context['notify']);
  176. $context['sticky'] = !empty($_REQUEST['sticky']);
  177. }
  178. // !!! These won't work if you're posting an event!
  179. $context['can_notify'] = allowedTo('mark_any_notify');
  180. $context['can_move'] = allowedTo('move_any');
  181. $context['move'] = !empty($_REQUEST['move']);
  182. $context['announce'] = !empty($_REQUEST['announce']);
  183. // You can only announce topics that will get approved...
  184. $context['can_announce'] = allowedTo('announce_topic') && $context['becomes_approved'];
  185. $context['locked'] = !empty($locked) || !empty($_REQUEST['lock']);
  186. $context['can_quote'] = empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC']));
  187. // Generally don't show the approval box... (Assume we want things approved)
  188. $context['show_approval'] = false;
  189. // An array to hold all the attachments for this topic.
  190. $context['current_attachments'] = array();
  191. // Don't allow a post if it's locked and you aren't all powerful.
  192. if ($locked && !allowedTo('moderate_board'))
  193. fatal_lang_error('topic_locked', false);
  194. // Check the users permissions - is the user allowed to add or post a poll?
  195. if (isset($_REQUEST['poll']) && $modSettings['pollMode'] == '1')
  196. {
  197. // New topic, new poll.
  198. if (empty($topic))
  199. isAllowedTo('poll_post');
  200. // This is an old topic - but it is yours! Can you add to it?
  201. elseif ($user_info['id'] == $id_member_poster && !allowedTo('poll_add_any'))
  202. isAllowedTo('poll_add_own');
  203. // If you're not the owner, can you add to any poll?
  204. else
  205. isAllowedTo('poll_add_any');
  206. require_once($sourcedir . '/Subs-Members.php');
  207. $allowedVoteGroups = groupsAllowedTo('poll_vote', $board);
  208. // Set up the poll options.
  209. $context['poll_options'] = array(
  210. 'max_votes' => empty($_POST['poll_max_votes']) ? '1' : max(1, $_POST['poll_max_votes']),
  211. 'hide' => empty($_POST['poll_hide']) ? 0 : $_POST['poll_hide'],
  212. 'expire' => !isset($_POST['poll_expire']) ? '' : $_POST['poll_expire'],
  213. 'change_vote' => isset($_POST['poll_change_vote']),
  214. 'guest_vote' => isset($_POST['poll_guest_vote']),
  215. 'guest_vote_enabled' => in_array(-1, $allowedVoteGroups['allowed']),
  216. );
  217. // Make all five poll choices empty.
  218. $context['choices'] = array(
  219. array('id' => 0, 'number' => 1, 'label' => '', 'is_last' => false),
  220. array('id' => 1, 'number' => 2, 'label' => '', 'is_last' => false),
  221. array('id' => 2, 'number' => 3, 'label' => '', 'is_last' => false),
  222. array('id' => 3, 'number' => 4, 'label' => '', 'is_last' => false),
  223. array('id' => 4, 'number' => 5, 'label' => '', 'is_last' => true)
  224. );
  225. }
  226. if ($context['make_event'])
  227. {
  228. // They might want to pick a board.
  229. if (!isset($context['current_board']))
  230. $context['current_board'] = 0;
  231. // Start loading up the event info.
  232. $context['event'] = array();
  233. $context['event']['title'] = isset($_REQUEST['evtitle']) ? htmlspecialchars(stripslashes($_REQUEST['evtitle'])) : '';
  234. $context['event']['id'] = isset($_REQUEST['eventid']) ? (int) $_REQUEST['eventid'] : -1;
  235. $context['event']['new'] = $context['event']['id'] == -1;
  236. // Permissions check!
  237. isAllowedTo('calendar_post');
  238. // Editing an event? (but NOT previewing!?)
  239. if (!$context['event']['new'] && !isset($_REQUEST['subject']))
  240. {
  241. // If the user doesn't have permission to edit the post in this topic, redirect them.
  242. if ((empty($id_member_poster) || $id_member_poster != $user_info['id'] || !allowedTo('modify_own')) && !allowedTo('modify_any'))
  243. {
  244. require_once($sourcedir . '/Calendar.php');
  245. return CalendarPost();
  246. }
  247. // Get the current event information.
  248. $request = $smcFunc['db_query']('', '
  249. SELECT
  250. id_member, title, MONTH(start_date) AS month, DAYOFMONTH(start_date) AS day,
  251. YEAR(start_date) AS year, (TO_DAYS(end_date) - TO_DAYS(start_date)) AS span
  252. FROM {db_prefix}calendar
  253. WHERE id_event = {int:id_event}
  254. LIMIT 1',
  255. array(
  256. 'id_event' => $context['event']['id'],
  257. )
  258. );
  259. $row = $smcFunc['db_fetch_assoc']($request);
  260. $smcFunc['db_free_result']($request);
  261. // Make sure the user is allowed to edit this event.
  262. if ($row['id_member'] != $user_info['id'])
  263. isAllowedTo('calendar_edit_any');
  264. elseif (!allowedTo('calendar_edit_any'))
  265. isAllowedTo('calendar_edit_own');
  266. $context['event']['month'] = $row['month'];
  267. $context['event']['day'] = $row['day'];
  268. $context['event']['year'] = $row['year'];
  269. $context['event']['title'] = $row['title'];
  270. $context['event']['span'] = $row['span'] + 1;
  271. }
  272. else
  273. {
  274. $today = getdate();
  275. // You must have a month and year specified!
  276. if (!isset($_REQUEST['month']))
  277. $_REQUEST['month'] = $today['mon'];
  278. if (!isset($_REQUEST['year']))
  279. $_REQUEST['year'] = $today['year'];
  280. $context['event']['month'] = (int) $_REQUEST['month'];
  281. $context['event']['year'] = (int) $_REQUEST['year'];
  282. $context['event']['day'] = isset($_REQUEST['day']) ? $_REQUEST['day'] : ($_REQUEST['month'] == $today['mon'] ? $today['mday'] : 0);
  283. $context['event']['span'] = isset($_REQUEST['span']) ? $_REQUEST['span'] : 1;
  284. // Make sure the year and month are in the valid range.
  285. if ($context['event']['month'] < 1 || $context['event']['month'] > 12)
  286. fatal_lang_error('invalid_month', false);
  287. if ($context['event']['year'] < $modSettings['cal_minyear'] || $context['event']['year'] > $modSettings['cal_maxyear'])
  288. fatal_lang_error('invalid_year', false);
  289. // Get a list of boards they can post in.
  290. $boards = boardsAllowedTo('post_new');
  291. if (empty($boards))
  292. fatal_lang_error('cannot_post_new', 'user');
  293. // Load a list of boards for this event in the context.
  294. require_once($sourcedir . '/Subs-MessageIndex.php');
  295. $boardListOptions = array(
  296. 'included_boards' => in_array(0, $boards) ? null : $boards,
  297. 'not_redirection' => true,
  298. 'use_permissions' => true,
  299. 'selected_board' => empty($context['current_board']) ? $modSettings['cal_defaultboard'] : $context['current_board'],
  300. );
  301. $context['event']['categories'] = getBoardList($boardListOptions);
  302. }
  303. // Find the last day of the month.
  304. $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']));
  305. $context['event']['board'] = !empty($board) ? $board : $modSettings['cal_defaultboard'];
  306. }
  307. if (empty($context['post_errors']))
  308. $context['post_errors'] = array();
  309. // See if any new replies have come along.
  310. if (empty($_REQUEST['msg']) && !empty($topic))
  311. {
  312. if (empty($options['no_new_reply_warning']) && isset($_REQUEST['last_msg']) && $context['topic_last_message'] > $_REQUEST['last_msg'])
  313. {
  314. $request = $smcFunc['db_query']('', '
  315. SELECT COUNT(*)
  316. FROM {db_prefix}messages
  317. WHERE id_topic = {int:current_topic}
  318. AND id_msg > {int:last_msg}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
  319. AND approved = {int:approved}') . '
  320. LIMIT 1',
  321. array(
  322. 'current_topic' => $topic,
  323. 'last_msg' => (int) $_REQUEST['last_msg'],
  324. 'approved' => 1,
  325. )
  326. );
  327. list ($context['new_replies']) = $smcFunc['db_fetch_row']($request);
  328. $smcFunc['db_free_result']($request);
  329. if (!empty($context['new_replies']))
  330. {
  331. if ($context['new_replies'] == 1)
  332. $txt['error_new_reply'] = isset($_GET['last_msg']) ? $txt['error_new_reply_reading'] : $txt['error_new_reply'];
  333. else
  334. $txt['error_new_replies'] = sprintf(isset($_GET['last_msg']) ? $txt['error_new_replies_reading'] : $txt['error_new_replies'], $context['new_replies']);
  335. // If they've come from the display page then we treat the error differently....
  336. if (isset($_GET['last_msg']))
  337. $newRepliesError = $context['new_replies'];
  338. else
  339. $context['post_error'][$context['new_replies'] == 1 ? 'new_reply' : 'new_replies'] = true;
  340. $modSettings['topicSummaryPosts'] = $context['new_replies'] > $modSettings['topicSummaryPosts'] ? max($modSettings['topicSummaryPosts'], 5) : $modSettings['topicSummaryPosts'];
  341. }
  342. }
  343. // Check whether this is a really old post being bumped...
  344. if (!empty($modSettings['oldTopicDays']) && $lastPostTime + $modSettings['oldTopicDays'] * 86400 < time() && empty($sticky) && !isset($_REQUEST['subject']))
  345. $oldTopicError = true;
  346. }
  347. // Get a response prefix (like 'Re:') in the default forum language.
  348. if (!isset($context['response_prefix']) && !($context['response_prefix'] = cache_get_data('response_prefix')))
  349. {
  350. if ($language === $user_info['language'])
  351. $context['response_prefix'] = $txt['response_prefix'];
  352. else
  353. {
  354. loadLanguage('index', $language, false);
  355. $context['response_prefix'] = $txt['response_prefix'];
  356. loadLanguage('index');
  357. }
  358. cache_put_data('response_prefix', $context['response_prefix'], 600);
  359. }
  360. // Previewing, modifying, or posting?
  361. if (isset($_REQUEST['message']) || !empty($context['post_error']))
  362. {
  363. // Validate inputs.
  364. if (empty($context['post_error']))
  365. {
  366. if (htmltrim__recursive(htmlspecialchars__recursive($_REQUEST['subject'])) == '')
  367. $context['post_error']['no_subject'] = true;
  368. if (htmltrim__recursive(htmlspecialchars__recursive($_REQUEST['message'])) == '')
  369. $context['post_error']['no_message'] = true;
  370. if (!empty($modSettings['max_messageLength']) && $smcFunc['strlen']($_REQUEST['message']) > $modSettings['max_messageLength'])
  371. $context['post_error']['long_message'] = true;
  372. // Are you... a guest?
  373. if ($user_info['is_guest'])
  374. {
  375. $_REQUEST['guestname'] = !isset($_REQUEST['guestname']) ? '' : trim($_REQUEST['guestname']);
  376. $_REQUEST['email'] = !isset($_REQUEST['email']) ? '' : trim($_REQUEST['email']);
  377. // Validate the name and email.
  378. if (!isset($_REQUEST['guestname']) || trim(strtr($_REQUEST['guestname'], '_', ' ')) == '')
  379. $context['post_error']['no_name'] = true;
  380. elseif ($smcFunc['strlen']($_REQUEST['guestname']) > 25)
  381. $context['post_error']['long_name'] = true;
  382. else
  383. {
  384. require_once($sourcedir . '/Subs-Members.php');
  385. if (isReservedName(htmlspecialchars($_REQUEST['guestname']), 0, true, false))
  386. $context['post_error']['bad_name'] = true;
  387. }
  388. if (empty($modSettings['guest_post_no_email']))
  389. {
  390. if (!isset($_REQUEST['email']) || $_REQUEST['email'] == '')
  391. $context['post_error']['no_email'] = true;
  392. elseif (preg_match('~^[0-9A-Za-z=_+\-/][0-9A-Za-z=_\'+\-/\.]*@[\w\-]+(\.[\w\-]+)*(\.[\w]{2,6})$~', $_REQUEST['email']) == 0)
  393. $context['post_error']['bad_email'] = true;
  394. }
  395. }
  396. // This is self explanatory - got any questions?
  397. if (isset($_REQUEST['question']) && trim($_REQUEST['question']) == '')
  398. $context['post_error']['no_question'] = true;
  399. // This means they didn't click Post and get an error.
  400. $really_previewing = true;
  401. }
  402. else
  403. {
  404. if (!isset($_REQUEST['subject']))
  405. $_REQUEST['subject'] = '';
  406. if (!isset($_REQUEST['message']))
  407. $_REQUEST['message'] = '';
  408. if (!isset($_REQUEST['icon']))
  409. $_REQUEST['icon'] = 'xx';
  410. // They are previewing if they asked to preview (i.e. came from quick reply).
  411. $really_previewing = !empty($_POST['preview']);
  412. }
  413. // In order to keep the approval status flowing through, we have to pass it through the form...
  414. $context['becomes_approved'] = empty($_REQUEST['not_approved']);
  415. $context['show_approval'] = isset($_REQUEST['approve']) ? ($_REQUEST['approve'] ? 2 : 1) : 0;
  416. $context['can_announce'] &= $context['becomes_approved'];
  417. // Set up the inputs for the form.
  418. $form_subject = strtr($smcFunc['htmlspecialchars']($_REQUEST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
  419. $form_message = $smcFunc['htmlspecialchars']($_REQUEST['message'], ENT_QUOTES);
  420. // Make sure the subject isn't too long - taking into account special characters.
  421. if ($smcFunc['strlen']($form_subject) > 100)
  422. $form_subject = $smcFunc['substr']($form_subject, 0, 100);
  423. // Have we inadvertently trimmed off the subject of useful information?
  424. if ($smcFunc['htmltrim']($form_subject) === '')
  425. $context['post_error']['no_subject'] = true;
  426. // Any errors occurred?
  427. if (!empty($context['post_error']))
  428. {
  429. loadLanguage('Errors');
  430. $context['error_type'] = 'minor';
  431. $context['post_error']['messages'] = array();
  432. foreach ($context['post_error'] as $post_error => $dummy)
  433. {
  434. if ($post_error == 'messages')
  435. continue;
  436. if ($post_error == 'long_message')
  437. $txt['error_' . $post_error] = sprintf($txt['error_' . $post_error], $modSettings['max_messageLength']);
  438. $context['post_error']['messages'][] = $txt['error_' . $post_error];
  439. // If it's not a minor error flag it as such.
  440. if (!in_array($post_error, array('new_reply', 'not_approved', 'new_replies', 'old_topic', 'need_qr_verification')))
  441. $context['error_type'] = 'serious';
  442. }
  443. }
  444. if (isset($_REQUEST['poll']))
  445. {
  446. $context['question'] = isset($_REQUEST['question']) ? $smcFunc['htmlspecialchars'](trim($_REQUEST['question'])) : '';
  447. $context['choices'] = array();
  448. $choice_id = 0;
  449. $_POST['options'] = empty($_POST['options']) ? array() : htmlspecialchars__recursive($_POST['options']);
  450. foreach ($_POST['options'] as $option)
  451. {
  452. if (trim($option) == '')
  453. continue;
  454. $context['choices'][] = array(
  455. 'id' => $choice_id++,
  456. 'number' => $choice_id,
  457. 'label' => $option,
  458. 'is_last' => false
  459. );
  460. }
  461. if (count($context['choices']) < 2)
  462. {
  463. $context['choices'][] = array(
  464. 'id' => $choice_id++,
  465. 'number' => $choice_id,
  466. 'label' => '',
  467. 'is_last' => false
  468. );
  469. $context['choices'][] = array(
  470. 'id' => $choice_id++,
  471. 'number' => $choice_id,
  472. 'label' => '',
  473. 'is_last' => false
  474. );
  475. }
  476. $context['choices'][count($context['choices']) - 1]['is_last'] = true;
  477. }
  478. // Are you... a guest?
  479. if ($user_info['is_guest'])
  480. {
  481. $_REQUEST['guestname'] = !isset($_REQUEST['guestname']) ? '' : trim($_REQUEST['guestname']);
  482. $_REQUEST['email'] = !isset($_REQUEST['email']) ? '' : trim($_REQUEST['email']);
  483. $_REQUEST['guestname'] = htmlspecialchars($_REQUEST['guestname']);
  484. $context['name'] = $_REQUEST['guestname'];
  485. $_REQUEST['email'] = htmlspecialchars($_REQUEST['email']);
  486. $context['email'] = $_REQUEST['email'];
  487. $user_info['name'] = $_REQUEST['guestname'];
  488. }
  489. // Only show the preview stuff if they hit Preview.
  490. if ($really_previewing == true || isset($_REQUEST['xml']))
  491. {
  492. // Set up the preview message and subject and censor them...
  493. $context['preview_message'] = $form_message;
  494. preparsecode($form_message, true);
  495. preparsecode($context['preview_message']);
  496. // Do all bulletin board code tags, with or without smileys.
  497. $context['preview_message'] = parse_bbc($context['preview_message'], isset($_REQUEST['ns']) ? 0 : 1);
  498. if ($form_subject != '')
  499. {
  500. $context['preview_subject'] = $form_subject;
  501. censorText($context['preview_subject']);
  502. censorText($context['preview_message']);
  503. }
  504. else
  505. $context['preview_subject'] = '<em>' . $txt['no_subject'] . '</em>';
  506. // Protect any CDATA blocks.
  507. if (isset($_REQUEST['xml']))
  508. $context['preview_message'] = strtr($context['preview_message'], array(']]>' => ']]]]><![CDATA[>'));
  509. }
  510. // Set up the checkboxes.
  511. $context['notify'] = !empty($_REQUEST['notify']);
  512. $context['use_smileys'] = !isset($_REQUEST['ns']);
  513. $context['icon'] = isset($_REQUEST['icon']) ? preg_replace('~[\./\\\\*\':"<>]~', '', $_REQUEST['icon']) : 'xx';
  514. // Set the destination action for submission.
  515. $context['destination'] = 'post2;start=' . $_REQUEST['start'] . (isset($_REQUEST['msg']) ? ';msg=' . $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id'] : '') . (isset($_REQUEST['poll']) ? ';poll' : '');
  516. $context['submit_label'] = isset($_REQUEST['msg']) ? $txt['save'] : $txt['post'];
  517. // Previewing an edit?
  518. if (isset($_REQUEST['msg']) && !empty($topic))
  519. {
  520. // Get the existing message.
  521. $request = $smcFunc['db_query']('', '
  522. SELECT
  523. m.id_member, m.modified_time, m.smileys_enabled, m.body,
  524. m.poster_name, m.poster_email, m.subject, m.icon, m.approved,
  525. IFNULL(a.size, -1) AS filesize, a.filename, a.id_attach,
  526. a.approved AS attachment_approved, t.id_member_started AS id_member_poster,
  527. m.poster_time
  528. FROM {db_prefix}messages AS m
  529. INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
  530. LEFT JOIN {db_prefix}attachments AS a ON (a.id_msg = m.id_msg AND a.attachment_type = {int:attachment_type})
  531. WHERE m.id_msg = {int:id_msg}
  532. AND m.id_topic = {int:current_topic}',
  533. array(
  534. 'current_topic' => $topic,
  535. 'attachment_type' => 0,
  536. 'id_msg' => $_REQUEST['msg'],
  537. )
  538. );
  539. // The message they were trying to edit was most likely deleted.
  540. // !!! Change this error message?
  541. if ($smcFunc['db_num_rows']($request) == 0)
  542. fatal_lang_error('no_board', false);
  543. $row = $smcFunc['db_fetch_assoc']($request);
  544. $attachment_stuff = array($row);
  545. while ($row2 = $smcFunc['db_fetch_assoc']($request))
  546. $attachment_stuff[] = $row2;
  547. $smcFunc['db_free_result']($request);
  548. if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any'))
  549. {
  550. // Give an extra five minutes over the disable time threshold, so they can type - assuming the post is public.
  551. if ($row['approved'] && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time())
  552. fatal_lang_error('modify_post_time_passed', false);
  553. elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_own'))
  554. isAllowedTo('modify_replies');
  555. else
  556. isAllowedTo('modify_own');
  557. }
  558. elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_any'))
  559. isAllowedTo('modify_replies');
  560. else
  561. isAllowedTo('modify_any');
  562. if (!empty($modSettings['attachmentEnable']))
  563. {
  564. $request = $smcFunc['db_query']('', '
  565. SELECT IFNULL(size, -1) AS filesize, filename, id_attach, approved
  566. FROM {db_prefix}attachments
  567. WHERE id_msg = {int:id_msg}
  568. AND attachment_type = {int:attachment_type}',
  569. array(
  570. 'id_msg' => (int) $_REQUEST['msg'],
  571. 'attachment_type' => 0,
  572. )
  573. );
  574. while ($row = $smcFunc['db_fetch_assoc']($request))
  575. {
  576. if ($row['filesize'] <= 0)
  577. continue;
  578. $context['current_attachments'][] = array(
  579. 'name' => htmlspecialchars($row['filename']),
  580. 'id' => $row['id_attach'],
  581. 'approved' => $row['approved'],
  582. );
  583. }
  584. $smcFunc['db_free_result']($request);
  585. }
  586. // Allow moderators to change names....
  587. if (allowedTo('moderate_forum') && !empty($topic))
  588. {
  589. $request = $smcFunc['db_query']('', '
  590. SELECT id_member, poster_name, poster_email
  591. FROM {db_prefix}messages
  592. WHERE id_msg = {int:id_msg}
  593. AND id_topic = {int:current_topic}
  594. LIMIT 1',
  595. array(
  596. 'current_topic' => $topic,
  597. 'id_msg' => (int) $_REQUEST['msg'],
  598. )
  599. );
  600. $row = $smcFunc['db_fetch_assoc']($request);
  601. $smcFunc['db_free_result']($request);
  602. if (empty($row['id_member']))
  603. {
  604. $context['name'] = htmlspecialchars($row['poster_name']);
  605. $context['email'] = htmlspecialchars($row['poster_email']);
  606. }
  607. }
  608. }
  609. // No check is needed, since nothing is really posted.
  610. checkSubmitOnce('free');
  611. }
  612. // Editing a message...
  613. elseif (isset($_REQUEST['msg']) && !empty($topic))
  614. {
  615. $_REQUEST['msg'] = (int) $_REQUEST['msg'];
  616. // Get the existing message.
  617. $request = $smcFunc['db_query']('', '
  618. SELECT
  619. m.id_member, m.modified_time, m.smileys_enabled, m.body,
  620. m.poster_name, m.poster_email, m.subject, m.icon, m.approved,
  621. IFNULL(a.size, -1) AS filesize, a.filename, a.id_attach,
  622. a.approved AS attachment_approved, t.id_member_started AS id_member_poster,
  623. m.poster_time
  624. FROM {db_prefix}messages AS m
  625. INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
  626. LEFT JOIN {db_prefix}attachments AS a ON (a.id_msg = m.id_msg AND a.attachment_type = {int:attachment_type})
  627. WHERE m.id_msg = {int:id_msg}
  628. AND m.id_topic = {int:current_topic}',
  629. array(
  630. 'current_topic' => $topic,
  631. 'attachment_type' => 0,
  632. 'id_msg' => $_REQUEST['msg'],
  633. )
  634. );
  635. // The message they were trying to edit was most likely deleted.
  636. // !!! Change this error message?
  637. if ($smcFunc['db_num_rows']($request) == 0)
  638. fatal_lang_error('no_board', false);
  639. $row = $smcFunc['db_fetch_assoc']($request);
  640. $attachment_stuff = array($row);
  641. while ($row2 = $smcFunc['db_fetch_assoc']($request))
  642. $attachment_stuff[] = $row2;
  643. $smcFunc['db_free_result']($request);
  644. if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any'))
  645. {
  646. // Give an extra five minutes over the disable time threshold, so they can type - assuming the post is public.
  647. if ($row['approved'] && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time())
  648. fatal_lang_error('modify_post_time_passed', false);
  649. elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_own'))
  650. isAllowedTo('modify_replies');
  651. else
  652. isAllowedTo('modify_own');
  653. }
  654. elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_any'))
  655. isAllowedTo('modify_replies');
  656. else
  657. isAllowedTo('modify_any');
  658. // When was it last modified?
  659. if (!empty($row['modified_time']))
  660. $context['last_modified'] = timeformat($row['modified_time']);
  661. // Get the stuff ready for the form.
  662. $form_subject = $row['subject'];
  663. $form_message = un_preparsecode($row['body']);
  664. censorText($form_message);
  665. censorText($form_subject);
  666. // Check the boxes that should be checked.
  667. $context['use_smileys'] = !empty($row['smileys_enabled']);
  668. $context['icon'] = $row['icon'];
  669. // Show an "approve" box if the user can approve it, and the message isn't approved.
  670. if (!$row['approved'] && !$context['show_approval'])
  671. $context['show_approval'] = allowedTo('approve_posts');
  672. // Load up 'em attachments!
  673. foreach ($attachment_stuff as $attachment)
  674. {
  675. if ($attachment['filesize'] >= 0 && !empty($modSettings['attachmentEnable']))
  676. $context['current_attachments'][] = array(
  677. 'name' => htmlspecialchars($attachment['filename']),
  678. 'id' => $attachment['id_attach'],
  679. 'approved' => $attachment['attachment_approved'],
  680. );
  681. }
  682. // Allow moderators to change names....
  683. if (allowedTo('moderate_forum') && empty($row['id_member']))
  684. {
  685. $context['name'] = htmlspecialchars($row['poster_name']);
  686. $context['email'] = htmlspecialchars($row['poster_email']);
  687. }
  688. // Set the destinaton.
  689. $context['destination'] = 'post2;start=' . $_REQUEST['start'] . ';msg=' . $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id'] . (isset($_REQUEST['poll']) ? ';poll' : '');
  690. $context['submit_label'] = $txt['save'];
  691. }
  692. // Posting...
  693. else
  694. {
  695. // By default....
  696. $context['use_smileys'] = true;
  697. $context['icon'] = 'xx';
  698. if ($user_info['is_guest'])
  699. {
  700. $context['name'] = isset($_SESSION['guest_name']) ? $_SESSION['guest_name'] : '';
  701. $context['email'] = isset($_SESSION['guest_email']) ? $_SESSION['guest_email'] : '';
  702. }
  703. $context['destination'] = 'post2;start=' . $_REQUEST['start'] . (isset($_REQUEST['poll']) ? ';poll' : '');
  704. $context['submit_label'] = $txt['post'];
  705. // Posting a quoted reply?
  706. if (!empty($topic) && !empty($_REQUEST['quote']))
  707. {
  708. // Make sure they _can_ quote this post, and if so get it.
  709. $request = $smcFunc['db_query']('', '
  710. SELECT m.subject, IFNULL(mem.real_name, m.poster_name) AS poster_name, m.poster_time, m.body
  711. FROM {db_prefix}messages AS m
  712. INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board AND {query_see_board})
  713. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
  714. WHERE m.id_msg = {int:id_msg}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
  715. AND m.approved = {int:is_approved}') . '
  716. LIMIT 1',
  717. array(
  718. 'id_msg' => (int) $_REQUEST['quote'],
  719. 'is_approved' => 1,
  720. )
  721. );
  722. if ($smcFunc['db_num_rows']($request) == 0)
  723. fatal_lang_error('quoted_post_deleted', false);
  724. list ($form_subject, $mname, $mdate, $form_message) = $smcFunc['db_fetch_row']($request);
  725. $smcFunc['db_free_result']($request);
  726. // Add 'Re: ' to the front of the quoted subject.
  727. if (trim($context['response_prefix']) != '' && $smcFunc['strpos']($form_subject, trim($context['response_prefix'])) !== 0)
  728. $form_subject = $context['response_prefix'] . $form_subject;
  729. // Censor the message and subject.
  730. censorText($form_message);
  731. censorText($form_subject);
  732. // But if it's in HTML world, turn them into htmlspecialchar's so they can be edited!
  733. if (strpos($form_message, '[html]') !== false)
  734. {
  735. $parts = preg_split('~(\[/code\]|\[code(?:=[^\]]+)?\])~i', $form_message, -1, PREG_SPLIT_DELIM_CAPTURE);
  736. for ($i = 0, $n = count($parts); $i < $n; $i++)
  737. {
  738. // It goes 0 = outside, 1 = begin tag, 2 = inside, 3 = close tag, repeat.
  739. if ($i % 4 == 0)
  740. $parts[$i] = preg_replace_callback('~\[html\](.+?)\[/html\]~is', create_function('$m', ' return \'[html]\' . preg_replace(\'~<br\s?/?' . '>~i\', \'&lt;br /&gt;<br />\', "$m[1]") . \'[/html]\';'), $parts[$i]);
  741. }
  742. $form_message = implode('', $parts);
  743. }
  744. $form_message = preg_replace('~<br ?/?' . '>~i', "\n", $form_message);
  745. // Remove any nested quotes, if necessary.
  746. if (!empty($modSettings['removeNestedQuotes']))
  747. $form_message = preg_replace(array('~\n?\[quote.*?\].+?\[/quote\]\n?~is', '~^\n~', '~\[/quote\]~'), '', $form_message);
  748. // Add a quote string on the front and end.
  749. $form_message = '[quote author=' . $mname . ' link=topic=' . $topic . '.msg' . (int) $_REQUEST['quote'] . '#msg' . (int) $_REQUEST['quote'] . ' date=' . $mdate . ']' . "\n" . rtrim($form_message) . "\n" . '[/quote]';
  750. }
  751. // Posting a reply without a quote?
  752. elseif (!empty($topic) && empty($_REQUEST['quote']))
  753. {
  754. // Get the first message's subject.
  755. $form_subject = $first_subject;
  756. // Add 'Re: ' to the front of the subject.
  757. if (trim($context['response_prefix']) != '' && $form_subject != '' && $smcFunc['strpos']($form_subject, trim($context['response_prefix'])) !== 0)
  758. $form_subject = $context['response_prefix'] . $form_subject;
  759. // Censor the subject.
  760. censorText($form_subject);
  761. $form_message = '';
  762. }
  763. else
  764. {
  765. $form_subject = isset($_GET['subject']) ? $_GET['subject'] : '';
  766. $form_message = '';
  767. }
  768. }
  769. // !!! This won't work if you're posting an event.
  770. if (allowedTo('post_attachment') || allowedTo('post_unapproved_attachments'))
  771. {
  772. if (empty($_SESSION['temp_attachments']))
  773. $_SESSION['temp_attachments'] = array();
  774. if (!empty($modSettings['currentAttachmentUploadDir']))
  775. {
  776. if (!is_array($modSettings['attachmentUploadDir']))
  777. $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']);
  778. // Just use the current path for temp files.
  779. $current_attach_dir = $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']];
  780. }
  781. else
  782. $current_attach_dir = $modSettings['attachmentUploadDir'];
  783. // If this isn't a new post, check the current attachments.
  784. if (isset($_REQUEST['msg']))
  785. {
  786. $request = $smcFunc['db_query']('', '
  787. SELECT COUNT(*), SUM(size)
  788. FROM {db_prefix}attachments
  789. WHERE id_msg = {int:id_msg}
  790. AND attachment_type = {int:attachment_type}',
  791. array(
  792. 'id_msg' => (int) $_REQUEST['msg'],
  793. 'attachment_type' => 0,
  794. )
  795. );
  796. list ($quantity, $total_size) = $smcFunc['db_fetch_row']($request);
  797. $smcFunc['db_free_result']($request);
  798. }
  799. else
  800. {
  801. $quantity = 0;
  802. $total_size = 0;
  803. }
  804. $temp_start = 0;
  805. if (!empty($_SESSION['temp_attachments']))
  806. {
  807. if ($context['current_action'] != 'post2' || !empty($_POST['from_qr']))
  808. {
  809. $context['post_error']['messages'][] = $txt['error_temp_attachments'];
  810. $context['error_type'] = 'minor';
  811. }
  812. foreach ($_SESSION['temp_attachments'] as $attachID => $name)
  813. {
  814. $temp_start++;
  815. if (preg_match('~^post_tmp_' . $user_info['id'] . '_\d+$~', $attachID) == 0)
  816. {
  817. unset($_SESSION['temp_attachments'][$attachID]);
  818. continue;
  819. }
  820. if (!empty($_POST['attach_del']) && !in_array($attachID, $_POST['attach_del']))
  821. {
  822. $deleted_attachments = true;
  823. unset($_SESSION['temp_attachments'][$attachID]);
  824. @unlink($current_attach_dir . '/' . $attachID);
  825. continue;
  826. }
  827. $quantity++;
  828. $total_size += filesize($current_attach_dir . '/' . $attachID);
  829. $context['current_attachments'][] = array(
  830. 'name' => htmlspecialchars($name),
  831. 'id' => $attachID,
  832. 'approved' => 1,
  833. );
  834. }
  835. }
  836. if (!empty($_POST['attach_del']))
  837. {
  838. $del_temp = array();
  839. foreach ($_POST['attach_del'] as $i => $dummy)
  840. $del_temp[$i] = (int) $dummy;
  841. foreach ($context['current_attachments'] as $k => $dummy)
  842. if (!in_array($dummy['id'], $del_temp))
  843. {
  844. $context['current_attachments'][$k]['unchecked'] = true;
  845. $deleted_attachments = !isset($deleted_attachments) || is_bool($deleted_attachments) ? 1 : $deleted_attachments + 1;
  846. $quantity--;
  847. }
  848. }
  849. if (!empty($_FILES['attachment']))
  850. foreach ($_FILES['attachment']['tmp_name'] as $n => $dummy)
  851. {
  852. if ($_FILES['attachment']['name'][$n] == '')
  853. continue;
  854. if (!is_uploaded_file($_FILES['attachment']['tmp_name'][$n]) || (@ini_get('open_basedir') == '' && !file_exists($_FILES['attachment']['tmp_name'][$n])))
  855. fatal_lang_error('attach_timeout', 'critical');
  856. if (!empty($modSettings['attachmentSizeLimit']) && $_FILES['attachment']['size'][$n] > $modSettings['attachmentSizeLimit'] * 1024)
  857. fatal_lang_error('file_too_big', false, array($modSettings['attachmentSizeLimit']));
  858. $quantity++;
  859. if (!empty($modSettings['attachmentNumPerPostLimit']) && $quantity > $modSettings['attachmentNumPerPostLimit'])
  860. fatal_lang_error('attachments_limit_per_post', false, array($modSettings['attachmentNumPerPostLimit']));
  861. $total_size += $_FILES['attachment']['size'][$n];
  862. if (!empty($modSettings['attachmentPostLimit']) && $total_size > $modSettings['attachmentPostLimit'] * 1024)
  863. fatal_lang_error('file_too_big', false, array($modSettings['attachmentPostLimit']));
  864. if (!empty($modSettings['attachmentCheckExtensions']))
  865. {
  866. if (!in_array(strtolower(substr(strrchr($_FILES['attachment']['name'][$n], '.'), 1)), explode(',', strtolower($modSettings['attachmentExtensions']))))
  867. fatal_error($_FILES['attachment']['name'][$n] . '.<br />' . $txt['cant_upload_type'] . ' ' . $modSettings['attachmentExtensions'] . '.', false);
  868. }
  869. if (!empty($modSettings['attachmentDirSizeLimit']))
  870. {
  871. // Make sure the directory isn't full.
  872. $dirSize = 0;
  873. $dir = @opendir($current_attach_dir) or fatal_lang_error('cant_access_upload_path', 'critical');
  874. while ($file = readdir($dir))
  875. {
  876. if ($file == '.' || $file == '..')
  877. continue;
  878. if (preg_match('~^post_tmp_\d+_\d+$~', $file) != 0)
  879. {
  880. // Temp file is more than 5 hours old!
  881. if (filemtime($current_attach_dir . '/' . $file) < time() - 18000)
  882. @unlink($current_attach_dir . '/' . $file);
  883. continue;
  884. }
  885. $dirSize += filesize($current_attach_dir . '/' . $file);
  886. }
  887. closedir($dir);
  888. // Too big! Maybe you could zip it or something...
  889. if ($_FILES['attachment']['size'][$n] + $dirSize > $modSettings['attachmentDirSizeLimit'] * 1024)
  890. fatal_lang_error('ran_out_of_space');
  891. }
  892. if (!is_writable($current_attach_dir))
  893. fatal_lang_error('attachments_no_write', 'critical');
  894. $attachID = 'post_tmp_' . $user_info['id'] . '_' . $temp_start++;
  895. $_SESSION['temp_attachments'][$attachID] = basename($_FILES['attachment']['name'][$n]);
  896. $context['current_attachments'][] = array(
  897. 'name' => htmlspecialchars(basename($_FILES['attachment']['name'][$n])),
  898. 'id' => $attachID,
  899. 'approved' => 1,
  900. );
  901. $destName = $current_attach_dir . '/' . $attachID;
  902. if (!move_uploaded_file($_FILES['attachment']['tmp_name'][$n], $destName))
  903. fatal_lang_error('attach_timeout', 'critical');
  904. @chmod($destName, 0644);
  905. }
  906. }
  907. // If we are coming here to make a reply, and someone has already replied... make a special warning message.
  908. if (isset($newRepliesError))
  909. {
  910. $context['post_error']['messages'][] = $newRepliesError == 1 ? $txt['error_new_reply'] : $txt['error_new_replies'];
  911. $context['error_type'] = 'minor';
  912. }
  913. if (isset($oldTopicError))
  914. {
  915. $context['post_error']['messages'][] = sprintf($txt['error_old_topic'], $modSettings['oldTopicDays']);
  916. $context['error_type'] = 'minor';
  917. }
  918. // What are you doing? Posting a poll, modifying, previewing, new post, or reply...
  919. if (isset($_REQUEST['poll']))
  920. $context['page_title'] = $txt['new_poll'];
  921. elseif ($context['make_event'])
  922. $context['page_title'] = $context['event']['id'] == -1 ? $txt['calendar_post_event'] : $txt['calendar_edit'];
  923. elseif (isset($_REQUEST['msg']))
  924. $context['page_title'] = $txt['modify_msg'];
  925. elseif (isset($_REQUEST['subject'], $context['preview_subject']))
  926. $context['page_title'] = $txt['preview'] . ' - ' . strip_tags($context['preview_subject']);
  927. elseif (empty($topic))
  928. $context['page_title'] = $txt['start_new_topic'];
  929. else
  930. $context['page_title'] = $txt['post_reply'];
  931. // Build the link tree.
  932. if (empty($topic))
  933. $context['linktree'][] = array(
  934. 'name' => '<em>' . $txt['start_new_topic'] . '</em>'
  935. );
  936. else
  937. $context['linktree'][] = array(
  938. 'url' => $scripturl . '?topic=' . $topic . '.' . $_REQUEST['start'],
  939. 'name' => $form_subject,
  940. 'extra_before' => '<span' . ($settings['linktree_inline'] ? ' class="smalltext"' : '') . '><strong class="nav">' . $context['page_title'] . ' ( </strong></span>',
  941. 'extra_after' => '<span' . ($settings['linktree_inline'] ? ' class="smalltext"' : '') . '><strong class="nav"> )</strong></span>'
  942. );
  943. // Give wireless a linktree url to the post screen, so that they can switch to full version.
  944. if (WIRELESS)
  945. $context['linktree'][count($context['linktree']) - 1]['url'] = $scripturl . '?action=post;' . (!empty($topic) ? 'topic=' . $topic : 'board=' . $board) . '.' . $_REQUEST['start'] . (isset($_REQUEST['msg']) ? ';msg=' . (int) $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id'] : '');
  946. // 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.
  947. // !!! This won't work if you're posting an event.
  948. $context['num_allowed_attachments'] = empty($modSettings['attachmentNumPerPostLimit']) ? 50 : min($modSettings['attachmentNumPerPostLimit'] - count($context['current_attachments']) + (isset($deleted_attachments) ? $deleted_attachments : 0), $modSettings['attachmentNumPerPostLimit']);
  949. $context['can_post_attachment'] = !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1 && (allowedTo('post_attachment') || ($modSettings['postmod_active'] && allowedTo('post_unapproved_attachments'))) && $context['num_allowed_attachments'] > 0;
  950. $context['can_post_attachment_unapproved'] = allowedTo('post_attachment');
  951. $context['subject'] = addcslashes($form_subject, '"');
  952. $context['message'] = str_replace(array('"', '<', '>', '&nbsp;'), array('&quot;', '&lt;', '&gt;', ' '), $form_message);
  953. // Needed for the editor and message icons.
  954. require_once($sourcedir . '/Subs-Editor.php');
  955. // Now create the editor.
  956. $editorOptions = array(
  957. 'id' => 'message',
  958. 'value' => $context['message'],
  959. 'labels' => array(
  960. 'post_button' => $context['submit_label'],
  961. ),
  962. // add height and width for the editor
  963. 'height' => '175px',
  964. 'width' => '100%',
  965. // We do XML preview here.
  966. 'preview_type' => 2,
  967. );
  968. create_control_richedit($editorOptions);
  969. // Store the ID.
  970. $context['post_box_name'] = $editorOptions['id'];
  971. $context['attached'] = '';
  972. $context['make_poll'] = isset($_REQUEST['poll']);
  973. // Message icons - customized icons are off?
  974. $context['icons'] = getMessageIcons($board);
  975. if (!empty($context['icons']))
  976. $context['icons'][count($context['icons']) - 1]['is_last'] = true;
  977. $context['icon_url'] = '';
  978. for ($i = 0, $n = count($context['icons']); $i < $n; $i++)
  979. {
  980. $context['icons'][$i]['selected'] = $context['icon'] == $context['icons'][$i]['value'];
  981. if ($context['icons'][$i]['selected'])
  982. $context['icon_url'] = $context['icons'][$i]['url'];
  983. }
  984. if (empty($context['icon_url']))
  985. {
  986. $context['icon_url'] = $settings[file_exists($settings['theme_dir'] . '/images/post/' . $context['icon'] . '.gif') ? 'images_url' : 'default_images_url'] . '/post/' . $context['icon'] . '.gif';
  987. array_unshift($context['icons'], array(
  988. 'value' => $context['icon'],
  989. 'name' => $txt['current_icon'],
  990. 'url' => $context['icon_url'],
  991. 'is_last' => empty($context['icons']),
  992. 'selected' => true,
  993. ));
  994. }
  995. if (!empty($topic) && !empty($modSettings['topicSummaryPosts']))
  996. getTopic();
  997. // If the user can post attachments prepare the warning labels.
  998. if ($context['can_post_attachment'])
  999. {
  1000. $context['allowed_extensions'] = strtr($modSettings['attachmentExtensions'], array(',' => ', '));
  1001. $context['attachment_restrictions'] = array();
  1002. $attachmentRestrictionTypes = array('attachmentNumPerPostLimit', 'attachmentPostLimit', 'attachmentSizeLimit');
  1003. foreach ($attachmentRestrictionTypes as $type)
  1004. if (!empty($modSettings[$type]))
  1005. $context['attachment_restrictions'][] = sprintf($txt['attach_restrict_' . $type], $modSettings[$type]);
  1006. }
  1007. $context['back_to_topic'] = isset($_REQUEST['goback']) || (isset($_REQUEST['msg']) && !isset($_REQUEST['subject']));
  1008. $context['show_additional_options'] = !empty($_POST['additional_options']) || !empty($_SESSION['temp_attachments']) || !empty($deleted_attachments);
  1009. $context['is_new_topic'] = empty($topic);
  1010. $context['is_new_post'] = !isset($_REQUEST['msg']);
  1011. $context['is_first_post'] = $context['is_new_topic'] || (isset($_REQUEST['msg']) && $_REQUEST['msg'] == $id_first_msg);
  1012. // Do we need to show the visual verification image?
  1013. $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));
  1014. if ($context['require_verification'])
  1015. {
  1016. require_once($sourcedir . '/Subs-Editor.php');
  1017. $verificationOptions = array(
  1018. 'id' => 'post',
  1019. );
  1020. $context['require_verification'] = create_control_verification($verificationOptions);
  1021. $context['visual_verification_id'] = $verificationOptions['id'];
  1022. }
  1023. // If they came from quick reply, and have to enter verification details, give them some notice.
  1024. if (!empty($_REQUEST['from_qr']) && !empty($context['require_verification']))
  1025. {
  1026. $context['post_error']['messages'][] = $txt['enter_verification_details'];
  1027. $context['error_type'] = 'minor';
  1028. }
  1029. // WYSIWYG only works if BBC is enabled
  1030. $modSettings['disable_wysiwyg'] = !empty($modSettings['disable_wysiwyg']) || empty($modSettings['enableBBC']);
  1031. // Register this form in the session variables.
  1032. checkSubmitOnce('register');
  1033. // Finally, load the template.
  1034. if (WIRELESS && WIRELESS_PROTOCOL != 'wap')
  1035. $context['sub_template'] = WIRELESS_PROTOCOL . '_post';
  1036. elseif (!isset($_REQUEST['xml']))
  1037. loadTemplate('Post');
  1038. }
  1039. function Post2()
  1040. {
  1041. global $board, $topic, $txt, $modSettings, $sourcedir, $context;
  1042. global $user_info, $board_info, $options, $smcFunc;
  1043. // Sneaking off, are we?
  1044. if (empty($_POST) && empty($topic))
  1045. redirectexit('action=post;board=' . $board . '.0');
  1046. elseif (empty($_POST) && !empty($topic))
  1047. redirectexit('action=post;topic=' . $topic . '.0');
  1048. // No need!
  1049. $context['robot_no_index'] = true;
  1050. // If we came from WYSIWYG then turn it back into BBC regardless.
  1051. if (!empty($_REQUEST['message_mode']) && isset($_REQUEST['message']))
  1052. {
  1053. require_once($sourcedir . '/Subs-Editor.php');
  1054. $_REQUEST['message'] = html_to_bbc($_REQUEST['message']);
  1055. // We need to unhtml it now as it gets done shortly.
  1056. $_REQUEST['message'] = un_htmlspecialchars($_REQUEST['message']);
  1057. // We need this for everything else.
  1058. $_POST['message'] = $_REQUEST['message'];
  1059. }
  1060. // Previewing? Go back to start.
  1061. if (isset($_REQUEST['preview']))
  1062. return Post();
  1063. // Prevent double submission of this form.
  1064. checkSubmitOnce('check');
  1065. // No errors as yet.
  1066. $post_errors = array();
  1067. // If the session has timed out, let the user re-submit their form.
  1068. if (checkSession('post', '', false) != '')
  1069. $post_errors[] = 'session_timeout';
  1070. // Wrong verification code?
  1071. 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)))
  1072. {
  1073. require_once($sourcedir . '/Subs-Editor.php');
  1074. $verificationOptions = array(
  1075. 'id' => 'post',
  1076. );
  1077. $context['require_verification'] = create_control_verification($verificationOptions, true);
  1078. if (is_array($context['require_verification']))
  1079. $post_errors = array_merge($post_errors, $context['require_verification']);
  1080. }
  1081. require_once($sourcedir . '/Subs-Post.php');
  1082. loadLanguage('Post');
  1083. // If this isn't a new topic load the topic info that we need.
  1084. if (!empty($topic))
  1085. {
  1086. $request = $smcFunc['db_query']('', '
  1087. SELECT locked, is_sticky, id_poll, approved, id_first_msg, id_last_msg, id_member_started, id_board
  1088. FROM {db_prefix}topics
  1089. WHERE id_topic = {int:current_topic}
  1090. LIMIT 1',
  1091. array(
  1092. 'current_topic' => $topic,
  1093. )
  1094. );
  1095. $topic_info = $smcFunc['db_fetch_assoc']($request);
  1096. $smcFunc['db_free_result']($request);
  1097. // Though the topic should be there, it might have vanished.
  1098. if (!is_array($topic_info))
  1099. fatal_lang_error('topic_doesnt_exist');
  1100. // Did this topic suddenly move? Just checking...
  1101. if ($topic_info['id_board'] != $board)
  1102. fatal_lang_error('not_a_topic');
  1103. }
  1104. // Replying to a topic?
  1105. if (!empty($topic) && !isset($_REQUEST['msg']))
  1106. {
  1107. // Don't allow a post if it's locked.
  1108. if ($topic_info['locked'] != 0 && !allowedTo('moderate_board'))
  1109. fatal_lang_error('topic_locked', false);
  1110. // Sorry, multiple polls aren't allowed... yet. You should stop giving me ideas :P.
  1111. if (isset($_REQUEST['poll']) && $topic_info['id_poll'] > 0)
  1112. unset($_REQUEST['poll']);
  1113. // Do the permissions and approval stuff...
  1114. $

Large files files are truncated, but you can click here to view the full file