Post.php 104 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913
  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.1 Alpha 1
  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. function Post()
  70. {
  71. global $txt, $scripturl, $topic, $modSettings, $board;
  72. global $user_info, $sc, $board_info, $context, $settings;
  73. global $sourcedir, $options, $smcFunc, $language;
  74. loadLanguage('Post');
  75. // You can't reply with a poll... hacker.
  76. if (isset($_REQUEST['poll']) && !empty($topic) && !isset($_REQUEST['msg']))
  77. unset($_REQUEST['poll']);
  78. // Posting an event?
  79. $context['make_event'] = isset($_REQUEST['calendar']);
  80. $context['robot_no_index'] = true;
  81. // You must be posting to *some* board.
  82. if (empty($board) && !$context['make_event'])
  83. fatal_lang_error('no_board', false);
  84. require_once($sourcedir . '/Subs-Post.php');
  85. if (isset($_REQUEST['xml']))
  86. {
  87. $context['sub_template'] = 'post';
  88. // Just in case of an earlier error...
  89. $context['preview_message'] = '';
  90. $context['preview_subject'] = '';
  91. }
  92. // No message is complete without a topic.
  93. if (empty($topic) && !empty($_REQUEST['msg']))
  94. {
  95. $request = $smcFunc['db_query']('', '
  96. SELECT id_topic
  97. FROM {db_prefix}messages
  98. WHERE id_msg = {int:msg}',
  99. array(
  100. 'msg' => (int) $_REQUEST['msg'],
  101. ));
  102. if ($smcFunc['db_num_rows']($request) != 1)
  103. unset($_REQUEST['msg'], $_POST['msg'], $_GET['msg']);
  104. else
  105. list ($topic) = $smcFunc['db_fetch_row']($request);
  106. $smcFunc['db_free_result']($request);
  107. }
  108. // Check if it's locked. It isn't locked if no topic is specified.
  109. if (!empty($topic))
  110. {
  111. $request = $smcFunc['db_query']('', '
  112. SELECT
  113. t.locked, IFNULL(ln.id_topic, 0) AS notify, t.is_sticky, t.id_poll, t.id_last_msg, mf.id_member,
  114. t.id_first_msg, mf.subject,
  115. CASE WHEN ml.poster_time > ml.modified_time THEN ml.poster_time ELSE ml.modified_time END AS last_post_time
  116. FROM {db_prefix}topics AS t
  117. LEFT JOIN {db_prefix}log_notify AS ln ON (ln.id_topic = t.id_topic AND ln.id_member = {int:current_member})
  118. LEFT JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg)
  119. LEFT JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
  120. WHERE t.id_topic = {int:current_topic}
  121. LIMIT 1',
  122. array(
  123. 'current_member' => $user_info['id'],
  124. 'current_topic' => $topic,
  125. )
  126. );
  127. list ($locked, $context['notify'], $sticky, $pollID, $context['topic_last_message'], $id_member_poster, $id_first_msg, $first_subject, $lastPostTime) = $smcFunc['db_fetch_row']($request);
  128. $smcFunc['db_free_result']($request);
  129. // If this topic already has a poll, they sure can't add another.
  130. if (isset($_REQUEST['poll']) && $pollID > 0)
  131. unset($_REQUEST['poll']);
  132. if (empty($_REQUEST['msg']))
  133. {
  134. if ($user_info['is_guest'] && !allowedTo('post_reply_any') && (!$modSettings['postmod_active'] || !allowedTo('post_unapproved_replies_any')))
  135. is_not_guest();
  136. // By default the reply will be approved...
  137. $context['becomes_approved'] = true;
  138. if ($id_member_poster != $user_info['id'])
  139. {
  140. if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_any') && !allowedTo('post_reply_any'))
  141. $context['becomes_approved'] = false;
  142. else
  143. isAllowedTo('post_reply_any');
  144. }
  145. elseif (!allowedTo('post_reply_any'))
  146. {
  147. if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_own') && !allowedTo('post_reply_own'))
  148. $context['becomes_approved'] = false;
  149. else
  150. isAllowedTo('post_reply_own');
  151. }
  152. }
  153. else
  154. $context['becomes_approved'] = true;
  155. $context['can_lock'] = allowedTo('lock_any') || ($user_info['id'] == $id_member_poster && allowedTo('lock_own'));
  156. $context['can_sticky'] = allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']);
  157. $context['notify'] = !empty($context['notify']);
  158. $context['sticky'] = isset($_REQUEST['sticky']) ? !empty($_REQUEST['sticky']) : $sticky;
  159. }
  160. else
  161. {
  162. $context['becomes_approved'] = true;
  163. if ((!$context['make_event'] || !empty($board)))
  164. {
  165. if ($modSettings['postmod_active'] && !allowedTo('post_new') && allowedTo('post_unapproved_topics'))
  166. $context['becomes_approved'] = false;
  167. else
  168. isAllowedTo('post_new');
  169. }
  170. $locked = 0;
  171. // @todo These won't work if you're making an event.
  172. $context['can_lock'] = allowedTo(array('lock_any', 'lock_own'));
  173. $context['can_sticky'] = allowedTo('make_sticky') && !empty($modSettings['enableStickyTopics']);
  174. $context['notify'] = !empty($context['notify']);
  175. $context['sticky'] = !empty($_REQUEST['sticky']);
  176. }
  177. // @todo These won't work if you're posting an event!
  178. $context['can_notify'] = allowedTo('mark_any_notify');
  179. $context['can_move'] = allowedTo('move_any');
  180. $context['move'] = !empty($_REQUEST['move']);
  181. $context['announce'] = !empty($_REQUEST['announce']);
  182. // You can only announce topics that will get approved...
  183. $context['can_announce'] = allowedTo('announce_topic') && $context['becomes_approved'];
  184. $context['locked'] = !empty($locked) || !empty($_REQUEST['lock']);
  185. $context['can_quote'] = empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC']));
  186. // Generally don't show the approval box... (Assume we want things approved)
  187. $context['show_approval'] = false;
  188. // An array to hold all the attachments for this topic.
  189. $context['current_attachments'] = array();
  190. // Don't allow a post if it's locked and you aren't all powerful.
  191. if ($locked && !allowedTo('moderate_board'))
  192. fatal_lang_error('topic_locked', false);
  193. // Check the users permissions - is the user allowed to add or post a poll?
  194. if (isset($_REQUEST['poll']) && $modSettings['pollMode'] == '1')
  195. {
  196. // New topic, new poll.
  197. if (empty($topic))
  198. isAllowedTo('poll_post');
  199. // This is an old topic - but it is yours! Can you add to it?
  200. elseif ($user_info['id'] == $id_member_poster && !allowedTo('poll_add_any'))
  201. isAllowedTo('poll_add_own');
  202. // If you're not the owner, can you add to any poll?
  203. else
  204. isAllowedTo('poll_add_any');
  205. require_once($sourcedir . '/Subs-Members.php');
  206. $allowedVoteGroups = groupsAllowedTo('poll_vote', $board);
  207. // Set up the poll options.
  208. $context['poll_options'] = array(
  209. 'max_votes' => empty($_POST['poll_max_votes']) ? '1' : max(1, $_POST['poll_max_votes']),
  210. 'hide' => empty($_POST['poll_hide']) ? 0 : $_POST['poll_hide'],
  211. 'expire' => !isset($_POST['poll_expire']) ? '' : $_POST['poll_expire'],
  212. 'change_vote' => isset($_POST['poll_change_vote']),
  213. 'guest_vote' => isset($_POST['poll_guest_vote']),
  214. 'guest_vote_enabled' => in_array(-1, $allowedVoteGroups['allowed']),
  215. );
  216. // Make all five poll choices empty.
  217. $context['choices'] = array(
  218. array('id' => 0, 'number' => 1, 'label' => '', 'is_last' => false),
  219. array('id' => 1, 'number' => 2, 'label' => '', 'is_last' => false),
  220. array('id' => 2, 'number' => 3, 'label' => '', 'is_last' => false),
  221. array('id' => 3, 'number' => 4, 'label' => '', 'is_last' => false),
  222. array('id' => 4, 'number' => 5, 'label' => '', 'is_last' => true)
  223. );
  224. }
  225. if ($context['make_event'])
  226. {
  227. // They might want to pick a board.
  228. if (!isset($context['current_board']))
  229. $context['current_board'] = 0;
  230. // Start loading up the event info.
  231. $context['event'] = array();
  232. $context['event']['title'] = isset($_REQUEST['evtitle']) ? htmlspecialchars(stripslashes($_REQUEST['evtitle'])) : '';
  233. $context['event']['id'] = isset($_REQUEST['eventid']) ? (int) $_REQUEST['eventid'] : -1;
  234. $context['event']['new'] = $context['event']['id'] == -1;
  235. // Permissions check!
  236. isAllowedTo('calendar_post');
  237. // Editing an event? (but NOT previewing!?)
  238. if (empty($context['event']['new']) && !isset($_REQUEST['subject']))
  239. {
  240. // If the user doesn't have permission to edit the post in this topic, redirect them.
  241. if ((empty($id_member_poster) || $id_member_poster != $user_info['id'] || !allowedTo('modify_own')) && !allowedTo('modify_any'))
  242. {
  243. require_once($sourcedir . '/Calendar.php');
  244. return CalendarPost();
  245. }
  246. // Get the current event information.
  247. $request = $smcFunc['db_query']('', '
  248. SELECT
  249. id_member, title, MONTH(start_date) AS month, DAYOFMONTH(start_date) AS day,
  250. YEAR(start_date) AS year, (TO_DAYS(end_date) - TO_DAYS(start_date)) AS span
  251. FROM {db_prefix}calendar
  252. WHERE id_event = {int:id_event}
  253. LIMIT 1',
  254. array(
  255. 'id_event' => $context['event']['id'],
  256. )
  257. );
  258. $row = $smcFunc['db_fetch_assoc']($request);
  259. $smcFunc['db_free_result']($request);
  260. // Make sure the user is allowed to edit this event.
  261. if ($row['id_member'] != $user_info['id'])
  262. isAllowedTo('calendar_edit_any');
  263. elseif (!allowedTo('calendar_edit_any'))
  264. isAllowedTo('calendar_edit_own');
  265. $context['event']['month'] = $row['month'];
  266. $context['event']['day'] = $row['day'];
  267. $context['event']['year'] = $row['year'];
  268. $context['event']['title'] = $row['title'];
  269. $context['event']['span'] = $row['span'] + 1;
  270. }
  271. else
  272. {
  273. $today = getdate();
  274. // You must have a month and year specified!
  275. if (!isset($_REQUEST['month']))
  276. $_REQUEST['month'] = $today['mon'];
  277. if (!isset($_REQUEST['year']))
  278. $_REQUEST['year'] = $today['year'];
  279. $context['event']['month'] = (int) $_REQUEST['month'];
  280. $context['event']['year'] = (int) $_REQUEST['year'];
  281. $context['event']['day'] = isset($_REQUEST['day']) ? $_REQUEST['day'] : ($_REQUEST['month'] == $today['mon'] ? $today['mday'] : 0);
  282. $context['event']['span'] = isset($_REQUEST['span']) ? $_REQUEST['span'] : 1;
  283. // Make sure the year and month are in the valid range.
  284. if ($context['event']['month'] < 1 || $context['event']['month'] > 12)
  285. fatal_lang_error('invalid_month', false);
  286. if ($context['event']['year'] < $modSettings['cal_minyear'] || $context['event']['year'] > $modSettings['cal_maxyear'])
  287. fatal_lang_error('invalid_year', false);
  288. // Get a list of boards they can post in.
  289. $boards = boardsAllowedTo('post_new');
  290. if (empty($boards))
  291. fatal_lang_error('cannot_post_new', 'user');
  292. // Load a list of boards for this event in the context.
  293. require_once($sourcedir . '/Subs-MessageIndex.php');
  294. $boardListOptions = array(
  295. 'included_boards' => in_array(0, $boards) ? null : $boards,
  296. 'not_redirection' => true,
  297. 'use_permissions' => true,
  298. 'selected_board' => empty($context['current_board']) ? $modSettings['cal_defaultboard'] : $context['current_board'],
  299. );
  300. $context['event']['categories'] = getBoardList($boardListOptions);
  301. }
  302. // Find the last day of the month.
  303. $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']));
  304. $context['event']['board'] = !empty($board) ? $board : $modSettings['cal_defaultboard'];
  305. }
  306. if (empty($context['post_errors']))
  307. $context['post_errors'] = array();
  308. // See if any new replies have come along.
  309. // Huh, $_REQUEST['msg'] is set upon submit, so this doesn't get executed at submit
  310. // only at preview
  311. if (empty($_REQUEST['msg']) && !empty($topic))
  312. {
  313. if (empty($options['no_new_reply_warning']) && isset($_REQUEST['last_msg']) && $context['topic_last_message'] > $_REQUEST['last_msg'])
  314. {
  315. $request = $smcFunc['db_query']('', '
  316. SELECT COUNT(*)
  317. FROM {db_prefix}messages
  318. WHERE id_topic = {int:current_topic}
  319. AND id_msg > {int:last_msg}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
  320. AND approved = {int:approved}') . '
  321. LIMIT 1',
  322. array(
  323. 'current_topic' => $topic,
  324. 'last_msg' => (int) $_REQUEST['last_msg'],
  325. 'approved' => 1,
  326. )
  327. );
  328. list ($context['new_replies']) = $smcFunc['db_fetch_row']($request);
  329. $smcFunc['db_free_result']($request);
  330. if (!empty($context['new_replies']))
  331. {
  332. if ($context['new_replies'] == 1)
  333. $txt['error_new_reply'] = isset($_GET['last_msg']) ? $txt['error_new_reply_reading'] : $txt['error_new_reply'];
  334. else
  335. $txt['error_new_replies'] = sprintf(isset($_GET['last_msg']) ? $txt['error_new_replies_reading'] : $txt['error_new_replies'], $context['new_replies']);
  336. // If they've come from the display page then we treat the error differently....
  337. if (isset($_GET['last_msg']))
  338. $newRepliesError = $context['new_replies'];
  339. else
  340. $context['post_error'][$context['new_replies'] == 1 ? 'new_reply' : 'new_replies'] = true;
  341. $modSettings['topicSummaryPosts'] = $context['new_replies'] > $modSettings['topicSummaryPosts'] ? max($modSettings['topicSummaryPosts'], 5) : $modSettings['topicSummaryPosts'];
  342. }
  343. }
  344. // Check whether this is a really old post being bumped...
  345. if (!empty($modSettings['oldTopicDays']) && $lastPostTime + $modSettings['oldTopicDays'] * 86400 < time() && empty($sticky) && !isset($_REQUEST['subject']))
  346. $oldTopicError = true;
  347. }
  348. // Get a response prefix (like 'Re:') in the default forum language.
  349. if (!isset($context['response_prefix']) && !($context['response_prefix'] = cache_get_data('response_prefix')))
  350. {
  351. if ($language === $user_info['language'])
  352. $context['response_prefix'] = $txt['response_prefix'];
  353. else
  354. {
  355. loadLanguage('index', $language, false);
  356. $context['response_prefix'] = $txt['response_prefix'];
  357. loadLanguage('index');
  358. }
  359. cache_put_data('response_prefix', $context['response_prefix'], 600);
  360. }
  361. // Previewing, modifying, or posting?
  362. // Do we have a body, but an error happened.
  363. if (isset($_REQUEST['message']) || !empty($context['post_error']))
  364. {
  365. // Validate inputs.
  366. if (empty($context['post_error']))
  367. {
  368. if (htmltrim__recursive(htmlspecialchars__recursive($_REQUEST['subject'])) == '')
  369. $context['post_error']['no_subject'] = true;
  370. if (htmltrim__recursive(htmlspecialchars__recursive($_REQUEST['message'])) == '')
  371. $context['post_error']['no_message'] = true;
  372. if (!empty($modSettings['max_messageLength']) && $smcFunc['strlen']($_REQUEST['message']) > $modSettings['max_messageLength'])
  373. $context['post_error']['long_message'] = true;
  374. // Are you... a guest?
  375. if ($user_info['is_guest'])
  376. {
  377. $_REQUEST['guestname'] = !isset($_REQUEST['guestname']) ? '' : trim($_REQUEST['guestname']);
  378. $_REQUEST['email'] = !isset($_REQUEST['email']) ? '' : trim($_REQUEST['email']);
  379. // Validate the name and email.
  380. if (!isset($_REQUEST['guestname']) || trim(strtr($_REQUEST['guestname'], '_', ' ')) == '')
  381. $context['post_error']['no_name'] = true;
  382. elseif ($smcFunc['strlen']($_REQUEST['guestname']) > 25)
  383. $context['post_error']['long_name'] = true;
  384. else
  385. {
  386. require_once($sourcedir . '/Subs-Members.php');
  387. if (isReservedName(htmlspecialchars($_REQUEST['guestname']), 0, true, false))
  388. $context['post_error']['bad_name'] = true;
  389. }
  390. if (empty($modSettings['guest_post_no_email']))
  391. {
  392. if (!isset($_REQUEST['email']) || $_REQUEST['email'] == '')
  393. $context['post_error']['no_email'] = true;
  394. elseif (preg_match('~^[0-9A-Za-z=_+\-/][0-9A-Za-z=_\'+\-/\.]*@[\w\-]+(\.[\w\-]+)*(\.[\w]{2,6})$~', $_REQUEST['email']) == 0)
  395. $context['post_error']['bad_email'] = true;
  396. }
  397. }
  398. // This is self explanatory - got any questions?
  399. if (isset($_REQUEST['question']) && trim($_REQUEST['question']) == '')
  400. $context['post_error']['no_question'] = true;
  401. // This means they didn't click Post and get an error.
  402. $really_previewing = true;
  403. }
  404. else
  405. {
  406. if (!isset($_REQUEST['subject']))
  407. $_REQUEST['subject'] = '';
  408. if (!isset($_REQUEST['message']))
  409. $_REQUEST['message'] = '';
  410. if (!isset($_REQUEST['icon']))
  411. $_REQUEST['icon'] = 'xx';
  412. // They are previewing if they asked to preview (i.e. came from quick reply).
  413. $really_previewing = !empty($_POST['preview']);
  414. }
  415. // In order to keep the approval status flowing through, we have to pass it through the form...
  416. $context['becomes_approved'] = empty($_REQUEST['not_approved']);
  417. $context['show_approval'] = isset($_REQUEST['approve']) ? ($_REQUEST['approve'] ? 2 : 1) : 0;
  418. $context['can_announce'] &= $context['becomes_approved'];
  419. // Set up the inputs for the form.
  420. $form_subject = strtr($smcFunc['htmlspecialchars']($_REQUEST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
  421. $form_message = $smcFunc['htmlspecialchars']($_REQUEST['message'], ENT_QUOTES);
  422. // Make sure the subject isn't too long - taking into account special characters.
  423. if ($smcFunc['strlen']($form_subject) > 100)
  424. $form_subject = $smcFunc['substr']($form_subject, 0, 100);
  425. // Have we inadvertently trimmed off the subject of useful information?
  426. if ($smcFunc['htmltrim']($form_subject) === '')
  427. $context['post_error']['no_subject'] = true;
  428. // Any errors occurred?
  429. if (!empty($context['post_error']))
  430. {
  431. loadLanguage('Errors');
  432. $context['error_type'] = 'minor';
  433. $context['post_error']['messages'] = array();
  434. foreach ($context['post_error'] as $post_error => $dummy)
  435. {
  436. if ($post_error == 'messages')
  437. continue;
  438. if ($post_error == 'long_message')
  439. $txt['error_' . $post_error] = sprintf($txt['error_' . $post_error], $modSettings['max_messageLength']);
  440. $context['post_error']['messages'][] = $txt['error_' . $post_error];
  441. // If it's not a minor error flag it as such.
  442. if (!in_array($post_error, array('new_reply', 'not_approved', 'new_replies', 'old_topic', 'need_qr_verification')))
  443. $context['error_type'] = 'serious';
  444. }
  445. }
  446. if (isset($_REQUEST['poll']))
  447. {
  448. $context['question'] = isset($_REQUEST['question']) ? $smcFunc['htmlspecialchars'](trim($_REQUEST['question'])) : '';
  449. $context['choices'] = array();
  450. $choice_id = 0;
  451. $_POST['options'] = empty($_POST['options']) ? array() : htmlspecialchars__recursive($_POST['options']);
  452. foreach ($_POST['options'] as $option)
  453. {
  454. if (trim($option) == '')
  455. continue;
  456. $context['choices'][] = array(
  457. 'id' => $choice_id++,
  458. 'number' => $choice_id,
  459. 'label' => $option,
  460. 'is_last' => false
  461. );
  462. }
  463. if (count($context['choices']) < 2)
  464. {
  465. $context['choices'][] = array(
  466. 'id' => $choice_id++,
  467. 'number' => $choice_id,
  468. 'label' => '',
  469. 'is_last' => false
  470. );
  471. $context['choices'][] = array(
  472. 'id' => $choice_id++,
  473. 'number' => $choice_id,
  474. 'label' => '',
  475. 'is_last' => false
  476. );
  477. }
  478. $context['choices'][count($context['choices']) - 1]['is_last'] = true;
  479. }
  480. // Are you... a guest?
  481. if ($user_info['is_guest'])
  482. {
  483. $_REQUEST['guestname'] = !isset($_REQUEST['guestname']) ? '' : trim($_REQUEST['guestname']);
  484. $_REQUEST['email'] = !isset($_REQUEST['email']) ? '' : trim($_REQUEST['email']);
  485. $_REQUEST['guestname'] = htmlspecialchars($_REQUEST['guestname']);
  486. $context['name'] = $_REQUEST['guestname'];
  487. $_REQUEST['email'] = htmlspecialchars($_REQUEST['email']);
  488. $context['email'] = $_REQUEST['email'];
  489. $user_info['name'] = $_REQUEST['guestname'];
  490. }
  491. // Only show the preview stuff if they hit Preview.
  492. if ($really_previewing == true || isset($_REQUEST['xml']))
  493. {
  494. // Set up the preview message and subject and censor them...
  495. $context['preview_message'] = $form_message;
  496. preparsecode($form_message, true);
  497. preparsecode($context['preview_message']);
  498. // Do all bulletin board code tags, with or without smileys.
  499. $context['preview_message'] = parse_bbc($context['preview_message'], isset($_REQUEST['ns']) ? 0 : 1);
  500. if ($form_subject != '')
  501. {
  502. $context['preview_subject'] = $form_subject;
  503. censorText($context['preview_subject']);
  504. censorText($context['preview_message']);
  505. }
  506. else
  507. $context['preview_subject'] = '<em>' . $txt['no_subject'] . '</em>';
  508. // Protect any CDATA blocks.
  509. if (isset($_REQUEST['xml']))
  510. $context['preview_message'] = strtr($context['preview_message'], array(']]>' => ']]]]><![CDATA[>'));
  511. }
  512. // Set up the checkboxes.
  513. $context['notify'] = !empty($_REQUEST['notify']);
  514. $context['use_smileys'] = !isset($_REQUEST['ns']);
  515. $context['icon'] = isset($_REQUEST['icon']) ? preg_replace('~[\./\\\\*\':"<>]~', '', $_REQUEST['icon']) : 'xx';
  516. // Set the destination action for submission.
  517. $context['destination'] = 'post2;start=' . $_REQUEST['start'] . (isset($_REQUEST['msg']) ? ';msg=' . $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id'] : '') . (isset($_REQUEST['poll']) ? ';poll' : '');
  518. $context['submit_label'] = isset($_REQUEST['msg']) ? $txt['save'] : $txt['post'];
  519. // Previewing an edit?
  520. if (isset($_REQUEST['msg']) && !empty($topic))
  521. {
  522. // Get the existing message.
  523. $request = $smcFunc['db_query']('', '
  524. SELECT
  525. m.id_member, m.modified_time, m.smileys_enabled, m.body,
  526. m.poster_name, m.poster_email, m.subject, m.icon, m.approved,
  527. IFNULL(a.size, -1) AS filesize, a.filename, a.id_attach,
  528. a.approved AS attachment_approved, t.id_member_started AS id_member_poster,
  529. m.poster_time
  530. FROM {db_prefix}messages AS m
  531. INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
  532. LEFT JOIN {db_prefix}attachments AS a ON (a.id_msg = m.id_msg AND a.attachment_type = {int:attachment_type})
  533. WHERE m.id_msg = {int:id_msg}
  534. AND m.id_topic = {int:current_topic}',
  535. array(
  536. 'current_topic' => $topic,
  537. 'attachment_type' => 0,
  538. 'id_msg' => $_REQUEST['msg'],
  539. )
  540. );
  541. // The message they were trying to edit was most likely deleted.
  542. /**
  543. * @todo Change this error message?
  544. */
  545. if ($smcFunc['db_num_rows']($request) == 0)
  546. fatal_lang_error('no_board', false);
  547. $row = $smcFunc['db_fetch_assoc']($request);
  548. $attachment_stuff = array($row);
  549. while ($row2 = $smcFunc['db_fetch_assoc']($request))
  550. $attachment_stuff[] = $row2;
  551. $smcFunc['db_free_result']($request);
  552. if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any'))
  553. {
  554. // Give an extra five minutes over the disable time threshold, so they can type - assuming the post is public.
  555. if ($row['approved'] && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time())
  556. fatal_lang_error('modify_post_time_passed', false);
  557. elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_own'))
  558. isAllowedTo('modify_replies');
  559. else
  560. isAllowedTo('modify_own');
  561. }
  562. elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_any'))
  563. isAllowedTo('modify_replies');
  564. else
  565. isAllowedTo('modify_any');
  566. if (!empty($modSettings['attachmentEnable']))
  567. {
  568. $request = $smcFunc['db_query']('', '
  569. SELECT IFNULL(size, -1) AS filesize, filename, id_attach, approved
  570. FROM {db_prefix}attachments
  571. WHERE id_msg = {int:id_msg}
  572. AND attachment_type = {int:attachment_type}',
  573. array(
  574. 'id_msg' => (int) $_REQUEST['msg'],
  575. 'attachment_type' => 0,
  576. )
  577. );
  578. while ($row = $smcFunc['db_fetch_assoc']($request))
  579. {
  580. if ($row['filesize'] <= 0)
  581. continue;
  582. $context['current_attachments'][] = array(
  583. 'name' => htmlspecialchars($row['filename']),
  584. 'id' => $row['id_attach'],
  585. 'approved' => $row['approved'],
  586. );
  587. }
  588. $smcFunc['db_free_result']($request);
  589. }
  590. // Allow moderators to change names....
  591. if (allowedTo('moderate_forum') && !empty($topic))
  592. {
  593. $request = $smcFunc['db_query']('', '
  594. SELECT id_member, poster_name, poster_email
  595. FROM {db_prefix}messages
  596. WHERE id_msg = {int:id_msg}
  597. AND id_topic = {int:current_topic}
  598. LIMIT 1',
  599. array(
  600. 'current_topic' => $topic,
  601. 'id_msg' => (int) $_REQUEST['msg'],
  602. )
  603. );
  604. $row = $smcFunc['db_fetch_assoc']($request);
  605. $smcFunc['db_free_result']($request);
  606. if (empty($row['id_member']))
  607. {
  608. $context['name'] = htmlspecialchars($row['poster_name']);
  609. $context['email'] = htmlspecialchars($row['poster_email']);
  610. }
  611. }
  612. }
  613. // No check is needed, since nothing is really posted.
  614. checkSubmitOnce('free');
  615. }
  616. // Editing a message...
  617. elseif (isset($_REQUEST['msg']) && !empty($topic))
  618. {
  619. $_REQUEST['msg'] = (int) $_REQUEST['msg'];
  620. // Get the existing message.
  621. $request = $smcFunc['db_query']('', '
  622. SELECT
  623. m.id_member, m.modified_time, m.smileys_enabled, m.body,
  624. m.poster_name, m.poster_email, m.subject, m.icon, m.approved,
  625. IFNULL(a.size, -1) AS filesize, a.filename, a.id_attach,
  626. a.approved AS attachment_approved, t.id_member_started AS id_member_poster,
  627. m.poster_time
  628. FROM {db_prefix}messages AS m
  629. INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
  630. LEFT JOIN {db_prefix}attachments AS a ON (a.id_msg = m.id_msg AND a.attachment_type = {int:attachment_type})
  631. WHERE m.id_msg = {int:id_msg}
  632. AND m.id_topic = {int:current_topic}',
  633. array(
  634. 'current_topic' => $topic,
  635. 'attachment_type' => 0,
  636. 'id_msg' => $_REQUEST['msg'],
  637. )
  638. );
  639. // The message they were trying to edit was most likely deleted.
  640. /**
  641. * @todo Change this error message?
  642. */
  643. if ($smcFunc['db_num_rows']($request) == 0)
  644. fatal_lang_error('no_board', false);
  645. $row = $smcFunc['db_fetch_assoc']($request);
  646. $attachment_stuff = array($row);
  647. while ($row2 = $smcFunc['db_fetch_assoc']($request))
  648. $attachment_stuff[] = $row2;
  649. $smcFunc['db_free_result']($request);
  650. if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any'))
  651. {
  652. // Give an extra five minutes over the disable time threshold, so they can type - assuming the post is public.
  653. if ($row['approved'] && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time())
  654. fatal_lang_error('modify_post_time_passed', false);
  655. elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_own'))
  656. isAllowedTo('modify_replies');
  657. else
  658. isAllowedTo('modify_own');
  659. }
  660. elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('modify_any'))
  661. isAllowedTo('modify_replies');
  662. else
  663. isAllowedTo('modify_any');
  664. // When was it last modified?
  665. if (!empty($row['modified_time']))
  666. $context['last_modified'] = timeformat($row['modified_time']);
  667. // Get the stuff ready for the form.
  668. $form_subject = $row['subject'];
  669. $form_message = un_preparsecode($row['body']);
  670. censorText($form_message);
  671. censorText($form_subject);
  672. // Check the boxes that should be checked.
  673. $context['use_smileys'] = !empty($row['smileys_enabled']);
  674. $context['icon'] = $row['icon'];
  675. // Show an "approve" box if the user can approve it, and the message isn't approved.
  676. if (!$row['approved'] && !$context['show_approval'])
  677. $context['show_approval'] = allowedTo('approve_posts');
  678. // Load up 'em attachments!
  679. foreach ($attachment_stuff as $attachment)
  680. {
  681. if ($attachment['filesize'] >= 0 && !empty($modSettings['attachmentEnable']))
  682. $context['current_attachments'][] = array(
  683. 'name' => htmlspecialchars($attachment['filename']),
  684. 'id' => $attachment['id_attach'],
  685. 'approved' => $attachment['attachment_approved'],
  686. );
  687. }
  688. // Allow moderators to change names....
  689. if (allowedTo('moderate_forum') && empty($row['id_member']))
  690. {
  691. $context['name'] = htmlspecialchars($row['poster_name']);
  692. $context['email'] = htmlspecialchars($row['poster_email']);
  693. }
  694. // Set the destinaton.
  695. $context['destination'] = 'post2;start=' . $_REQUEST['start'] . ';msg=' . $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id'] . (isset($_REQUEST['poll']) ? ';poll' : '');
  696. $context['submit_label'] = $txt['save'];
  697. }
  698. // Posting...
  699. else
  700. {
  701. // By default....
  702. $context['use_smileys'] = true;
  703. $context['icon'] = 'xx';
  704. if ($user_info['is_guest'])
  705. {
  706. $context['name'] = isset($_SESSION['guest_name']) ? $_SESSION['guest_name'] : '';
  707. $context['email'] = isset($_SESSION['guest_email']) ? $_SESSION['guest_email'] : '';
  708. }
  709. $context['destination'] = 'post2;start=' . $_REQUEST['start'] . (isset($_REQUEST['poll']) ? ';poll' : '');
  710. $context['submit_label'] = $txt['post'];
  711. // Posting a quoted reply?
  712. if (!empty($topic) && !empty($_REQUEST['quote']))
  713. {
  714. // Make sure they _can_ quote this post, and if so get it.
  715. $request = $smcFunc['db_query']('', '
  716. SELECT m.subject, IFNULL(mem.real_name, m.poster_name) AS poster_name, m.poster_time, m.body
  717. FROM {db_prefix}messages AS m
  718. INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board AND {query_see_board})
  719. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
  720. WHERE m.id_msg = {int:id_msg}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
  721. AND m.approved = {int:is_approved}') . '
  722. LIMIT 1',
  723. array(
  724. 'id_msg' => (int) $_REQUEST['quote'],
  725. 'is_approved' => 1,
  726. )
  727. );
  728. if ($smcFunc['db_num_rows']($request) == 0)
  729. fatal_lang_error('quoted_post_deleted', false);
  730. list ($form_subject, $mname, $mdate, $form_message) = $smcFunc['db_fetch_row']($request);
  731. $smcFunc['db_free_result']($request);
  732. // Add 'Re: ' to the front of the quoted subject.
  733. if (trim($context['response_prefix']) != '' && $smcFunc['strpos']($form_subject, trim($context['response_prefix'])) !== 0)
  734. $form_subject = $context['response_prefix'] . $form_subject;
  735. // Censor the message and subject.
  736. censorText($form_message);
  737. censorText($form_subject);
  738. // But if it's in HTML world, turn them into htmlspecialchar's so they can be edited!
  739. if (strpos($form_message, '[html]') !== false)
  740. {
  741. $parts = preg_split('~(\[/code\]|\[code(?:=[^\]]+)?\])~i', $form_message, -1, PREG_SPLIT_DELIM_CAPTURE);
  742. for ($i = 0, $n = count($parts); $i < $n; $i++)
  743. {
  744. // It goes 0 = outside, 1 = begin tag, 2 = inside, 3 = close tag, repeat.
  745. if ($i % 4 == 0)
  746. $parts[$i] = preg_replace('~\[html\](.+?)\[/html\]~ise', '\'[html]\' . preg_replace(\'~<br\s?/?' . '>~i\', \'&lt;br /&gt;<br />\', \'$1\') . \'[/html]\'', $parts[$i]);
  747. }
  748. $form_message = implode('', $parts);
  749. }
  750. $form_message = preg_replace('~<br ?/?' . '>~i', "\n", $form_message);
  751. // Remove any nested quotes, if necessary.
  752. if (!empty($modSettings['removeNestedQuotes']))
  753. $form_message = preg_replace(array('~\n?\[quote.*?\].+?\[/quote\]\n?~is', '~^\n~', '~\[/quote\]~'), '', $form_message);
  754. // Add a quote string on the front and end.
  755. $form_message = '[quote author=' . $mname . ' link=topic=' . $topic . '.msg' . (int) $_REQUEST['quote'] . '#msg' . (int) $_REQUEST['quote'] . ' date=' . $mdate . ']' . "\n" . rtrim($form_message) . "\n" . '[/quote]';
  756. }
  757. // Posting a reply without a quote?
  758. elseif (!empty($topic) && empty($_REQUEST['quote']))
  759. {
  760. // Get the first message's subject.
  761. $form_subject = $first_subject;
  762. // Add 'Re: ' to the front of the subject.
  763. if (trim($context['response_prefix']) != '' && $form_subject != '' && $smcFunc['strpos']($form_subject, trim($context['response_prefix'])) !== 0)
  764. $form_subject = $context['response_prefix'] . $form_subject;
  765. // Censor the subject.
  766. censorText($form_subject);
  767. $form_message = '';
  768. }
  769. else
  770. {
  771. $form_subject = isset($_GET['subject']) ? $_GET['subject'] : '';
  772. $form_message = '';
  773. }
  774. }
  775. /**
  776. * This won't work if you're posting an event.
  777. */
  778. if (allowedTo('post_attachment') || allowedTo('post_unapproved_attachments'))
  779. {
  780. if (empty($_SESSION['temp_attachments']))
  781. $_SESSION['temp_attachments'] = array();
  782. if (!empty($modSettings['currentAttachmentUploadDir']))
  783. {
  784. if (!is_array($modSettings['attachmentUploadDir']))
  785. $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']);
  786. // Just use the current path for temp files.
  787. $current_attach_dir = $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']];
  788. }
  789. else
  790. $current_attach_dir = $modSettings['attachmentUploadDir'];
  791. // If this isn't a new post, check the current attachments.
  792. if (isset($_REQUEST['msg']))
  793. {
  794. $request = $smcFunc['db_query']('', '
  795. SELECT COUNT(*), SUM(size)
  796. FROM {db_prefix}attachments
  797. WHERE id_msg = {int:id_msg}
  798. AND attachment_type = {int:attachment_type}',
  799. array(
  800. 'id_msg' => (int) $_REQUEST['msg'],
  801. 'attachment_type' => 0,
  802. )
  803. );
  804. list ($quantity, $total_size) = $smcFunc['db_fetch_row']($request);
  805. $smcFunc['db_free_result']($request);
  806. }
  807. else
  808. {
  809. $quantity = 0;
  810. $total_size = 0;
  811. }
  812. $temp_start = 0;
  813. if (!empty($_SESSION['temp_attachments']))
  814. {
  815. if ($context['current_action'] != 'post2' || !empty($_POST['from_qr']))
  816. {
  817. $context['post_error']['messages'][] = $txt['error_temp_attachments'];
  818. $context['error_type'] = 'minor';
  819. }
  820. foreach ($_SESSION['temp_attachments'] as $attachID => $name)
  821. {
  822. $temp_start++;
  823. if (preg_match('~^post_tmp_' . $user_info['id'] . '_\d+$~', $attachID) == 0)
  824. {
  825. unset($_SESSION['temp_attachments'][$attachID]);
  826. continue;
  827. }
  828. if (!empty($_POST['attach_del']) && !in_array($attachID, $_POST['attach_del']))
  829. {
  830. $deleted_attachments = true;
  831. unset($_SESSION['temp_attachments'][$attachID]);
  832. @unlink($current_attach_dir . '/' . $attachID);
  833. continue;
  834. }
  835. $quantity++;
  836. $total_size += filesize($current_attach_dir . '/' . $attachID);
  837. $context['current_attachments'][] = array(
  838. 'name' => htmlspecialchars($name),
  839. 'id' => $attachID,
  840. 'approved' => 1,
  841. );
  842. }
  843. }
  844. if (!empty($_POST['attach_del']))
  845. {
  846. $del_temp = array();
  847. foreach ($_POST['attach_del'] as $i => $dummy)
  848. $del_temp[$i] = (int) $dummy;
  849. foreach ($context['current_attachments'] as $k => $dummy)
  850. if (!in_array($dummy['id'], $del_temp))
  851. {
  852. $context['current_attachments'][$k]['unchecked'] = true;
  853. $deleted_attachments = !isset($deleted_attachments) || is_bool($deleted_attachments) ? 1 : $deleted_attachments + 1;
  854. $quantity--;
  855. }
  856. }
  857. if (!empty($_FILES['attachment']))
  858. foreach ($_FILES['attachment']['tmp_name'] as $n => $dummy)
  859. {
  860. if ($_FILES['attachment']['name'][$n] == '')
  861. continue;
  862. if (!is_uploaded_file($_FILES['attachment']['tmp_name'][$n]) || (@ini_get('open_basedir') == '' && !file_exists($_FILES['attachment']['tmp_name'][$n])))
  863. fatal_lang_error('attach_timeout', 'critical');
  864. if (!empty($modSettings['attachmentSizeLimit']) && $_FILES['attachment']['size'][$n] > $modSettings['attachmentSizeLimit'] * 1024)
  865. fatal_lang_error('file_too_big', false, array($modSettings['attachmentSizeLimit']));
  866. $quantity++;
  867. if (!empty($modSettings['attachmentNumPerPostLimit']) && $quantity > $modSettings['attachmentNumPerPostLimit'])
  868. fatal_lang_error('attachments_limit_per_post', false, array($modSettings['attachmentNumPerPostLimit']));
  869. $total_size += $_FILES['attachment']['size'][$n];
  870. if (!empty($modSettings['attachmentPostLimit']) && $total_size > $modSettings['attachmentPostLimit'] * 1024)
  871. fatal_lang_error('file_too_big', false, array($modSettings['attachmentPostLimit']));
  872. if (!empty($modSettings['attachmentCheckExtensions']))
  873. {
  874. if (!in_array(strtolower(substr(strrchr($_FILES['attachment']['name'][$n], '.'), 1)), explode(',', strtolower($modSettings['attachmentExtensions']))))
  875. fatal_error($_FILES['attachment']['name'][$n] . '.<br />' . $txt['cant_upload_type'] . ' ' . $modSettings['attachmentExtensions'] . '.', false);
  876. }
  877. if (!empty($modSettings['attachmentDirSizeLimit']))
  878. {
  879. // Make sure the directory isn't full.
  880. $dirSize = 0;
  881. $dir = @opendir($current_attach_dir) or fatal_lang_error('cant_access_upload_path', 'critical');
  882. while ($file = readdir($dir))
  883. {
  884. if ($file == '.' || $file == '..')
  885. continue;
  886. if (preg_match('~^post_tmp_\d+_\d+$~', $file) != 0)
  887. {
  888. // Temp file is more than 5 hours old!
  889. if (filemtime($current_attach_dir . '/' . $file) < time() - 18000)
  890. @unlink($current_attach_dir . '/' . $file);
  891. continue;
  892. }
  893. $dirSize += filesize($current_attach_dir . '/' . $file);
  894. }
  895. closedir($dir);
  896. // Too big! Maybe you could zip it or something...
  897. if ($_FILES['attachment']['size'][$n] + $dirSize > $modSettings['attachmentDirSizeLimit'] * 1024)
  898. fatal_lang_error('ran_out_of_space');
  899. }
  900. if (!is_writable($current_attach_dir))
  901. fatal_lang_error('attachments_no_write', 'critical');
  902. $attachID = 'post_tmp_' . $user_info['id'] . '_' . $temp_start++;
  903. $_SESSION['temp_attachments'][$attachID] = basename($_FILES['attachment']['name'][$n]);
  904. $context['current_attachments'][] = array(
  905. 'name' => htmlspecialchars(basename($_FILES['attachment']['name'][$n])),
  906. 'id' => $attachID,
  907. 'approved' => 1,
  908. );
  909. $destName = $current_attach_dir . '/' . $attachID;
  910. if (!move_uploaded_file($_FILES['attachment']['tmp_name'][$n], $destName))
  911. fatal_lang_error('attach_timeout', 'critical');
  912. @chmod($destName, 0644);
  913. }
  914. }
  915. // If we are coming here to make a reply, and someone has already replied... make a special warning message.
  916. if (isset($newRepliesError))
  917. {
  918. $context['post_error']['messages'][] = $newRepliesError == 1 ? $txt['error_new_reply'] : $txt['error_new_replies'];
  919. $context['error_type'] = 'minor';
  920. }
  921. if (isset($oldTopicError))
  922. {
  923. $context['post_error']['messages'][] = sprintf($txt['error_old_topic'], $modSettings['oldTopicDays']);
  924. $context['error_type'] = 'minor';
  925. }
  926. // What are you doing? Posting a poll, modifying, previewing, new post, or reply...
  927. if (isset($_REQUEST['poll']))
  928. $context['page_title'] = $txt['new_poll'];
  929. elseif ($context['make_event'])
  930. $context['page_title'] = $context['event']['id'] == -1 ? $txt['calendar_post_event'] : $txt['calendar_edit'];
  931. elseif (isset($_REQUEST['msg']))
  932. $context['page_title'] = $txt['modify_msg'];
  933. elseif (isset($_REQUEST['subject'], $context['preview_subject']))
  934. $context['page_title'] = $txt['preview'] . ' - ' . strip_tags($context['preview_subject']);
  935. elseif (empty($topic))
  936. $context['page_title'] = $txt['start_new_topic'];
  937. else
  938. $context['page_title'] = $txt['post_reply'];
  939. // Build the link tree.
  940. if (empty($topic))
  941. $context['linktree'][] = array(
  942. 'name' => '<em>' . $txt['start_new_topic'] . '</em>'
  943. );
  944. else
  945. $context['linktree'][] = array(
  946. 'url' => $scripturl . '?topic=' . $topic . '.' . $_REQUEST['start'],
  947. 'name' => $form_subject,
  948. 'extra_before' => '<span' . ($settings['linktree_inline'] ? ' class="smalltext"' : '') . '><strong class="nav">' . $context['page_title'] . ' ( </strong></span>',
  949. 'extra_after' => '<span' . ($settings['linktree_inline'] ? ' class="smalltext"' : '') . '><strong class="nav"> )</strong></span>'
  950. );
  951. // Give wireless a linktree url to the post screen, so that they can switch to full version.
  952. if (WIRELESS)
  953. $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'] : '');
  954. // 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.
  955. /**
  956. * @todo This won't work if you're posting an event.
  957. */
  958. $context['num_allowed_attachments'] = empty($modSettings['attachmentNumPerPostLimit']) ? 50 : min($modSettings['attachmentNumPerPostLimit'] - count($context['current_attachments']) + (isset($deleted_attachments) ? $deleted_attachments : 0), $modSettings['attachmentNumPerPostLimit']);
  959. $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;
  960. $context['can_post_attachment_unapproved'] = allowedTo('post_attachment');
  961. $context['subject'] = addcslashes($form_subject, '"');
  962. $context['message'] = str_replace(array('"', '<', '>', '&nbsp;'), array('&quot;', '&lt;', '&gt;', ' '), $form_message);
  963. // Needed for the editor and message icons.
  964. require_once($sourcedir . '/Subs-Editor.php');
  965. // Now create the editor.
  966. $editorOptions = array(
  967. 'id' => 'message',
  968. 'value' => $context['message'],
  969. 'labels' => array(
  970. 'post_button' => $context['submit_label'],
  971. ),
  972. // add height and width for the editor
  973. 'height' => '175px',
  974. 'width' => '100%',
  975. // We do XML preview here.
  976. 'preview_type' => 2,
  977. );
  978. create_control_richedit($editorOptions);
  979. // Store the ID.
  980. $context['post_box_name'] = $editorOptions['id'];
  981. $context['attached'] = '';
  982. $context['make_poll'] = isset($_REQUEST['poll']);
  983. // Message icons - customized icons are off?
  984. $context['icons'] = getMessageIcons($board);
  985. if (!empty($context['icons']))
  986. $context['icons'][count($context['icons']) - 1]['is_last'] = true;
  987. $context['icon_url'] = '';
  988. for ($i = 0, $n = count($context['icons']); $i < $n; $i++)
  989. {
  990. $context['icons'][$i]['selected'] = $context['icon'] == $context['icons'][$i]['value'];
  991. if ($context['icons'][$i]['selected'])
  992. $context['icon_url'] = $context['icons'][$i]['url'];
  993. }
  994. if (empty($context['icon_url']))
  995. {
  996. $context['icon_url'] = $settings[file_exists($settings['theme_dir'] . '/images/post/' . $context['icon'] . '.gif') ? 'images_url' : 'default_images_url'] . '/post/' . $context['icon'] . '.gif';
  997. array_unshift($context['icons'], array(
  998. 'value' => $context['icon'],
  999. 'name' => $txt['current_icon'],
  1000. 'url' => $context['icon_url'],
  1001. 'is_last' => empty($context['icons']),
  1002. 'selected' => true,
  1003. ));
  1004. }
  1005. if (!empty($topic) && !empty($modSettings['topicSummaryPosts']))
  1006. getTopic();
  1007. // If the user can post attachments prepare the warning labels.
  1008. if ($context['can_post_attachment'])
  1009. {
  1010. $context['allowed_extensions'] = strtr($modSettings['attachmentExtensions'], array(',' => ', '));
  1011. $context['attachment_restrictions'] = array();
  1012. $attachmentRestrictionTypes = array('attachmentNumPerPostLimit', 'attachmentPostLimit', 'attachmentSizeLimit');
  1013. foreach ($attachmentRestrictionTypes as $type)
  1014. if (!empty($modSettings[$type]))
  1015. $context['attachment_restrictions'][] = sprintf($txt['attach_restrict_' . $type], $modSettings[$type]);
  1016. }
  1017. $context['back_to_topic'] = isset($_REQUEST['goback']) || (isset($_REQUEST['msg']) && !isset($_REQUEST['subject']));
  1018. $context['show_additional_options'] = !empty($_POST['additional_options']) || !empty($_SESSION['temp_attachments']) || !empty($deleted_attachments);
  1019. $context['is_new_topic'] = empty($topic);
  1020. $context['is_new_post'] = !isset($_REQUEST['msg']);
  1021. $context['is_first_post'] = $context['is_new_topic'] || (isset($_REQUEST['msg']) && $_REQUEST['msg'] == $id_first_msg);
  1022. // Do we need to show the visual verification image?
  1023. $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));
  1024. if ($context['require_verification'])
  1025. {
  1026. require_once($sourcedir . '/Subs-Editor.php');
  1027. $verificationOptions = array(
  1028. 'id' => 'post',
  1029. );
  1030. $context['require_verification'] = create_control_verification($verificationOptions);
  1031. $context['visual_verification_id'] = $verificationOptions['id'];
  1032. }
  1033. // If they came from quick reply, and have to enter verification details, give them some notice.
  1034. if (!empty($_REQUEST['from_qr']) && !empty($context['require_verification']))
  1035. {
  1036. $context['post_error']['messages'][] = $txt['enter_verification_details'];
  1037. $context['error_type'] = 'minor';
  1038. }
  1039. // WYSIWYG only works if BBC is enabled
  1040. $modSettings['disable_wysiwyg'] = !empty($modSettings['disable_wysiwyg']) || empty($modSettings['enableBBC']);
  1041. // Register this form in the session variables.
  1042. checkSubmitOnce('register');
  1043. // Finally, load the template.
  1044. if (WIRELESS && WIRELESS_PROTOCOL != 'wap')
  1045. $context['sub_template'] = WIRELESS_PROTOCOL . '_post';
  1046. elseif (!isset($_REQUEST['xml']))
  1047. loadTemplate('Post');
  1048. }
  1049. function Post2()
  1050. {
  1051. global $board, $topic, $txt, $modSettings, $sourcedir, $context;
  1052. global $user_info, $board_info, $options, $smcFunc;
  1053. // Sneaking off, are we?
  1054. if (empty($_POST) && empty($topic))
  1055. redirectexit('action=post;board=' . $board . '.0');
  1056. elseif (empty($_POST) && !empty($topic))
  1057. redirectexit('action=post;topic=' . $topic . '.0');
  1058. // No need!
  1059. $context['robot_no_index'] = true;
  1060. // If we came from WYSIWYG then turn it back into BBC regardless.
  1061. if (!empty($_REQUEST['message_mode']) && isset($_REQUEST['message']))
  1062. {
  1063. require_once($sourcedir . '/Subs-Editor.php');
  1064. $_REQUEST['message'] = html_to_bbc($_REQUEST['message']);
  1065. // We need to unhtml it now as it gets done shortly.
  1066. $_REQUEST['message'] = un_htmlspecialchars($_REQUEST['message']);
  1067. // We need this for everything else.
  1068. $_POST['message'] = $_REQUEST['message'];
  1069. }
  1070. // Previewing? Go back to start.
  1071. if (isset($_REQUEST['preview']))
  1072. return Post();
  1073. // Prevent double submission of this form.
  1074. checkSubmitOnce('check');
  1075. // No errors as yet.
  1076. $post_errors = array();
  1077. // If the session has timed out, let the user re-submit their form.
  1078. if (checkSession('post', '', false) != '')
  1079. $post_errors[] = 'session_timeout';
  1080. // Wrong verification code?
  1081. 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)))
  1082. {
  1083. require_once($sourcedir . '/Subs-Editor.php');
  1084. $verificationOptions = array(
  1085. 'id' => 'post',
  1086. );
  1087. $context['require_verification'] = create_control_verification($verificationOptions, true);
  1088. if (is_array($context['require_verification']))
  1089. $post_errors = array_merge($post_errors, $context['require_verification']);
  1090. }
  1091. require_once($sourcedir . '/Subs-Post.php');
  1092. loadLanguage('Post');
  1093. // If this isn't a new topic load the topic info that we need.
  1094. if (!empty($topic))
  1095. {
  1096. $request = $smcFunc['db_query']('', '
  1097. SELECT locked, is_sticky, id_poll, approved, id_first_msg, id_last_msg, id_member_started, id_board
  1098. FROM {db_prefix}topics
  1099. WHERE id_topic = {int:current_topic}
  1100. LIMIT 1',
  1101. array(
  1102. 'current_topic' => $topic,
  1103. )
  1104. );
  1105. $topic_info = $smcFunc['db_fetch_assoc']($request);
  1106. $smcFunc['db_free_result']($request);
  1107. // Though the topic should be there, it might have vanished.
  1108. if (!is_array($topic_info))
  1109. fatal_lang_error('topic_doesnt_exist');
  1110. // Did this topic suddenly move? Just checking...
  1111. if ($topic_info['id_board'] != $board)
  1112. fatal_lang_error('not_a_topic');
  1113. }
  1114. // Replying to a topic?
  1115. if (!empty($topic) && !isset($_REQUEST['msg']))
  1116. {
  1117. // Don't allow a post if it's locked.
  1118. if ($topic_info['locked'] != 0 && !allowedTo('moderate_board'))
  1119. fatal_lang_error('topic_locked', false);
  1120. // Sorry, multiple polls aren't allowed... yet. You should stop giving me ideas :P.
  1121. if (isset($_REQUEST['poll']) && $topic_info['id_poll'] > 0)
  1122. unset($_REQUEST['poll']);
  1123. // Do the permissions and approval stuff...
  1124. $becomesApproved = true;
  1125. if ($topic_info['id_member_started'] != $user_info['id'])
  1126. {
  1127. if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_any') && !allowedTo('post_reply_any'))
  1128. $becomesApproved = false;
  1129. else
  1130. isAllowedTo('post_reply_any');
  1131. }
  1132. elseif (!allowedTo('post_reply_any'))
  1133. {
  1134. if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_own') && !allowedTo('post_reply_own'))
  1135. $becomesApproved = false;
  1136. else
  1137. isAllowedTo('post_reply_own');
  1138. }
  1139. if (isset($_POST['lock']))
  1140. {
  1141. // Nothing is changed to the lock.
  1142. if ((empty($topic_info['locked']) && empty($_POST['lock'])) || (!empty($_POST['lock']) && !empty($topic_info['locked'])))
  1143. unset($_POST['lock']);
  1144. // You're have no permission to lock this topic.
  1145. elseif (!allowedTo(array('lock_any', 'lock_own')) || (!allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']))
  1146. unset($_POST['lock']);
  1147. // You are allowed to (un)lock your own topic only.
  1148. elseif (!allowedTo('lock_any'))
  1149. {
  1150. // You cannot override a moderator lock.
  1151. if ($topic_info['locked'] == 1)
  1152. unset($_POST['lock']);
  1153. else
  1154. $_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
  1155. }
  1156. // Hail mighty moderator, (un)lock this topic immediately.
  1157. else
  1158. $_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
  1159. }
  1160. // So you wanna (un)sticky this...let's see.
  1161. if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || $_POST['sticky'] == $topic_info['is_sticky'] || !allowedTo('make_sticky')))
  1162. unset($_POST['sticky']);
  1163. // If the number of replies has changed, if the setting is enabled, go back to Post() - which handles the error.
  1164. if (empty($options['no_new_reply_warning']) && isset($_POST['last_msg']) && $topic_info['id_last_msg'] > $_POST['last_msg'])
  1165. {
  1166. $_REQUEST['preview'] = true;
  1167. return Post();
  1168. }
  1169. $posterIsGuest = $user_info['is_guest'];
  1170. }
  1171. // Posting a new topic.
  1172. elseif (empty($topic))
  1173. {
  1174. // Now don't be silly, new topics will get their own id_msg soon enough.
  1175. unset($_REQUEST['msg'], $_POST['msg'], $_GET['msg']);
  1176. // Do like, the permissions, for safety and stuff...
  1177. $becomesApproved = true;
  1178. if ($modSettings['postmod_active'] && !allowedTo('post_new') && allowedTo('post_unapproved_topics'))
  1179. $becomesApproved = false;
  1180. else
  1181. isAllowedTo('post_new');
  1182. if (isset($_POST['lock']))
  1183. {
  1184. // New topics are by default not locked.
  1185. if (empty($_POST['lock']))
  1186. unset($_POST['lock']);
  1187. // Besides, you need permission.
  1188. elseif (!allowedTo(array('lock_any', 'lock_own')))
  1189. unset($_POST['lock']);
  1190. // A moderator-lock (1) can override a user-lock (2).
  1191. else
  1192. $_POST['lock'] = allowedTo('lock_any') ? 1 : 2;
  1193. }
  1194. if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || empty($_POST['sticky']) || !allowedTo('make_sticky')))
  1195. unset($_POST['sticky']);
  1196. $posterIsGuest = $user_info['is_guest'];
  1197. }
  1198. // Modifying an existing message?
  1199. elseif (isset($_REQUEST['msg']) && !empty($topic))
  1200. {
  1201. $_REQUEST['msg'] = (int) $_REQUEST['msg'];
  1202. $request = $smcFunc['db_query']('', '
  1203. SELECT id_member, poster_name, poster_email, poster_time, approved
  1204. FROM {db_prefix}messages
  1205. WHERE id_msg = {int:id_msg}
  1206. LIMIT 1',
  1207. array(
  1208. 'id_msg' => $_REQUEST['msg'],
  1209. )
  1210. );
  1211. if ($smcFunc['db_num_rows']($request) == 0)
  1212. fatal_lang_error('cant_find_messages', false);
  1213. $row = $smcFunc['db_fetch_assoc']($request);
  1214. $smcFunc['db_free_result']($request);
  1215. if (!empty($topic_info['locked']) && !allowedTo('moderate_board'))
  1216. fatal_lang_error('topic_locked', false);
  1217. if (isset($_POST['lock']))
  1218. {
  1219. // Nothing changes to the lock status.
  1220. if ((empty($_POST['lock']) && empty($topic_info['locked'])) || (!empty($_POST['lock']) && !empty($topic_info['locked'])))
  1221. unset($_POST['lock']);
  1222. // You're simply not allowed to (un)lock this.
  1223. elseif (!allowedTo(array('lock_any', 'lock_own')) || (!allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']))
  1224. unset($_POST['lock']);
  1225. // You're only allowed to lock your own topics.
  1226. elseif (!allowedTo('lock_any'))
  1227. {
  1228. // You're not allowed to break a moderator's lock.
  1229. if ($topic_info['locked'] == 1)
  1230. unset($_POST['lock']);
  1231. // Lock it with a soft lock or unlock it.
  1232. else
  1233. $_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
  1234. }
  1235. // You must be the moderator.
  1236. else
  1237. $_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
  1238. }
  1239. // Change the sticky status of this topic?
  1240. if (isset($_POST['sticky']) && (!allowedTo('make_sticky') || $_POST['sticky'] == $topic_info['is_sticky']))
  1241. unset($_POST['sticky']);
  1242. if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any'))
  1243. {
  1244. if ((!$modSettings['postmod_active'] || $row['approved']) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time())
  1245. fatal_lang_error('modify_post_time_passed', false);
  1246. elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_own'))
  1247. isAllowedTo('modify_replies');
  1248. else
  1249. isAllowedTo('modify_own');
  1250. }
  1251. elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_any'))
  1252. {
  1253. isAllowedTo('modify_replies');
  1254. // If you're modifying a reply, I say it better be logged...
  1255. $moderationAction = true;
  1256. }
  1257. else
  1258. {
  1259. isAllowedTo('modify_any');
  1260. // Log it, assuming you're not modifying your own post.
  1261. if ($row['id_member'] != $user_info['id'])
  1262. $moderationAction = true;
  1263. }
  1264. $posterIsGuest = empty($row['id_member']);
  1265. // Can they approve it?
  1266. $can_approve = allowedTo('approve_posts');
  1267. $becomesApproved = $modSettings['postmod_active'] ? ($can_approve && !$row['approved'] ? (!empty($_REQUEST['approve']) ? 1 : 0) : $row['approved']) : 1;
  1268. $approve_has_changed = $row['approved'] != $becomesApproved;
  1269. if (!allowedTo('moderate_forum') || !$posterIsGuest)
  1270. {
  1271. $_POST['guestname'] = $row['poster_name'];
  1272. $_POST['email'] = $row['poster_email'];
  1273. }
  1274. }
  1275. // If the poster is a guest evaluate the legality of name and email.
  1276. if ($posterIsGuest)
  1277. {
  1278. $_POST['guestname'] = !isset($_POST['guestname']) ? '' : trim($_POST['guestname']);
  1279. $_POST['email'] = !isset($_POST['email']) ? '' : trim($_POST['email']);
  1280. if ($_POST['guestname'] == '' || $_POST['guestname'] == '_')
  1281. $post_errors[] = 'no_name';
  1282. if ($smcFunc['strlen']($_POST['guestname']) > 25)
  1283. $post_errors[] = 'long_name';
  1284. if (empty($modSettings['guest_post_no_email']))
  1285. {
  1286. // Only check if they changed it!
  1287. if (!isset($row) || $row['poster_email'] != $_POST['email'])
  1288. {
  1289. if (!allowedTo('moderate_forum') && (!isset($_POST['email']) || $_POST['email'] == ''))
  1290. $post_errors[] = 'no_email';
  1291. if (!allowedTo('moderate_forum') && preg_match('~^[0-9A-Za-z=_+\-/][0-9A-Za-z=_\'+\-/\.]*@[\w\-]+(\.[\w\-]+)*(\.[\w]{2,6})$~', $_POST['email']) == 0)
  1292. $post_errors[] = 'bad_email';
  1293. }
  1294. // Now make sure this email address is not banned from posting.
  1295. isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt['guest_title']));
  1296. }
  1297. // In case they are making multiple posts this visit, help them along by storing their name.
  1298. if (empty($post_errors))
  1299. {
  1300. $_SESSION['guest_name'] = $_POST['guestname'];
  1301. $_SESSION['guest_email'] = $_POST['email'];
  1302. }
  1303. }
  1304. // Check the subject and message.
  1305. if (!isset($_POST['subject']) || $smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['subject'])) === '')
  1306. $post_errors[] = 'no_subject';
  1307. if (!isset($_POST['message']) || $smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['message']), ENT_QUOTES) === '')
  1308. $post_errors[] = 'no_message';
  1309. elseif (!empty($modSettings['max_messageLength']) && $smcFunc['strlen']($_POST['message']) > $modSettings['max_messageLength'])
  1310. $post_errors[] = 'long_message';
  1311. else
  1312. {
  1313. // Prepare the message a bit for some additional testing.
  1314. $_POST['message'] = $smcFunc['htmlspecialchars']($_POST['message'], ENT_QUOTES);
  1315. // Preparse code. (Zef)
  1316. if ($user_info['is_guest'])
  1317. $user_info['name'] = $_POST['guestname'];
  1318. preparsecode($_POST['message']);
  1319. // Let's see if there's still some content left without the tags.
  1320. if ($smcFunc['htmltrim'](strip_tags(parse_bbc($_POST['message'], false), '<img>')) === '' && (!allowedTo('admin_forum') || strpos($_POST['message'], '[html]') === false))
  1321. $post_errors[] = 'no_message';
  1322. }
  1323. if (isset($_POST['calendar']) && !isset($_REQUEST['deleteevent']) && $smcFunc['htmltrim']($_POST['evtitle']) === '')
  1324. $post_errors[] = 'no_event';
  1325. // You are not!
  1326. if (isset($_POST['message']) && strtolower($_POST['message']) == 'i am the administrator.' && !$user_info['is_admin'])
  1327. fatal_error('Knave! Masquerader! Charlatan!', false);
  1328. // Validate the poll...
  1329. if (isset($_REQUEST['poll']) && $modSettings['pollMode'] == '1')
  1330. {
  1331. if (!empty($topic) && !isset($_REQUEST['msg']))
  1332. fatal_lang_error('no_access', false);
  1333. // This is a new topic... so it's a new poll.
  1334. if (empty($topic))
  1335. isAllowedTo('poll_post');
  1336. // Can you add to your own topics?
  1337. elseif ($user_info['id'] == $topic_info['id_member_started'] && !allowedTo('poll_add_any'))
  1338. isAllowedTo('poll_add_own');
  1339. // Can you add polls to any topic, then?
  1340. else
  1341. isAllowedTo('poll_add_any');
  1342. if (!isset($_POST['question']) || trim($_POST['question']) == '')
  1343. $post_errors[] = 'no_question';
  1344. $_POST['options'] = empty($_POST['options']) ? array() : htmltrim__recursive($_POST['options']);
  1345. // Get rid of empty ones.
  1346. foreach ($_POST['options'] as $k => $option)
  1347. if ($option == '')
  1348. unset($_POST['options'][$k], $_POST['options'][$k]);
  1349. // What are you going to vote between with one choice?!?
  1350. if (count($_POST['options']) < 2)
  1351. $post_errors[] = 'poll_few';
  1352. }
  1353. if ($posterIsGuest)
  1354. {
  1355. // If user is a guest, make sure the chosen name isn't taken.
  1356. require_once($sourcedir . '/Subs-Members.php');
  1357. if (isReservedName($_POST['guestname'], 0, true, false) && (!isset($row['poster_name']) || $_POST['guestname'] != $row['poster_name']))
  1358. $post_errors[] = 'bad_name';
  1359. }
  1360. // If the user isn't a guest, get his or her name and email.
  1361. elseif (!isset($_REQUEST['msg']))
  1362. {
  1363. $_POST['guestname'] = $user_info['username'];
  1364. $_POST['email'] = $user_info['email'];
  1365. }
  1366. // Any mistakes?
  1367. if (!empty($post_errors))
  1368. {
  1369. loadLanguage('Errors');
  1370. // Previewing.
  1371. $_REQUEST['preview'] = true;
  1372. $context['post_error'] = array('messages' => array());
  1373. foreach ($post_errors as $post_error)
  1374. {
  1375. $context['post_error'][$post_error] = true;
  1376. if ($post_error == 'long_message')
  1377. $txt['error_' . $post_error] = sprintf($txt['error_' . $post_error], $modSettings['max_messageLength']);
  1378. $context['post_error']['messages'][] = $txt['error_' . $post_error];
  1379. }
  1380. return Post();
  1381. }
  1382. // Make sure the user isn't spamming the board.
  1383. if (!isset($_REQUEST['msg']))
  1384. spamProtection('post');
  1385. // At about this point, we're posting and that's that.
  1386. ignore_user_abort(true);
  1387. @set_time_limit(300);
  1388. // Add special html entities to the subject, name, and email.
  1389. $_POST['subject'] = strtr($smcFunc['htmlspecialchars']($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
  1390. $_POST['guestname'] = htmlspecialchars($_POST['guestname']);
  1391. $_POST['email'] = htmlspecialchars($_POST['email']);
  1392. // At this point, we want to make sure the subject isn't too long.
  1393. if ($smcFunc['strlen']($_POST['subject']) > 100)
  1394. $_POST['subject'] = $smcFunc['substr']($_POST['subject'], 0, 100);
  1395. // Make the poll...
  1396. if (isset($_REQUEST['poll']))
  1397. {
  1398. // Make sure that the user has not entered a ridiculous number of options..
  1399. if (empty($_POST['poll_max_votes']) || $_POST['poll_max_votes'] <= 0)
  1400. $_POST['poll_max_votes'] = 1;
  1401. elseif ($_POST['poll_max_votes'] > count($_POST['options']))
  1402. $_POST['poll_max_votes'] = count($_POST['options']);
  1403. else
  1404. $_POST['poll_max_votes'] = (int) $_POST['poll_max_votes'];
  1405. $_POST['poll_expire'] = (int) $_POST['poll_expire'];
  1406. $_POST['poll_expire'] = $_POST['poll_expire'] > 9999 ? 9999 : ($_POST['poll_expire'] < 0 ? 0 : $_POST['poll_expire']);
  1407. // Just set it to zero if it's not there..
  1408. if (!isset($_POST['poll_hide']))
  1409. $_POST['poll_hide'] = 0;
  1410. else
  1411. $_POST['poll_hide'] = (int) $_POST['poll_hide'];
  1412. $_POST['poll_change_vote'] = isset($_POST['poll_change_vote']) ? 1 : 0;
  1413. $_POST['poll_guest_vote'] = isset($_POST['poll_guest_vote']) ? 1 : 0;
  1414. // Make sure guests are actually allowed to vote generally.
  1415. if ($_POST['poll_guest_vote'])
  1416. {
  1417. require_once($sourcedir . '/Subs-Members.php');
  1418. $allowedVoteGroups = groupsAllowedTo('poll_vote', $board);
  1419. if (!in_array(-1, $allowedVoteGroups['allowed']))
  1420. $_POST['poll_guest_vote'] = 0;
  1421. }
  1422. // If the user tries to set the poll too far in advance, don't let them.
  1423. if (!empty($_POST['poll_expire']) && $_POST['poll_expire'] < 1)
  1424. fatal_lang_error('poll_range_error', false);
  1425. // Don't allow them to select option 2 for hidden results if it's not time limited.
  1426. elseif (empty($_POST['poll_expire']) && $_POST['poll_hide'] == 2)
  1427. $_POST['poll_hide'] = 1;
  1428. // Clean up the question and answers.
  1429. $_POST['question'] = htmlspecialchars($_POST['question']);
  1430. $_POST['question'] = $smcFunc['truncate']($_POST['question'], 255);
  1431. $_POST['question'] = preg_replace('~&amp;#(\d{4,5}|[2-9]\d{2,4}|1[2-9]\d);~', '&#$1;', $_POST['question']);
  1432. $_POST['options'] = htmlspecialchars__recursive($_POST['options']);
  1433. }
  1434. // Check if they are trying to delete any current attachments....
  1435. if (isset($_REQUEST['msg'], $_POST['attach_del']) && (allowedTo('post_attachment') || ($modSettings['postmod_active'] && allowedTo('post_unapproved_attachments'))))
  1436. {
  1437. // @todo check attach_del; this will be executed when:
  1438. // modify a post with attachments; try to remove one, but receive an error
  1439. // (i.e. body empty); then check back the attachment
  1440. $del_temp = array();
  1441. foreach ($_POST['attach_del'] as $i => $dummy)
  1442. $del_temp[$i] = (int) $dummy;
  1443. require_once($sourcedir . '/ManageAttachments.php');
  1444. $attachmentQuery = array(
  1445. 'attachment_type' => 0,
  1446. 'id_msg' => (int) $_REQUEST['msg'],
  1447. 'not_id_attach' => $del_temp,
  1448. );
  1449. removeAttachments($attachmentQuery);
  1450. }
  1451. // ...or attach a new file...
  1452. if (isset($_FILES['attachment']['name']) || (!empty($_SESSION['temp_attachments']) && empty($_POST['from_qr'])))
  1453. {
  1454. // Verify they can post them!
  1455. if (!$modSettings['postmod_active'] || !allowedTo('post_unapproved_attachments'))
  1456. isAllowedTo('post_attachment');
  1457. // Make sure we're uploading to the right place.
  1458. if (!empty($modSettings['currentAttachmentUploadDir']))
  1459. {
  1460. if (!is_array($modSettings['attachmentUploadDir']))
  1461. $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']);
  1462. // The current directory, of course!
  1463. $current_attach_dir = $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']];
  1464. }
  1465. else
  1466. $current_attach_dir = $modSettings['attachmentUploadDir'];
  1467. // If this isn't a new post, check the current attachments.
  1468. if (isset($_REQUEST['msg']))
  1469. {
  1470. $request = $smcFunc['db_query']('', '
  1471. SELECT COUNT(*), SUM(size)
  1472. FROM {db_prefix}attachments
  1473. WHERE id_msg = {int:id_msg}
  1474. AND attachment_type = {int:attachment_type}',
  1475. array(
  1476. 'id_msg' => (int) $_REQUEST['msg'],
  1477. 'attachment_type' => 0,
  1478. )
  1479. );
  1480. list ($quantity, $total_size) = $smcFunc['db_fetch_row']($request);
  1481. $smcFunc['db_free_result']($request);
  1482. }
  1483. else
  1484. {
  1485. $quantity = 0;
  1486. $total_size = 0;
  1487. }
  1488. if (!empty($_SESSION['temp_attachments']))
  1489. foreach ($_SESSION['temp_attachments'] as $attachID => $name)
  1490. {
  1491. if (preg_match('~^post_tmp_' . $user_info['id'] . '_\d+$~', $attachID) == 0)
  1492. continue;
  1493. if (!empty($_POST['attach_del']) && !in_array($attachID, $_POST['attach_del']))
  1494. {
  1495. unset($_SESSION['temp_attachments'][$attachID]);
  1496. @unlink($current_attach_dir . '/' . $attachID);
  1497. continue;
  1498. }
  1499. $_FILES['attachment']['tmp_name'][] = $attachID;
  1500. $_FILES['attachment']['name'][] = $name;
  1501. $_FILES['attachment']['size'][] = filesize($current_attach_dir . '/' . $attachID);
  1502. list ($_FILES['attachment']['width'][], $_FILES['attachment']['height'][]) = @getimagesize($current_attach_dir . '/' . $attachID);
  1503. unset($_SESSION['temp_attachments'][$attachID]);
  1504. }
  1505. if (!isset($_FILES['attachment']['name']))
  1506. $_FILES['attachment']['tmp_name'] = array();
  1507. $attachIDs = array();
  1508. foreach ($_FILES['attachment']['tmp_name'] as $n => $dummy)
  1509. {
  1510. if ($_FILES['attachment']['name'][$n] == '')
  1511. continue;
  1512. // Have we reached the maximum number of files we are allowed?
  1513. $quantity++;
  1514. if (!empty($modSettings['attachmentNumPerPostLimit']) && $quantity > $modSettings['attachmentNumPerPostLimit'])
  1515. {
  1516. checkSubmitOnce('free');
  1517. fatal_lang_error('attachments_limit_per_post', false, array($modSettings['attachmentNumPerPostLimit']));
  1518. }
  1519. // Check the total upload size for this post...
  1520. $total_size += $_FILES['attachment']['size'][$n];
  1521. if (!empty($modSettings['attachmentPostLimit']) && $total_size > $modSettings['attachmentPostLimit'] * 1024)
  1522. {
  1523. checkSubmitOnce('free');
  1524. fatal_lang_error('file_too_big', false, array($modSettings['attachmentPostLimit']));
  1525. }
  1526. $attachmentOptions = array(
  1527. 'post' => isset($_REQUEST['msg']) ? $_REQUEST['msg'] : 0,
  1528. 'poster' => $user_info['id'],
  1529. 'name' => $_FILES['attachment']['name'][$n],
  1530. 'tmp_name' => $_FILES['attachment']['tmp_name'][$n],
  1531. 'size' => $_FILES['attachment']['size'][$n],
  1532. 'approved' => !$modSettings['postmod_active'] || allowedTo('post_attachment'),
  1533. );
  1534. if (createAttachment($attachmentOptions))
  1535. {
  1536. $attachIDs[] = $attachmentOptions['id'];
  1537. if (!empty($attachmentOptions['thumb']))
  1538. $attachIDs[] = $attachmentOptions['thumb'];
  1539. }
  1540. else
  1541. {
  1542. if (in_array('could_not_upload', $attachmentOptions['errors']))
  1543. {
  1544. checkSubmitOnce('free');
  1545. fatal_lang_error('attach_timeout', 'critical');
  1546. }
  1547. if (in_array('too_large', $attachmentOptions['errors']))
  1548. {
  1549. checkSubmitOnce('free');
  1550. fatal_lang_error('file_too_big', false, array($modSettings['attachmentSizeLimit']));
  1551. }
  1552. if (in_array('bad_extension', $attachmentOptions['errors']))
  1553. {
  1554. checkSubmitOnce('free');
  1555. fatal_error($attachmentOptions['name'] . '.<br />' . $txt['cant_upload_type'] . ' ' . $modSettings['attachmentExtensions'] . '.', false);
  1556. }
  1557. if (in_array('directory_full', $attachmentOptions['errors']))
  1558. {
  1559. checkSubmitOnce('free');
  1560. fatal_lang_error('ran_out_of_space', 'critical');
  1561. }
  1562. if (in_array('bad_filename', $attachmentOptions['errors']))
  1563. {
  1564. checkSubmitOnce('free');
  1565. fatal_error(basename($attachmentOptions['name']) . '.<br />' . $txt['restricted_filename'] . '.', 'critical');
  1566. }
  1567. if (in_array('taken_filename', $attachmentOptions['errors']))
  1568. {
  1569. checkSubmitOnce('free');
  1570. fatal_lang_error('filename_exists');
  1571. }
  1572. if (in_array('bad_attachment', $attachmentOptions['errors']))
  1573. {
  1574. checkSubmitOnce('free');
  1575. fatal_lang_error('bad_attachment');
  1576. }
  1577. }
  1578. }
  1579. }
  1580. // Make the poll...
  1581. if (isset($_REQUEST['poll']))
  1582. {
  1583. // Create the poll.
  1584. $smcFunc['db_insert']('',
  1585. '{db_prefix}polls',
  1586. array(
  1587. 'question' => 'string-255', 'hide_results' => 'int', 'max_votes' => 'int', 'expire_time' => 'int', 'id_member' => 'int',
  1588. 'poster_name' => 'string-255', 'change_vote' => 'int', 'guest_vote' => 'int'
  1589. ),
  1590. array(
  1591. $_POST['question'], $_POST['poll_hide'], $_POST['poll_max_votes'], (empty($_POST['poll_expire']) ? 0 : time() + $_POST['poll_expire'] * 3600 * 24), $user_info['id'],
  1592. $_POST['guestname'], $_POST['poll_change_vote'], $_POST['poll_guest_vote'],
  1593. ),
  1594. array('id_poll')
  1595. );
  1596. $id_poll = $smcFunc['db_insert_id']('{db_prefix}polls', 'id_poll');
  1597. // Create each answer choice.
  1598. $i = 0;
  1599. $pollOptions = array();
  1600. foreach ($_POST['options'] as $option)
  1601. {
  1602. $pollOptions[] = array($id_poll, $i, $option);
  1603. $i++;
  1604. }
  1605. $smcFunc['db_insert']('insert',
  1606. '{db_prefix}poll_choices',
  1607. array('id_poll' => 'int', 'id_choice' => 'int', 'label' => 'string-255'),
  1608. $pollOptions,
  1609. array('id_poll', 'id_choice')
  1610. );
  1611. }
  1612. else
  1613. $id_poll = 0;
  1614. // Creating a new topic?
  1615. $newTopic = empty($_REQUEST['msg']) && empty($topic);
  1616. $_POST['icon'] = !empty($attachIDs) && $_POST['icon'] == 'xx' ? 'clip' : $_POST['icon'];
  1617. // Collect all parameters for the creation or modification of a post.
  1618. $msgOptions = array(
  1619. 'id' => empty($_REQUEST['msg']) ? 0 : (int) $_REQUEST['msg'],
  1620. 'subject' => $_POST['subject'],
  1621. 'body' => $_POST['message'],
  1622. 'icon' => preg_replace('~[\./\\\\*:"\'<>]~', '', $_POST['icon']),
  1623. 'smileys_enabled' => !isset($_POST['ns']),
  1624. 'attachments' => empty($attachIDs) ? array() : $attachIDs,
  1625. 'approved' => $becomesApproved,
  1626. );
  1627. $topicOptions = array(
  1628. 'id' => empty($topic) ? 0 : $topic,
  1629. 'board' => $board,
  1630. 'poll' => isset($_REQUEST['poll']) ? $id_poll : null,
  1631. 'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null,
  1632. 'sticky_mode' => isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics']) ? (int) $_POST['sticky'] : null,
  1633. 'mark_as_read' => true,
  1634. 'is_approved' => !$modSettings['postmod_active'] || empty($topic) || !empty($board_info['cur_topic_approved']),
  1635. );
  1636. $posterOptions = array(
  1637. 'id' => $user_info['id'],
  1638. 'name' => $_POST['guestname'],
  1639. 'email' => $_POST['email'],
  1640. 'update_post_count' => !$user_info['is_guest'] && !isset($_REQUEST['msg']) && $board_info['posts_count'],
  1641. );
  1642. // This is an already existing message. Edit it.
  1643. if (!empty($_REQUEST['msg']))
  1644. {
  1645. // Have admins allowed people to hide their screwups?
  1646. if (time() - $row['poster_time'] > $modSettings['edit_wait_time'] || $user_info['id'] != $row['id_member'])
  1647. {
  1648. $msgOptions['modify_time'] = time();
  1649. $msgOptions['modify_name'] = $user_info['name'];
  1650. }
  1651. // This will save some time...
  1652. if (empty($approve_has_changed))
  1653. unset($msgOptions['approved']);
  1654. modifyPost($msgOptions, $topicOptions, $posterOptions);
  1655. }
  1656. // This is a new topic or an already existing one. Save it.
  1657. else
  1658. {
  1659. createPost($msgOptions, $topicOptions, $posterOptions);
  1660. if (isset($topicOptions['id']))
  1661. $topic = $topicOptions['id'];
  1662. }
  1663. // Editing or posting an event?
  1664. if (isset($_POST['calendar']) && (!isset($_REQUEST['eventid']) || $_REQUEST['eventid'] == -1))
  1665. {
  1666. require_once($sourcedir . '/Subs-Calendar.php');
  1667. // Make sure they can link an event to this post.
  1668. canLinkEvent();
  1669. // Insert the event.
  1670. $eventOptions = array(
  1671. 'board' => $board,
  1672. 'topic' => $topic,
  1673. 'title' => $_POST['evtitle'],
  1674. 'member' => $user_info['id'],
  1675. 'start_date' => sprintf('%04d-%02d-%02d', $_POST['year'], $_POST['month'], $_POST['day']),
  1676. 'span' => isset($_POST['span']) && $_POST['span'] > 0 ? min((int) $modSettings['cal_maxspan'], (int) $_POST['span'] - 1) : 0,
  1677. );
  1678. insertEvent($eventOptions);
  1679. }
  1680. elseif (isset($_POST['calendar']))
  1681. {
  1682. $_REQUEST['eventid'] = (int) $_REQUEST['eventid'];
  1683. // Validate the post...
  1684. require_once($sourcedir . '/Subs-Calendar.php');
  1685. validateEventPost();
  1686. // If you're not allowed to edit any events, you have to be the poster.
  1687. if (!allowedTo('calendar_edit_any'))
  1688. {
  1689. // Get the event's poster.
  1690. $request = $smcFunc['db_query']('', '
  1691. SELECT id_member
  1692. FROM {db_prefix}calendar
  1693. WHERE id_event = {int:id_event}',
  1694. array(
  1695. 'id_event' => $_REQUEST['eventid'],
  1696. )
  1697. );
  1698. $row2 = $smcFunc['db_fetch_assoc']($request);
  1699. $smcFunc['db_free_result']($request);
  1700. // Silly hacker, Trix are for kids. ...probably trademarked somewhere, this is FAIR USE! (parody...)
  1701. isAllowedTo('calendar_edit_' . ($row2['id_member'] == $user_info['id'] ? 'own' : 'any'));
  1702. }
  1703. // Delete it?
  1704. if (isset($_REQUEST['deleteevent']))
  1705. $smcFunc['db_query']('', '
  1706. DELETE FROM {db_prefix}calendar
  1707. WHERE id_event = {int:id_event}',
  1708. array(
  1709. 'id_event' => $_REQUEST['eventid'],
  1710. )
  1711. );
  1712. // ... or just update it?
  1713. else
  1714. {
  1715. $span = !empty($modSettings['cal_allowspan']) && !empty($_REQUEST['span']) ? min((int) $modSettings['cal_maxspan'], (int) $_REQUEST['span'] - 1) : 0;
  1716. $start_time = mktime(0, 0, 0, (int) $_REQUEST['month'], (int) $_REQUEST['day'], (int) $_REQUEST['year']);
  1717. $smcFunc['db_query']('', '
  1718. UPDATE {db_prefix}calendar
  1719. SET end_date = {date:end_date},
  1720. start_date = {date:start_date},
  1721. title = {string:title}
  1722. WHERE id_event = {int:id_event}',
  1723. array(
  1724. 'end_date' => strftime('%Y-%m-%d', $start_time + $span * 86400),
  1725. 'start_date' => strftime('%Y-%m-%d', $start_time),
  1726. 'id_event' => $_REQUEST['eventid'],
  1727. 'title' => $smcFunc['htmlspecialchars']($_REQUEST['evtitle'], ENT_QUOTES),
  1728. )
  1729. );
  1730. }
  1731. updateSettings(array(
  1732. 'calendar_updated' => time(),
  1733. ));
  1734. }
  1735. // Marking read should be done even for editing messages....
  1736. // Mark all the parents read. (since you just posted and they will be unread.)
  1737. if (!$user_info['is_guest'] && !empty($board_info['parent_boards']))
  1738. {
  1739. $smcFunc['db_query']('', '
  1740. UPDATE {db_prefix}log_boards
  1741. SET id_msg = {int:id_msg}
  1742. WHERE id_member = {int:current_member}
  1743. AND id_board IN ({array_int:board_list})',
  1744. array(
  1745. 'current_member' => $user_info['id'],
  1746. 'board_list' => array_keys($board_info['parent_boards']),
  1747. 'id_msg' => $modSettings['maxMsgID'],
  1748. )
  1749. );
  1750. }
  1751. // Turn notification on or off. (note this just blows smoke if it's already on or off.)
  1752. if (!empty($_POST['notify']) && allowedTo('mark_any_notify'))
  1753. {
  1754. $smcFunc['db_insert']('ignore',
  1755. '{db_prefix}log_notify',
  1756. array('id_member' => 'int', 'id_topic' => 'int', 'id_board' => 'int'),
  1757. array($user_info['id'], $topic, 0),
  1758. array('id_member', 'id_topic', 'id_board')
  1759. );
  1760. }
  1761. elseif (!$newTopic)
  1762. $smcFunc['db_query']('', '
  1763. DELETE FROM {db_prefix}log_notify
  1764. WHERE id_member = {int:current_member}
  1765. AND id_topic = {int:current_topic}',
  1766. array(
  1767. 'current_member' => $user_info['id'],
  1768. 'current_topic' => $topic,
  1769. )
  1770. );
  1771. // Log an act of moderation - modifying.
  1772. if (!empty($moderationAction))
  1773. logAction('modify', array('topic' => $topic, 'message' => (int) $_REQUEST['msg'], 'member' => $row['id_member'], 'board' => $board));
  1774. if (isset($_POST['lock']) && $_POST['lock'] != 2)
  1775. logAction('lock', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board']));
  1776. if (isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics']))
  1777. logAction('sticky', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board']));
  1778. // Notify any members who have notification turned on for this topic - only do this if it's going to be approved(!)
  1779. if ($becomesApproved)
  1780. {
  1781. if ($newTopic)
  1782. {
  1783. $notifyData = array(
  1784. 'body' => $_POST['message'],
  1785. 'subject' => $_POST['subject'],
  1786. 'name' => $user_info['name'],
  1787. 'poster' => $user_info['id'],
  1788. 'msg' => $msgOptions['id'],
  1789. 'board' => $board,
  1790. 'topic' => $topic,
  1791. );
  1792. notifyMembersBoard($notifyData);
  1793. }
  1794. elseif (empty($_REQUEST['msg']))
  1795. {
  1796. // Only send it to everyone if the topic is approved, otherwise just to the topic starter if they want it.
  1797. if ($topic_info['approved'])
  1798. sendNotifications($topic, 'reply');
  1799. else
  1800. sendNotifications($topic, 'reply', array(), $topic_info['id_member_started']);
  1801. }
  1802. }
  1803. // Returning to the topic?
  1804. if (!empty($_REQUEST['goback']))
  1805. {
  1806. // Mark the board as read.... because it might get confusing otherwise.
  1807. $smcFunc['db_query']('', '
  1808. UPDATE {db_prefix}log_boards
  1809. SET id_msg = {int:maxMsgID}
  1810. WHERE id_member = {int:current_member}
  1811. AND id_board = {int:current_board}',
  1812. array(
  1813. 'current_board' => $board,
  1814. 'current_member' => $user_info['id'],
  1815. 'maxMsgID' => $modSettings['maxMsgID'],
  1816. )
  1817. );
  1818. }
  1819. if ($board_info['num_topics'] == 0)
  1820. cache_put_data('board-' . $board, null, 120);
  1821. if (!empty($_POST['announce_topic']))
  1822. redirectexit('action=announce;sa=selectgroup;topic=' . $topic . (!empty($_POST['move']) && allowedTo('move_any') ? ';move' : '') . (empty($_REQUEST['goback']) ? '' : ';goback'));
  1823. if (!empty($_POST['move']) && allowedTo('move_any'))
  1824. redirectexit('action=movetopic;topic=' . $topic . '.0' . (empty($_REQUEST['goback']) ? '' : ';goback'));
  1825. // Return to post if the mod is on.
  1826. if (isset($_REQUEST['msg']) && !empty($_REQUEST['goback']))
  1827. redirectexit('topic=' . $topic . '.msg' . $_REQUEST['msg'] . '#msg' . $_REQUEST['msg'], isBrowser('ie'));
  1828. elseif (!empty($_REQUEST['goback']))
  1829. redirectexit('topic=' . $topic . '.new#new', isBrowser('ie'));
  1830. // Dut-dut-duh-duh-DUH-duh-dut-duh-duh! *dances to the Final Fantasy Fanfare...*
  1831. else
  1832. redirectexit('board=' . $board . '.0');
  1833. }
  1834. // General function for topic announcements.
  1835. function AnnounceTopic()
  1836. {
  1837. global $context, $txt, $topic;
  1838. isAllowedTo('announce_topic');
  1839. validateSession();
  1840. if (empty($topic))
  1841. fatal_lang_error('topic_gone', false);
  1842. loadLanguage('Post');
  1843. loadTemplate('Post');
  1844. $subActions = array(
  1845. 'selectgroup' => 'AnnouncementSelectMembergroup',
  1846. 'send' => 'AnnouncementSend',
  1847. );
  1848. $context['page_title'] = $txt['announce_topic'];
  1849. // Call the function based on the sub-action.
  1850. $subActions[isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'selectgroup']();
  1851. }
  1852. // Allow a user to chose the membergroups to send the announcement to.
  1853. function AnnouncementSelectMembergroup()
  1854. {
  1855. global $txt, $context, $topic, $board, $board_info, $smcFunc;
  1856. $groups = array_merge($board_info['groups'], array(1));
  1857. foreach ($groups as $id => $group)
  1858. $groups[$id] = (int) $group;
  1859. $context['groups'] = array();
  1860. if (in_array(0, $groups))
  1861. {
  1862. $context['groups'][0] = array(
  1863. 'id' => 0,
  1864. 'name' => $txt['announce_regular_members'],
  1865. 'member_count' => 'n/a',
  1866. );
  1867. }
  1868. // Get all membergroups that have access to the board the announcement was made on.
  1869. $request = $smcFunc['db_query']('', '
  1870. SELECT mg.id_group, COUNT(mem.id_member) AS num_members
  1871. FROM {db_prefix}membergroups AS mg
  1872. 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)
  1873. WHERE mg.id_group IN ({array_int:group_list})
  1874. GROUP BY mg.id_group',
  1875. array(
  1876. 'group_list' => $groups,
  1877. 'newbie_id_group' => 4,
  1878. )
  1879. );
  1880. while ($row = $smcFunc['db_fetch_assoc']($request))
  1881. {
  1882. $context['groups'][$row['id_group']] = array(
  1883. 'id' => $row['id_group'],
  1884. 'name' => '',
  1885. 'member_count' => $row['num_members'],
  1886. );
  1887. }
  1888. $smcFunc['db_free_result']($request);
  1889. // Now get the membergroup names.
  1890. $request = $smcFunc['db_query']('', '
  1891. SELECT id_group, group_name
  1892. FROM {db_prefix}membergroups
  1893. WHERE id_group IN ({array_int:group_list})',
  1894. array(
  1895. 'group_list' => $groups,
  1896. )
  1897. );
  1898. while ($row = $smcFunc['db_fetch_assoc']($request))
  1899. $context['groups'][$row['id_group']]['name'] = $row['group_name'];
  1900. $smcFunc['db_free_result']($request);
  1901. // Get the subject of the topic we're about to announce.
  1902. $request = $smcFunc['db_query']('', '
  1903. SELECT m.subject
  1904. FROM {db_prefix}topics AS t
  1905. INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)
  1906. WHERE t.id_topic = {int:current_topic}',
  1907. array(
  1908. 'current_topic' => $topic,
  1909. )
  1910. );
  1911. list ($context['topic_subject']) = $smcFunc['db_fetch_row']($request);
  1912. $smcFunc['db_free_result']($request);
  1913. censorText($context['announce_topic']['subject']);
  1914. $context['move'] = isset($_REQUEST['move']) ? 1 : 0;
  1915. $context['go_back'] = isset($_REQUEST['goback']) ? 1 : 0;
  1916. $context['sub_template'] = 'announce';
  1917. }
  1918. // Send the announcement in chunks.
  1919. function AnnouncementSend()
  1920. {
  1921. global $topic, $board, $board_info, $context, $modSettings;
  1922. global $language, $scripturl, $txt, $user_info, $sourcedir, $smcFunc;
  1923. checkSession();
  1924. /**
  1925. * @todo Might need an interface?
  1926. */
  1927. $chunkSize = empty($modSettings['mail_queue']) ? 50 : 500;
  1928. $context['start'] = empty($_REQUEST['start']) ? 0 : (int) $_REQUEST['start'];
  1929. $groups = array_merge($board_info['groups'], array(1));
  1930. if (isset($_POST['membergroups']))
  1931. $_POST['who'] = explode(',', $_POST['membergroups']);
  1932. // Check whether at least one membergroup was selected.
  1933. if (empty($_POST['who']))
  1934. fatal_lang_error('no_membergroup_selected');
  1935. // Make sure all membergroups are integers and can access the board of the announcement.
  1936. foreach ($_POST['who'] as $id => $mg)
  1937. $_POST['who'][$id] = in_array((int) $mg, $groups) ? (int) $mg : 0;
  1938. // Get the topic subject and censor it.
  1939. $request = $smcFunc['db_query']('', '
  1940. SELECT m.id_msg, m.subject, m.body
  1941. FROM {db_prefix}topics AS t
  1942. INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)
  1943. WHERE t.id_topic = {int:current_topic}',
  1944. array(
  1945. 'current_topic' => $topic,
  1946. )
  1947. );
  1948. list ($id_msg, $context['topic_subject'], $message) = $smcFunc['db_fetch_row']($request);
  1949. $smcFunc['db_free_result']($request);
  1950. censorText($context['topic_subject']);
  1951. censorText($message);
  1952. $message = trim(un_htmlspecialchars(strip_tags(strtr(parse_bbc($message, false, $id_msg), array('<br />' => "\n", '</div>' => "\n", '</li>' => "\n", '&#91;' => '[', '&#93;' => ']')))));
  1953. // We need this in order to be able send emails.
  1954. require_once($sourcedir . '/Subs-Post.php');
  1955. // Select the email addresses for this batch.
  1956. $request = $smcFunc['db_query']('', '
  1957. SELECT mem.id_member, mem.email_address, mem.lngfile
  1958. FROM {db_prefix}members AS mem
  1959. WHERE mem.id_member != {int:current_member}' . (!empty($modSettings['allow_disableAnnounce']) ? '
  1960. AND mem.notify_announcements = {int:notify_announcements}' : '') . '
  1961. AND mem.is_activated = {int:is_activated}
  1962. AND (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)
  1963. AND mem.id_member > {int:start}
  1964. ORDER BY mem.id_member
  1965. LIMIT ' . $chunkSize,
  1966. array(
  1967. 'current_member' => $user_info['id'],
  1968. 'group_list' => $_POST['who'],
  1969. 'notify_announcements' => 1,
  1970. 'is_activated' => 1,
  1971. 'start' => $context['start'],
  1972. 'additional_group_list' => implode(', mem.additional_groups) != 0 OR FIND_IN_SET(', $_POST['who']),
  1973. )
  1974. );
  1975. // All members have received a mail. Go to the next screen.
  1976. if ($smcFunc['db_num_rows']($request) == 0)
  1977. {
  1978. if (!empty($_REQUEST['move']) && allowedTo('move_any'))
  1979. redirectexit('action=movetopic;topic=' . $topic . '.0' . (empty($_REQUEST['goback']) ? '' : ';goback'));
  1980. elseif (!empty($_REQUEST['goback']))
  1981. redirectexit('topic=' . $topic . '.new;boardseen#new', isBrowser('ie'));
  1982. else
  1983. redirectexit('board=' . $board . '.0');
  1984. }
  1985. // Loop through all members that'll receive an announcement in this batch.
  1986. while ($row = $smcFunc['db_fetch_assoc']($request))
  1987. {
  1988. $cur_language = empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile'];
  1989. // If the language wasn't defined yet, load it and compose a notification message.
  1990. if (!isset($announcements[$cur_language]))
  1991. {
  1992. $replacements = array(
  1993. 'TOPICSUBJECT' => $context['topic_subject'],
  1994. 'MESSAGE' => $message,
  1995. 'TOPICLINK' => $scripturl . '?topic=' . $topic . '.0',
  1996. );
  1997. $emaildata = loadEmailTemplate('new_announcement', $replacements, $cur_language);
  1998. $announcements[$cur_language] = array(
  1999. 'subject' => $emaildata['subject'],
  2000. 'body' => $emaildata['body'],
  2001. 'recipients' => array(),
  2002. );
  2003. }
  2004. $announcements[$cur_language]['recipients'][$row['id_member']] = $row['email_address'];
  2005. $context['start'] = $row['id_member'];
  2006. }
  2007. $smcFunc['db_free_result']($request);
  2008. // For each language send a different mail - low priority...
  2009. foreach ($announcements as $lang => $mail)
  2010. sendmail($mail['recipients'], $mail['subject'], $mail['body'], null, null, false, 5);
  2011. $context['percentage_done'] = round(100 * $context['start'] / $modSettings['latestMember'], 1);
  2012. $context['move'] = empty($_REQUEST['move']) ? 0 : 1;
  2013. $context['go_back'] = empty($_REQUEST['goback']) ? 0 : 1;
  2014. $context['membergroups'] = implode(',', $_POST['who']);
  2015. $context['sub_template'] = 'announcement_send';
  2016. // Go back to the correct language for the user ;).
  2017. if (!empty($modSettings['userLanguage']))
  2018. loadLanguage('Post');
  2019. }
  2020. // Notify members of a new post.
  2021. function notifyMembersBoard(&$topicData)
  2022. {
  2023. global $txt, $scripturl, $language, $user_info;
  2024. global $modSettings, $sourcedir, $board, $smcFunc, $context;
  2025. require_once($sourcedir . '/Subs-Post.php');
  2026. // Do we have one or lots of topics?
  2027. if (isset($topicData['body']))
  2028. $topicData = array($topicData);
  2029. // Find out what boards we have... and clear out any rubbish!
  2030. $boards = array();
  2031. foreach ($topicData as $key => $topic)
  2032. {
  2033. if (!empty($topic['board']))
  2034. $boards[$topic['board']][] = $key;
  2035. else
  2036. {
  2037. unset($topic[$key]);
  2038. continue;
  2039. }
  2040. // Censor the subject and body...
  2041. censorText($topicData[$key]['subject']);
  2042. censorText($topicData[$key]['body']);
  2043. $topicData[$key]['subject'] = un_htmlspecialchars($topicData[$key]['subject']);
  2044. $topicData[$key]['body'] = trim(un_htmlspecialchars(strip_tags(strtr(parse_bbc($topicData[$key]['body'], false), array('<br />' => "\n", '</div>' => "\n", '</li>' => "\n", '&#91;' => '[', '&#93;' => ']')))));
  2045. }
  2046. // Just the board numbers.
  2047. $board_index = array_unique(array_keys($boards));
  2048. if (empty($board_index))
  2049. return;
  2050. // Yea, we need to add this to the digest queue.
  2051. $digest_insert = array();
  2052. foreach ($topicData as $id => $data)
  2053. $digest_insert[] = array($data['topic'], $data['msg'], 'topic', $user_info['id']);
  2054. $smcFunc['db_insert']('',
  2055. '{db_prefix}log_digest',
  2056. array(
  2057. 'id_topic' => 'int', 'id_msg' => 'int', 'note_type' => 'string', 'exclude' => 'int',
  2058. ),
  2059. $digest_insert,
  2060. array()
  2061. );
  2062. // Find the members with notification on for these boards.
  2063. $members = $smcFunc['db_query']('', '
  2064. SELECT
  2065. mem.id_member, mem.email_address, mem.notify_regularity, mem.notify_send_body, mem.lngfile,
  2066. ln.sent, ln.id_board, mem.id_group, mem.additional_groups, b.member_groups,
  2067. mem.id_post_group
  2068. FROM {db_prefix}log_notify AS ln
  2069. INNER JOIN {db_prefix}boards AS b ON (b.id_board = ln.id_board)
  2070. INNER JOIN {db_prefix}members AS mem ON (mem.id_member = ln.id_member)
  2071. WHERE ln.id_board IN ({array_int:board_list})
  2072. AND mem.id_member != {int:current_member}
  2073. AND mem.is_activated = {int:is_activated}
  2074. AND mem.notify_types != {int:notify_types}
  2075. AND mem.notify_regularity < {int:notify_regularity}
  2076. ORDER BY mem.lngfile',
  2077. array(
  2078. 'current_member' => $user_info['id'],
  2079. 'board_list' => $board_index,
  2080. 'is_activated' => 1,
  2081. 'notify_types' => 4,
  2082. 'notify_regularity' => 2,
  2083. )
  2084. );
  2085. while ($rowmember = $smcFunc['db_fetch_assoc']($members))
  2086. {
  2087. if ($rowmember['id_group'] != 1)
  2088. {
  2089. $allowed = explode(',', $rowmember['member_groups']);
  2090. $rowmember['additional_groups'] = explode(',', $rowmember['additional_groups']);
  2091. $rowmember['additional_groups'][] = $rowmember['id_group'];
  2092. $rowmember['additional_groups'][] = $rowmember['id_post_group'];
  2093. if (count(array_intersect($allowed, $rowmember['additional_groups'])) == 0)
  2094. continue;
  2095. }
  2096. $langloaded = loadLanguage('EmailTemplates', empty($rowmember['lngfile']) || empty($modSettings['userLanguage']) ? $language : $rowmember['lngfile'], false);
  2097. // Now loop through all the notifications to send for this board.
  2098. if (empty($boards[$rowmember['id_board']]))
  2099. continue;
  2100. $sentOnceAlready = 0;
  2101. foreach ($boards[$rowmember['id_board']] as $key)
  2102. {
  2103. // Don't notify the guy who started the topic!
  2104. // @todo In this case actually send them a "it's approved hooray" email :P
  2105. if ($topicData[$key]['poster'] == $rowmember['id_member'])
  2106. continue;
  2107. // Setup the string for adding the body to the message, if a user wants it.
  2108. $send_body = empty($modSettings['disallow_sendBody']) && !empty($rowmember['notify_send_body']);
  2109. $replacements = array(
  2110. 'TOPICSUBJECT' => $topicData[$key]['subject'],
  2111. 'TOPICLINK' => $scripturl . '?topic=' . $topicData[$key]['topic'] . '.new#new',
  2112. 'MESSAGE' => $topicData[$key]['body'],
  2113. 'UNSUBSCRIBELINK' => $scripturl . '?action=notifyboard;board=' . $topicData[$key]['board'] . '.0',
  2114. );
  2115. if (!$send_body)
  2116. unset($replacements['MESSAGE']);
  2117. // Figure out which email to send off
  2118. $emailtype = '';
  2119. // Send only if once is off or it's on and it hasn't been sent.
  2120. if (!empty($rowmember['notify_regularity']) && !$sentOnceAlready && empty($rowmember['sent']))
  2121. $emailtype = 'notify_boards_once';
  2122. elseif (empty($rowmember['notify_regularity']))
  2123. $emailtype = 'notify_boards';
  2124. if (!empty($emailtype))
  2125. {
  2126. $emailtype .= $send_body ? '_body' : '';
  2127. $emaildata = loadEmailTemplate($emailtype, $replacements, $langloaded);
  2128. sendmail($rowmember['email_address'], $emaildata['subject'], $emaildata['body'], null, null, false, 3);
  2129. }
  2130. $sentOnceAlready = 1;
  2131. }
  2132. }
  2133. $smcFunc['db_free_result']($members);
  2134. // Sent!
  2135. $smcFunc['db_query']('', '
  2136. UPDATE {db_prefix}log_notify
  2137. SET sent = {int:is_sent}
  2138. WHERE id_board IN ({array_int:board_list})
  2139. AND id_member != {int:current_member}',
  2140. array(
  2141. 'current_member' => $user_info['id'],
  2142. 'board_list' => $board_index,
  2143. 'is_sent' => 1,
  2144. )
  2145. );
  2146. }
  2147. // Get the topic for display purposes.
  2148. function getTopic()
  2149. {
  2150. global $topic, $modSettings, $context, $smcFunc, $counter, $options;
  2151. if (isset($_REQUEST['xml']))
  2152. $limit = '
  2153. LIMIT ' . (empty($context['new_replies']) ? '0' : $context['new_replies']);
  2154. else
  2155. $limit = empty($modSettings['topicSummaryPosts']) ? '' : '
  2156. LIMIT ' . (int) $modSettings['topicSummaryPosts'];
  2157. // If you're modifying, get only those posts before the current one. (otherwise get all.)
  2158. $request = $smcFunc['db_query']('', '
  2159. SELECT
  2160. IFNULL(mem.real_name, m.poster_name) AS poster_name, m.poster_time,
  2161. m.body, m.smileys_enabled, m.id_msg, m.id_member
  2162. FROM {db_prefix}messages AS m
  2163. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
  2164. WHERE m.id_topic = {int:current_topic}' . (isset($_REQUEST['msg']) ? '
  2165. AND m.id_msg < {int:id_msg}' : '') .(!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
  2166. AND m.approved = {int:approved}') . '
  2167. ORDER BY m.id_msg DESC' . $limit,
  2168. array(
  2169. 'current_topic' => $topic,
  2170. 'id_msg' => isset($_REQUEST['msg']) ? (int) $_REQUEST['msg'] : 0,
  2171. 'approved' => 1,
  2172. )
  2173. );
  2174. $context['previous_posts'] = array();
  2175. while ($row = $smcFunc['db_fetch_assoc']($request))
  2176. {
  2177. // Censor, BBC, ...
  2178. censorText($row['body']);
  2179. $row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']);
  2180. // ...and store.
  2181. $context['previous_posts'][] = array(
  2182. 'counter' => $counter++,
  2183. 'alternate' => $counter % 2,
  2184. 'poster' => $row['poster_name'],
  2185. 'message' => $row['body'],
  2186. 'time' => timeformat($row['poster_time']),
  2187. 'timestamp' => forum_time(true, $row['poster_time']),
  2188. 'id' => $row['id_msg'],
  2189. 'is_new' => !empty($context['new_replies']),
  2190. 'is_ignored' => !empty($modSettings['enable_buddylist']) && !empty($options['posts_apply_ignore_list']) && in_array($row['id_member'], $context['user']['ignoreusers']),
  2191. );
  2192. if (!empty($context['new_replies']))
  2193. $context['new_replies']--;
  2194. }
  2195. $smcFunc['db_free_result']($request);
  2196. }
  2197. function QuoteFast()
  2198. {
  2199. global $modSettings, $user_info, $txt, $settings, $context;
  2200. global $sourcedir, $smcFunc;
  2201. loadLanguage('Post');
  2202. if (!isset($_REQUEST['xml']))
  2203. loadTemplate('Post');
  2204. include_once($sourcedir . '/Subs-Post.php');
  2205. $moderate_boards = boardsAllowedTo('moderate_board');
  2206. // Where we going if we need to?
  2207. $context['post_box_name'] = isset($_GET['pb']) ? $_GET['pb'] : '';
  2208. $request = $smcFunc['db_query']('', '
  2209. SELECT IFNULL(mem.real_name, m.poster_name) AS poster_name, m.poster_time, m.body, m.id_topic, m.subject,
  2210. m.id_board, m.id_member, m.approved
  2211. FROM {db_prefix}messages AS m
  2212. INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)
  2213. INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board AND {query_see_board})
  2214. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
  2215. WHERE m.id_msg = {int:id_msg}' . (isset($_REQUEST['modify']) || (!empty($moderate_boards) && $moderate_boards[0] == 0) ? '' : '
  2216. AND (t.locked = {int:not_locked}' . (empty($moderate_boards) ? '' : ' OR b.id_board IN ({array_int:moderation_board_list})') . ')') . '
  2217. LIMIT 1',
  2218. array(
  2219. 'current_member' => $user_info['id'],
  2220. 'moderation_board_list' => $moderate_boards,
  2221. 'id_msg' => (int) $_REQUEST['quote'],
  2222. 'not_locked' => 0,
  2223. )
  2224. );
  2225. $context['close_window'] = $smcFunc['db_num_rows']($request) == 0;
  2226. $row = $smcFunc['db_fetch_assoc']($request);
  2227. $smcFunc['db_free_result']($request);
  2228. $context['sub_template'] = 'quotefast';
  2229. if (!empty($row))
  2230. $can_view_post = $row['approved'] || ($row['id_member'] != 0 && $row['id_member'] == $user_info['id']) || allowedTo('approve_posts', $row['id_board']);
  2231. if (!empty($can_view_post))
  2232. {
  2233. // Remove special formatting we don't want anymore.
  2234. $row['body'] = un_preparsecode($row['body']);
  2235. // Censor the message!
  2236. censorText($row['body']);
  2237. $row['body'] = preg_replace('~<br ?/?' . '>~i', "\n", $row['body']);
  2238. // Want to modify a single message by double clicking it?
  2239. if (isset($_REQUEST['modify']))
  2240. {
  2241. censorText($row['subject']);
  2242. $context['sub_template'] = 'modifyfast';
  2243. $context['message'] = array(
  2244. 'id' => $_REQUEST['quote'],
  2245. 'body' => $row['body'],
  2246. 'subject' => addcslashes($row['subject'], '"'),
  2247. );
  2248. return;
  2249. }
  2250. // Remove any nested quotes.
  2251. if (!empty($modSettings['removeNestedQuotes']))
  2252. $row['body'] = preg_replace(array('~\n?\[quote.*?\].+?\[/quote\]\n?~is', '~^\n~', '~\[/quote\]~'), '', $row['body']);
  2253. // Make the body HTML if need be.
  2254. if (!empty($_REQUEST['mode']))
  2255. {
  2256. require_once($sourcedir . '/Subs-Editor.php');
  2257. $row['body'] = strtr($row['body'], array('&lt;' => '#smlt#', '&gt;' => '#smgt#', '&amp;' => '#smamp#'));
  2258. $row['body'] = bbc_to_html($row['body']);
  2259. $lb = '<br />';
  2260. }
  2261. else
  2262. $lb = "\n";
  2263. // Add a quote string on the front and end.
  2264. $context['quote']['xml'] = '[quote author=' . $row['poster_name'] . ' link=topic=' . $row['id_topic'] . '.msg' . (int) $_REQUEST['quote'] . '#msg' . (int) $_REQUEST['quote'] . ' date=' . $row['poster_time'] . ']' . $lb . $row['body'] . $lb . '[/quote]';
  2265. $context['quote']['text'] = strtr(un_htmlspecialchars($context['quote']['xml']), array('\'' => '\\\'', '\\' => '\\\\', "\n" => '\\n', '</script>' => '</\' + \'script>'));
  2266. $context['quote']['xml'] = strtr($context['quote']['xml'], array('&nbsp;' => '&#160;', '<' => '&lt;', '>' => '&gt;'));
  2267. $context['quote']['mozilla'] = strtr($smcFunc['htmlspecialchars']($context['quote']['text']), array('&quot;' => '"'));
  2268. }
  2269. /**
  2270. * @todo Needs a nicer interface.
  2271. */
  2272. // In case our message has been removed in the meantime.
  2273. elseif (isset($_REQUEST['modify']))
  2274. {
  2275. $context['sub_template'] = 'modifyfast';
  2276. $context['message'] = array(
  2277. 'id' => 0,
  2278. 'body' => '',
  2279. 'subject' => '',
  2280. );
  2281. }
  2282. else
  2283. $context['quote'] = array(
  2284. 'xml' => '',
  2285. 'mozilla' => '',
  2286. 'text' => '',
  2287. );
  2288. }
  2289. function JavaScriptModify()
  2290. {
  2291. global $sourcedir, $modSettings, $board, $topic, $txt;
  2292. global $user_info, $context, $smcFunc, $language;
  2293. // We have to have a topic!
  2294. if (empty($topic))
  2295. obExit(false);
  2296. checkSession('get');
  2297. require_once($sourcedir . '/Subs-Post.php');
  2298. // Assume the first message if no message ID was given.
  2299. $request = $smcFunc['db_query']('', '
  2300. SELECT
  2301. t.locked, t.num_replies, t.id_member_started, t.id_first_msg,
  2302. m.id_msg, m.id_member, m.poster_time, m.subject, m.smileys_enabled, m.body, m.icon,
  2303. m.modified_time, m.modified_name, m.approved
  2304. FROM {db_prefix}messages AS m
  2305. INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
  2306. WHERE m.id_msg = {raw:id_msg}
  2307. AND m.id_topic = {int:current_topic}' . (allowedTo('approve_posts') ? '' : (!$modSettings['postmod_active'] ? '
  2308. AND (m.id_member != {int:guest_id} AND m.id_member = {int:current_member})' : '
  2309. AND (m.approved = {int:is_approved} OR (m.id_member != {int:guest_id} AND m.id_member = {int:current_member}))')),
  2310. array(
  2311. 'current_member' => $user_info['id'],
  2312. 'current_topic' => $topic,
  2313. 'id_msg' => empty($_REQUEST['msg']) ? 't.id_first_msg' : (int) $_REQUEST['msg'],
  2314. 'is_approved' => 1,
  2315. 'guest_id' => 0,
  2316. )
  2317. );
  2318. if ($smcFunc['db_num_rows']($request) == 0)
  2319. fatal_lang_error('no_board', false);
  2320. $row = $smcFunc['db_fetch_assoc']($request);
  2321. $smcFunc['db_free_result']($request);
  2322. // Change either body or subject requires permissions to modify messages.
  2323. if (isset($_POST['message']) || isset($_POST['subject']) || isset($_REQUEST['icon']))
  2324. {
  2325. if (!empty($row['locked']))
  2326. isAllowedTo('moderate_board');
  2327. if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any'))
  2328. {
  2329. if ((!$modSettings['postmod_active'] || $row['approved']) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time())
  2330. fatal_lang_error('modify_post_time_passed', false);
  2331. elseif ($row['id_member_started'] == $user_info['id'] && !allowedTo('modify_own'))
  2332. isAllowedTo('modify_replies');
  2333. else
  2334. isAllowedTo('modify_own');
  2335. }
  2336. // Otherwise, they're locked out; someone who can modify the replies is needed.
  2337. elseif ($row['id_member_started'] == $user_info['id'] && !allowedTo('modify_any'))
  2338. isAllowedTo('modify_replies');
  2339. else
  2340. isAllowedTo('modify_any');
  2341. // Only log this action if it wasn't your message.
  2342. $moderationAction = $row['id_member'] != $user_info['id'];
  2343. }
  2344. $post_errors = array();
  2345. if (isset($_POST['subject']) && $smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['subject'])) !== '')
  2346. {
  2347. $_POST['subject'] = strtr($smcFunc['htmlspecialchars']($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
  2348. // Maximum number of characters.
  2349. if ($smcFunc['strlen']($_POST['subject']) > 100)
  2350. $_POST['subject'] = $smcFunc['substr']($_POST['subject'], 0, 100);
  2351. }
  2352. elseif (isset($_POST['subject']))
  2353. {
  2354. $post_errors[] = 'no_subject';
  2355. unset($_POST['subject']);
  2356. }
  2357. if (isset($_POST['message']))
  2358. {
  2359. if ($smcFunc['htmltrim']($smcFunc['htmlspecialchars']($_POST['message'])) === '')
  2360. {
  2361. $post_errors[] = 'no_message';
  2362. unset($_POST['message']);
  2363. }
  2364. elseif (!empty($modSettings['max_messageLength']) && $smcFunc['strlen']($_POST['message']) > $modSettings['max_messageLength'])
  2365. {
  2366. $post_errors[] = 'long_message';
  2367. unset($_POST['message']);
  2368. }
  2369. else
  2370. {
  2371. $_POST['message'] = $smcFunc['htmlspecialchars']($_POST['message'], ENT_QUOTES);
  2372. preparsecode($_POST['message']);
  2373. if ($smcFunc['htmltrim'](strip_tags(parse_bbc($_POST['message'], false), '<img>')) === '')
  2374. {
  2375. $post_errors[] = 'no_message';
  2376. unset($_POST['message']);
  2377. }
  2378. }
  2379. }
  2380. if (isset($_POST['lock']))
  2381. {
  2382. if (!allowedTo(array('lock_any', 'lock_own')) || (!allowedTo('lock_any') && $user_info['id'] != $row['id_member']))
  2383. unset($_POST['lock']);
  2384. elseif (!allowedTo('lock_any'))
  2385. {
  2386. if ($row['locked'] == 1)
  2387. unset($_POST['lock']);
  2388. else
  2389. $_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
  2390. }
  2391. elseif (!empty($row['locked']) && !empty($_POST['lock']) || $_POST['lock'] == $row['locked'])
  2392. unset($_POST['lock']);
  2393. else
  2394. $_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
  2395. }
  2396. if (isset($_POST['sticky']) && !allowedTo('make_sticky'))
  2397. unset($_POST['sticky']);
  2398. if (empty($post_errors))
  2399. {
  2400. $msgOptions = array(
  2401. 'id' => $row['id_msg'],
  2402. 'subject' => isset($_POST['subject']) ? $_POST['subject'] : null,
  2403. 'body' => isset($_POST['message']) ? $_POST['message'] : null,
  2404. 'icon' => isset($_REQUEST['icon']) ? preg_replace('~[\./\\\\*\':"<>]~', '', $_REQUEST['icon']) : null,
  2405. );
  2406. $topicOptions = array(
  2407. 'id' => $topic,
  2408. 'board' => $board,
  2409. 'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null,
  2410. 'sticky_mode' => isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics']) ? (int) $_POST['sticky'] : null,
  2411. 'mark_as_read' => true,
  2412. );
  2413. $posterOptions = array();
  2414. // Only consider marking as editing if they have edited the subject, message or icon.
  2415. if ((isset($_POST['subject']) && $_POST['subject'] != $row['subject']) || (isset($_POST['message']) && $_POST['message'] != $row['body']) || (isset($_REQUEST['icon']) && $_REQUEST['icon'] != $row['icon']))
  2416. {
  2417. // And even then only if the time has passed...
  2418. if (time() - $row['poster_time'] > $modSettings['edit_wait_time'] || $user_info['id'] != $row['id_member'])
  2419. {
  2420. $msgOptions['modify_time'] = time();
  2421. $msgOptions['modify_name'] = $user_info['name'];
  2422. }
  2423. }
  2424. // If nothing was changed there's no need to add an entry to the moderation log.
  2425. else
  2426. $moderationAction = false;
  2427. modifyPost($msgOptions, $topicOptions, $posterOptions);
  2428. // If we didn't change anything this time but had before put back the old info.
  2429. if (!isset($msgOptions['modify_time']) && !empty($row['modified_time']))
  2430. {
  2431. $msgOptions['modify_time'] = $row['modified_time'];
  2432. $msgOptions['modify_name'] = $row['modified_name'];
  2433. }
  2434. // Changing the first subject updates other subjects to 'Re: new_subject'.
  2435. 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'))))
  2436. {
  2437. // Get the proper (default language) response prefix first.
  2438. if (!isset($context['response_prefix']) && !($context['response_prefix'] = cache_get_data('response_prefix')))
  2439. {
  2440. if ($language === $user_info['language'])
  2441. $context['response_prefix'] = $txt['response_prefix'];
  2442. else
  2443. {
  2444. loadLanguage('index', $language, false);
  2445. $context['response_prefix'] = $txt['response_prefix'];
  2446. loadLanguage('index');
  2447. }
  2448. cache_put_data('response_prefix', $context['response_prefix'], 600);
  2449. }
  2450. $smcFunc['db_query']('', '
  2451. UPDATE {db_prefix}messages
  2452. SET subject = {string:subject}
  2453. WHERE id_topic = {int:current_topic}
  2454. AND id_msg != {int:id_first_msg}',
  2455. array(
  2456. 'current_topic' => $topic,
  2457. 'id_first_msg' => $row['id_first_msg'],
  2458. 'subject' => $context['response_prefix'] . $_POST['subject'],
  2459. )
  2460. );
  2461. }
  2462. if (!empty($moderationAction))
  2463. logAction('modify', array('topic' => $topic, 'message' => $row['id_msg'], 'member' => $row['id_member'], 'board' => $board));
  2464. }
  2465. if (isset($_REQUEST['xml']))
  2466. {
  2467. $context['sub_template'] = 'modifydone';
  2468. if (empty($post_errors) && isset($msgOptions['subject']) && isset($msgOptions['body']))
  2469. {
  2470. $context['message'] = array(
  2471. 'id' => $row['id_msg'],
  2472. 'modified' => array(
  2473. 'time' => isset($msgOptions['modify_time']) ? timeformat($msgOptions['modify_time']) : '',
  2474. 'timestamp' => isset($msgOptions['modify_time']) ? forum_time(true, $msgOptions['modify_time']) : 0,
  2475. 'name' => isset($msgOptions['modify_time']) ? $msgOptions['modify_name'] : '',
  2476. ),
  2477. 'subject' => $msgOptions['subject'],
  2478. 'first_in_topic' => $row['id_msg'] == $row['id_first_msg'],
  2479. 'body' => strtr($msgOptions['body'], array(']]>' => ']]]]><![CDATA[>')),
  2480. );
  2481. censorText($context['message']['subject']);
  2482. censorText($context['message']['body']);
  2483. $context['message']['body'] = parse_bbc($context['message']['body'], $row['smileys_enabled'], $row['id_msg']);
  2484. }
  2485. // Topic?
  2486. elseif (empty($post_errors))
  2487. {
  2488. $context['sub_template'] = 'modifytopicdone';
  2489. $context['message'] = array(
  2490. 'id' => $row['id_msg'],
  2491. 'modified' => array(
  2492. 'time' => isset($msgOptions['modify_time']) ? timeformat($msgOptions['modify_time']) : '',
  2493. 'timestamp' => isset($msgOptions['modify_time']) ? forum_time(true, $msgOptions['modify_time']) : 0,
  2494. 'name' => isset($msgOptions['modify_time']) ? $msgOptions['modify_name'] : '',
  2495. ),
  2496. 'subject' => isset($msgOptions['subject']) ? $msgOptions['subject'] : '',
  2497. );
  2498. censorText($context['message']['subject']);
  2499. }
  2500. else
  2501. {
  2502. $context['message'] = array(
  2503. 'id' => $row['id_msg'],
  2504. 'errors' => array(),
  2505. 'error_in_subject' => in_array('no_subject', $post_errors),
  2506. 'error_in_body' => in_array('no_message', $post_errors) || in_array('long_message', $post_errors),
  2507. );
  2508. loadLanguage('Errors');
  2509. foreach ($post_errors as $post_error)
  2510. {
  2511. if ($post_error == 'long_message')
  2512. $context['message']['errors'][] = sprintf($txt['error_' . $post_error], $modSettings['max_messageLength']);
  2513. else
  2514. $context['message']['errors'][] = $txt['error_' . $post_error];
  2515. }
  2516. }
  2517. }
  2518. else
  2519. obExit(false);
  2520. }
  2521. ?>