PersonalMessage.php 124 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618
  1. <?php
  2. /**
  3. * Simple Machines Forum (SMF)
  4. *
  5. * @package SMF
  6. * @author Simple Machines http://www.simplemachines.org
  7. * @copyright 2011 Simple Machines
  8. * @license http://www.simplemachines.org/about/smf/license.php BSD
  9. *
  10. * @version 2.0
  11. */
  12. if (!defined('SMF'))
  13. die('Hacking attempt...');
  14. /* This file is mainly meant for viewing personal messages. It also sends,
  15. deletes, and marks personal messages. For compatibility reasons, they are
  16. often called "instant messages". The following functions are used:
  17. void MessageMain()
  18. // !!! ?action=pm
  19. void messageIndexBar(string area)
  20. // !!!
  21. void MessageFolder()
  22. // !!! ?action=pm;sa=folder
  23. void prepareMessageContext(type reset = 'subject', bool reset = false)
  24. // !!!
  25. void MessageSearch()
  26. // !!!
  27. void MessageSearch2()
  28. // !!!
  29. void MessagePost()
  30. // !!! ?action=pm;sa=post
  31. void messagePostError(array error_types, array named_recipients, array recipient_ids)
  32. // !!!
  33. void MessagePost2()
  34. // !!! ?action=pm;sa=post2
  35. void WirelessAddBuddy()
  36. // !!!
  37. void MessageActionsApply()
  38. // !!! ?action=pm;sa=pmactions
  39. void MessageKillAllQuery()
  40. // !!! ?action=pm;sa=killall
  41. void MessageKillAll()
  42. // !!! ?action=pm;sa=killall2
  43. void MessagePrune()
  44. // !!! ?action=pm;sa=prune
  45. void deleteMessages(array personal_messages, string folder,
  46. int owner = user)
  47. // !!!
  48. void markMessages(array personal_messages = all, int label = all,
  49. int owner = user)
  50. - marks the specified personal_messages read.
  51. - if label is set, only marks messages with that label.
  52. - if owner is set, marks messages owned by that member id.
  53. void ManageLabels()
  54. // !!!
  55. void MessageSettings()
  56. // !!!
  57. void ReportMessage()
  58. - allows the user to report a personal message to an administrator.
  59. - in the first instance requires that the ID of the message to report
  60. is passed through $_GET.
  61. - allows the user to report to either a particular administrator - or
  62. the whole admin team.
  63. - will forward on a copy of the original message without allowing the
  64. reporter to make changes.
  65. - uses the report_message sub-template.
  66. void ManageRules()
  67. // !!!
  68. void LoadRules()
  69. // !!!
  70. void ApplyRules()
  71. // !!!
  72. */
  73. // This helps organize things...
  74. function MessageMain()
  75. {
  76. global $txt, $scripturl, $sourcedir, $context, $user_info, $user_settings, $smcFunc, $modSettings;
  77. // No guests!
  78. is_not_guest();
  79. // You're not supposed to be here at all, if you can't even read PMs.
  80. isAllowedTo('pm_read');
  81. // This file contains the basic functions for sending a PM.
  82. require_once($sourcedir . '/Subs-Post.php');
  83. loadLanguage('PersonalMessage');
  84. if (WIRELESS && WIRELESS_PROTOCOL == 'wap')
  85. fatal_lang_error('wireless_error_notyet', false);
  86. elseif (WIRELESS)
  87. $context['sub_template'] = WIRELESS_PROTOCOL . '_pm';
  88. else
  89. loadTemplate('PersonalMessage');
  90. // Load up the members maximum message capacity.
  91. if ($user_info['is_admin'])
  92. $context['message_limit'] = 0;
  93. elseif (($context['message_limit'] = cache_get_data('msgLimit:' . $user_info['id'], 360)) === null)
  94. {
  95. // !!! Why do we do this? It seems like if they have any limit we should use it.
  96. $request = $smcFunc['db_query']('', '
  97. SELECT MAX(max_messages) AS top_limit, MIN(max_messages) AS bottom_limit
  98. FROM {db_prefix}membergroups
  99. WHERE id_group IN ({array_int:users_groups})',
  100. array(
  101. 'users_groups' => $user_info['groups'],
  102. )
  103. );
  104. list ($maxMessage, $minMessage) = $smcFunc['db_fetch_row']($request);
  105. $smcFunc['db_free_result']($request);
  106. $context['message_limit'] = $minMessage == 0 ? 0 : $maxMessage;
  107. // Save us doing it again!
  108. cache_put_data('msgLimit:' . $user_info['id'], $context['message_limit'], 360);
  109. }
  110. // Prepare the context for the capacity bar.
  111. if (!empty($context['message_limit']))
  112. {
  113. $bar = ($user_info['messages'] * 100) / $context['message_limit'];
  114. $context['limit_bar'] = array(
  115. 'messages' => $user_info['messages'],
  116. 'allowed' => $context['message_limit'],
  117. 'percent' => $bar,
  118. 'bar' => min(100, (int) $bar),
  119. 'text' => sprintf($txt['pm_currently_using'], $user_info['messages'], round($bar, 1)),
  120. );
  121. }
  122. // a previous message was sent successfully? show a small indication.
  123. if (isset($_GET['done']) && ($_GET['done'] == 'sent'))
  124. $context['pm_sent'] = true;
  125. // Now we have the labels, and assuming we have unsorted mail, apply our rules!
  126. if ($user_settings['new_pm'])
  127. {
  128. $context['labels'] = $user_settings['message_labels'] == '' ? array() : explode(',', $user_settings['message_labels']);
  129. foreach ($context['labels'] as $id_label => $label_name)
  130. $context['labels'][(int) $id_label] = array(
  131. 'id' => $id_label,
  132. 'name' => trim($label_name),
  133. 'messages' => 0,
  134. 'unread_messages' => 0,
  135. );
  136. $context['labels'][-1] = array(
  137. 'id' => -1,
  138. 'name' => $txt['pm_msg_label_inbox'],
  139. 'messages' => 0,
  140. 'unread_messages' => 0,
  141. );
  142. ApplyRules();
  143. updateMemberData($user_info['id'], array('new_pm' => 0));
  144. $smcFunc['db_query']('', '
  145. UPDATE {db_prefix}pm_recipients
  146. SET is_new = {int:not_new}
  147. WHERE id_member = {int:current_member}',
  148. array(
  149. 'current_member' => $user_info['id'],
  150. 'not_new' => 0,
  151. )
  152. );
  153. }
  154. // Load the label data.
  155. if ($user_settings['new_pm'] || ($context['labels'] = cache_get_data('labelCounts:' . $user_info['id'], 720)) === null)
  156. {
  157. $context['labels'] = $user_settings['message_labels'] == '' ? array() : explode(',', $user_settings['message_labels']);
  158. foreach ($context['labels'] as $id_label => $label_name)
  159. $context['labels'][(int) $id_label] = array(
  160. 'id' => $id_label,
  161. 'name' => trim($label_name),
  162. 'messages' => 0,
  163. 'unread_messages' => 0,
  164. );
  165. $context['labels'][-1] = array(
  166. 'id' => -1,
  167. 'name' => $txt['pm_msg_label_inbox'],
  168. 'messages' => 0,
  169. 'unread_messages' => 0,
  170. );
  171. // Looks like we need to reseek!
  172. $result = $smcFunc['db_query']('', '
  173. SELECT labels, is_read, COUNT(*) AS num
  174. FROM {db_prefix}pm_recipients
  175. WHERE id_member = {int:current_member}
  176. AND deleted = {int:not_deleted}
  177. GROUP BY labels, is_read',
  178. array(
  179. 'current_member' => $user_info['id'],
  180. 'not_deleted' => 0,
  181. )
  182. );
  183. while ($row = $smcFunc['db_fetch_assoc']($result))
  184. {
  185. $this_labels = explode(',', $row['labels']);
  186. foreach ($this_labels as $this_label)
  187. {
  188. $context['labels'][(int) $this_label]['messages'] += $row['num'];
  189. if (!($row['is_read'] & 1))
  190. $context['labels'][(int) $this_label]['unread_messages'] += $row['num'];
  191. }
  192. }
  193. $smcFunc['db_free_result']($result);
  194. // Store it please!
  195. cache_put_data('labelCounts:' . $user_info['id'], $context['labels'], 720);
  196. }
  197. // This determines if we have more labels than just the standard inbox.
  198. $context['currently_using_labels'] = count($context['labels']) > 1 ? 1 : 0;
  199. // Some stuff for the labels...
  200. $context['current_label_id'] = isset($_REQUEST['l']) && isset($context['labels'][(int) $_REQUEST['l']]) ? (int) $_REQUEST['l'] : -1;
  201. $context['current_label'] = &$context['labels'][(int) $context['current_label_id']]['name'];
  202. $context['folder'] = !isset($_REQUEST['f']) || $_REQUEST['f'] != 'sent' ? 'inbox' : 'sent';
  203. // This is convenient. Do you know how annoying it is to do this every time?!
  204. $context['current_label_redirect'] = 'action=pm;f=' . $context['folder'] . (isset($_GET['start']) ? ';start=' . $_GET['start'] : '') . (isset($_REQUEST['l']) ? ';l=' . $_REQUEST['l'] : '');
  205. $context['can_issue_warning'] = in_array('w', $context['admin_features']) && allowedTo('issue_warning') && $modSettings['warning_settings'][0] == 1;
  206. // Build the linktree for all the actions...
  207. $context['linktree'][] = array(
  208. 'url' => $scripturl . '?action=pm',
  209. 'name' => $txt['personal_messages']
  210. );
  211. // Preferences...
  212. $context['display_mode'] = WIRELESS ? 0 : $user_settings['pm_prefs'] & 3;
  213. $subActions = array(
  214. 'addbuddy' => 'WirelessAddBuddy',
  215. 'manlabels' => 'ManageLabels',
  216. 'manrules' => 'ManageRules',
  217. 'pmactions' => 'MessageActionsApply',
  218. 'prune' => 'MessagePrune',
  219. 'removeall' => 'MessageKillAllQuery',
  220. 'removeall2' => 'MessageKillAll',
  221. 'report' => 'ReportMessage',
  222. 'search' => 'MessageSearch',
  223. 'search2' => 'MessageSearch2',
  224. 'send' => 'MessagePost',
  225. 'send2' => 'MessagePost2',
  226. 'settings' => 'MessageSettings',
  227. );
  228. if (!isset($_REQUEST['sa']) || !isset($subActions[$_REQUEST['sa']]))
  229. MessageFolder();
  230. else
  231. {
  232. messageIndexBar($_REQUEST['sa']);
  233. $subActions[$_REQUEST['sa']]();
  234. }
  235. }
  236. // A sidebar to easily access different areas of the section
  237. function messageIndexBar($area)
  238. {
  239. global $txt, $context, $scripturl, $sourcedir, $sc, $modSettings, $settings, $user_info, $options;
  240. $pm_areas = array(
  241. 'folders' => array(
  242. 'title' => $txt['pm_messages'],
  243. 'areas' => array(
  244. 'send' => array(
  245. 'label' => $txt['new_message'],
  246. 'custom_url' => $scripturl . '?action=pm;sa=send',
  247. 'permission' => allowedTo('pm_send'),
  248. ),
  249. 'inbox' => array(
  250. 'label' => $txt['inbox'],
  251. 'custom_url' => $scripturl . '?action=pm',
  252. ),
  253. 'sent' => array(
  254. 'label' => $txt['sent_items'],
  255. 'custom_url' => $scripturl . '?action=pm;f=sent',
  256. ),
  257. ),
  258. ),
  259. 'labels' => array(
  260. 'title' => $txt['pm_labels'],
  261. 'areas' => array(),
  262. ),
  263. 'actions' => array(
  264. 'title' => $txt['pm_actions'],
  265. 'areas' => array(
  266. 'search' => array(
  267. 'label' => $txt['pm_search_bar_title'],
  268. 'custom_url' => $scripturl . '?action=pm;sa=search',
  269. ),
  270. 'prune' => array(
  271. 'label' => $txt['pm_prune'],
  272. 'custom_url' => $scripturl . '?action=pm;sa=prune'
  273. ),
  274. ),
  275. ),
  276. 'pref' => array(
  277. 'title' => $txt['pm_preferences'],
  278. 'areas' => array(
  279. 'manlabels' => array(
  280. 'label' => $txt['pm_manage_labels'],
  281. 'custom_url' => $scripturl . '?action=pm;sa=manlabels',
  282. ),
  283. 'manrules' => array(
  284. 'label' => $txt['pm_manage_rules'],
  285. 'custom_url' => $scripturl . '?action=pm;sa=manrules',
  286. ),
  287. 'settings' => array(
  288. 'label' => $txt['pm_settings'],
  289. 'custom_url' => $scripturl . '?action=pm;sa=settings',
  290. ),
  291. ),
  292. ),
  293. );
  294. // Handle labels.
  295. if (empty($context['currently_using_labels']))
  296. unset($pm_areas['labels']);
  297. else
  298. {
  299. // Note we send labels by id as it will have less problems in the querystring.
  300. $unread_in_labels = 0;
  301. foreach ($context['labels'] as $label)
  302. {
  303. if ($label['id'] == -1)
  304. continue;
  305. // Count the amount of unread items in labels.
  306. $unread_in_labels += $label['unread_messages'];
  307. // Add the label to the menu.
  308. $pm_areas['labels']['areas']['label' . $label['id']] = array(
  309. 'label' => $label['name'] . (!empty($label['unread_messages']) ? ' (<strong>' . $label['unread_messages'] . '</strong>)' : ''),
  310. 'custom_url' => $scripturl . '?action=pm;l=' . $label['id'],
  311. 'unread_messages' => $label['unread_messages'],
  312. 'messages' => $label['messages'],
  313. );
  314. }
  315. if (!empty($unread_in_labels))
  316. $pm_areas['labels']['title'] .= ' (' . $unread_in_labels . ')';
  317. }
  318. $pm_areas['folders']['areas']['inbox']['unread_messages'] = &$context['labels'][-1]['unread_messages'];
  319. $pm_areas['folders']['areas']['inbox']['messages'] = &$context['labels'][-1]['messages'];
  320. if (!empty($context['labels'][-1]['unread_messages']))
  321. {
  322. $pm_areas['folders']['areas']['inbox']['label'] .= ' (<strong>' . $context['labels'][-1]['unread_messages'] . '</strong>)';
  323. $pm_areas['folders']['title'] .= ' (' . $context['labels'][-1]['unread_messages'] . ')';
  324. }
  325. // Do we have a limit on the amount of messages we can keep?
  326. if (!empty($context['message_limit']))
  327. {
  328. $bar = round(($user_info['messages'] * 100) / $context['message_limit'], 1);
  329. $context['limit_bar'] = array(
  330. 'messages' => $user_info['messages'],
  331. 'allowed' => $context['message_limit'],
  332. 'percent' => $bar,
  333. 'bar' => $bar > 100 ? 100 : (int) $bar,
  334. 'text' => sprintf($txt['pm_currently_using'], $user_info['messages'], $bar)
  335. );
  336. }
  337. require_once($sourcedir . '/Subs-Menu.php');
  338. // What page is this, again?
  339. $current_page = $scripturl . '?action=pm' . (!empty($_REQUEST['sa']) ? ';sa=' . $_REQUEST['sa'] : '') . (!empty($context['folder']) ? ';f=' . $context['folder'] : '') . (!empty($context['current_label_id']) ? ';l=' . $context['current_label_id'] : '');
  340. // Set a few options for the menu.
  341. $menuOptions = array(
  342. 'current_area' => $area,
  343. 'disable_url_session_check' => true,
  344. 'toggle_url' => $current_page . ';togglebar',
  345. 'toggle_redirect_url' => $current_page,
  346. );
  347. // Actually create the menu!
  348. $pm_include_data = createMenu($pm_areas, $menuOptions);
  349. unset($pm_areas);
  350. // Make a note of the Unique ID for this menu.
  351. $context['pm_menu_id'] = $context['max_menu_id'];
  352. $context['pm_menu_name'] = 'menu_data_' . $context['pm_menu_id'];
  353. // Set the selected item.
  354. $context['menu_item_selected'] = $pm_include_data['current_area'];
  355. // obExit will know what to do!
  356. if (!WIRELESS)
  357. $context['template_layers'][] = 'pm';
  358. }
  359. // A folder, ie. inbox/sent etc.
  360. function MessageFolder()
  361. {
  362. global $txt, $scripturl, $modSettings, $context, $subjects_request;
  363. global $messages_request, $user_info, $recipients, $options, $smcFunc, $memberContext, $user_settings;
  364. // Changing view?
  365. if (isset($_GET['view']))
  366. {
  367. $context['display_mode'] = $context['display_mode'] > 1 ? 0 : $context['display_mode'] + 1;
  368. updateMemberData($user_info['id'], array('pm_prefs' => ($user_settings['pm_prefs'] & 252) | $context['display_mode']));
  369. }
  370. // Make sure the starting location is valid.
  371. if (isset($_GET['start']) && $_GET['start'] != 'new')
  372. $_GET['start'] = (int) $_GET['start'];
  373. elseif (!isset($_GET['start']) && !empty($options['view_newest_pm_first']))
  374. $_GET['start'] = 0;
  375. else
  376. $_GET['start'] = 'new';
  377. // Set up some basic theme stuff.
  378. $context['from_or_to'] = $context['folder'] != 'sent' ? 'from' : 'to';
  379. $context['get_pmessage'] = 'prepareMessageContext';
  380. $context['signature_enabled'] = substr($modSettings['signature_settings'], 0, 1) == 1;
  381. $labelQuery = $context['folder'] != 'sent' ? '
  382. AND FIND_IN_SET(' . $context['current_label_id'] . ', pmr.labels) != 0' : '';
  383. // Set the index bar correct!
  384. messageIndexBar($context['current_label_id'] == -1 ? $context['folder'] : 'label' . $context['current_label_id']);
  385. // Sorting the folder.
  386. $sort_methods = array(
  387. 'date' => 'pm.id_pm',
  388. 'name' => 'IFNULL(mem.real_name, \'\')',
  389. 'subject' => 'pm.subject',
  390. );
  391. // They didn't pick one, use the forum default.
  392. if (!isset($_GET['sort']) || !isset($sort_methods[$_GET['sort']]))
  393. {
  394. $context['sort_by'] = 'date';
  395. $_GET['sort'] = 'pm.id_pm';
  396. // An overriding setting?
  397. $descending = !empty($options['view_newest_pm_first']);
  398. }
  399. // Otherwise use the defaults: ascending, by date.
  400. else
  401. {
  402. $context['sort_by'] = $_GET['sort'];
  403. $_GET['sort'] = $sort_methods[$_GET['sort']];
  404. $descending = isset($_GET['desc']);
  405. }
  406. $context['sort_direction'] = $descending ? 'down' : 'up';
  407. // Why would you want access to your sent items if you're not allowed to send anything?
  408. if ($context['folder'] == 'sent')
  409. isAllowedTo('pm_send');
  410. // Set the text to resemble the current folder.
  411. $pmbox = $context['folder'] != 'sent' ? $txt['inbox'] : $txt['sent_items'];
  412. $txt['delete_all'] = str_replace('PMBOX', $pmbox, $txt['delete_all']);
  413. // Now, build the link tree!
  414. if ($context['current_label_id'] == -1)
  415. $context['linktree'][] = array(
  416. 'url' => $scripturl . '?action=pm;f=' . $context['folder'],
  417. 'name' => $pmbox
  418. );
  419. // Build it further for a label.
  420. if ($context['current_label_id'] != -1)
  421. $context['linktree'][] = array(
  422. 'url' => $scripturl . '?action=pm;f=' . $context['folder'] . ';l=' . $context['current_label_id'],
  423. 'name' => $txt['pm_current_label'] . ': ' . $context['current_label']
  424. );
  425. // Figure out how many messages there are.
  426. if ($context['folder'] == 'sent')
  427. $request = $smcFunc['db_query']('', '
  428. SELECT COUNT(' . ($context['display_mode'] == 2 ? 'DISTINCT pm.id_pm_head' : '*') . ')
  429. FROM {db_prefix}personal_messages AS pm
  430. WHERE pm.id_member_from = {int:current_member}
  431. AND pm.deleted_by_sender = {int:not_deleted}',
  432. array(
  433. 'current_member' => $user_info['id'],
  434. 'not_deleted' => 0,
  435. )
  436. );
  437. else
  438. $request = $smcFunc['db_query']('', '
  439. SELECT COUNT(' . ($context['display_mode'] == 2 ? 'DISTINCT pm.id_pm_head' : '*') . ')
  440. FROM {db_prefix}pm_recipients AS pmr' . ($context['display_mode'] == 2 ? '
  441. INNER JOIN {db_prefix}personal_messages AS pm ON (pm.id_pm = pmr.id_pm)' : '') . '
  442. WHERE pmr.id_member = {int:current_member}
  443. AND pmr.deleted = {int:not_deleted}' . $labelQuery,
  444. array(
  445. 'current_member' => $user_info['id'],
  446. 'not_deleted' => 0,
  447. )
  448. );
  449. list ($max_messages) = $smcFunc['db_fetch_row']($request);
  450. $smcFunc['db_free_result']($request);
  451. // Only show the button if there are messages to delete.
  452. $context['show_delete'] = $max_messages > 0;
  453. // Start on the last page.
  454. if (!is_numeric($_GET['start']) || $_GET['start'] >= $max_messages)
  455. $_GET['start'] = ($max_messages - 1) - (($max_messages - 1) % $modSettings['defaultMaxMessages']);
  456. elseif ($_GET['start'] < 0)
  457. $_GET['start'] = 0;
  458. // ... but wait - what if we want to start from a specific message?
  459. if (isset($_GET['pmid']))
  460. {
  461. $pmID = (int) $_GET['pmid'];
  462. // Make sure you have access to this PM.
  463. if (!isAccessiblePM($pmID, $context['folder'] == 'sent' ? 'outbox' : 'inbox'))
  464. fatal_lang_error('no_access', false);
  465. $context['current_pm'] = $pmID;
  466. // With only one page of PM's we're gonna want page 1.
  467. if ($max_messages <= $modSettings['defaultMaxMessages'])
  468. $_GET['start'] = 0;
  469. // If we pass kstart we assume we're in the right place.
  470. elseif (!isset($_GET['kstart']))
  471. {
  472. if ($context['folder'] == 'sent')
  473. $request = $smcFunc['db_query']('', '
  474. SELECT COUNT(' . ($context['display_mode'] == 2 ? 'DISTINCT pm.id_pm_head' : '*') . ')
  475. FROM {db_prefix}personal_messages
  476. WHERE id_member_from = {int:current_member}
  477. AND deleted_by_sender = {int:not_deleted}
  478. AND id_pm ' . ($descending ? '>' : '<') . ' {int:id_pm}',
  479. array(
  480. 'current_member' => $user_info['id'],
  481. 'not_deleted' => 0,
  482. 'id_pm' => $pmID,
  483. )
  484. );
  485. else
  486. $request = $smcFunc['db_query']('', '
  487. SELECT COUNT(' . ($context['display_mode'] == 2 ? 'DISTINCT pm.id_pm_head' : '*') . ')
  488. FROM {db_prefix}pm_recipients AS pmr' . ($context['display_mode'] == 2 ? '
  489. INNER JOIN {db_prefix}personal_messages AS pm ON (pm.id_pm = pmr.id_pm)' : '') . '
  490. WHERE pmr.id_member = {int:current_member}
  491. AND pmr.deleted = {int:not_deleted}' . $labelQuery . '
  492. AND pmr.id_pm ' . ($descending ? '>' : '<') . ' {int:id_pm}',
  493. array(
  494. 'current_member' => $user_info['id'],
  495. 'not_deleted' => 0,
  496. 'id_pm' => $pmID,
  497. )
  498. );
  499. list ($_GET['start']) = $smcFunc['db_fetch_row']($request);
  500. $smcFunc['db_free_result']($request);
  501. // To stop the page index's being abnormal, start the page on the page the message would normally be located on...
  502. $_GET['start'] = $modSettings['defaultMaxMessages'] * (int) ($_GET['start'] / $modSettings['defaultMaxMessages']);
  503. }
  504. }
  505. // Sanitize and validate pmsg variable if set.
  506. if (isset($_GET['pmsg']))
  507. {
  508. $pmsg = (int) $_GET['pmsg'];
  509. if (!isAccessiblePM($pmsg, $context['folder'] == 'sent' ? 'outbox' : 'inbox'))
  510. fatal_lang_error('no_access', false);
  511. }
  512. // Set up the page index.
  513. $context['page_index'] = constructPageIndex($scripturl . '?action=pm;f=' . $context['folder'] . (isset($_REQUEST['l']) ? ';l=' . (int) $_REQUEST['l'] : '') . ';sort=' . $context['sort_by'] . ($descending ? ';desc' : ''), $_GET['start'], $max_messages, $modSettings['defaultMaxMessages']);
  514. $context['start'] = $_GET['start'];
  515. // Determine the navigation context (especially useful for the wireless template).
  516. $context['links'] = array(
  517. 'first' => $_GET['start'] >= $modSettings['defaultMaxMessages'] ? $scripturl . '?action=pm;start=0' : '',
  518. 'prev' => $_GET['start'] >= $modSettings['defaultMaxMessages'] ? $scripturl . '?action=pm;start=' . ($_GET['start'] - $modSettings['defaultMaxMessages']) : '',
  519. 'next' => $_GET['start'] + $modSettings['defaultMaxMessages'] < $max_messages ? $scripturl . '?action=pm;start=' . ($_GET['start'] + $modSettings['defaultMaxMessages']) : '',
  520. 'last' => $_GET['start'] + $modSettings['defaultMaxMessages'] < $max_messages ? $scripturl . '?action=pm;start=' . (floor(($max_messages - 1) / $modSettings['defaultMaxMessages']) * $modSettings['defaultMaxMessages']) : '',
  521. 'up' => $scripturl,
  522. );
  523. $context['page_info'] = array(
  524. 'current_page' => $_GET['start'] / $modSettings['defaultMaxMessages'] + 1,
  525. 'num_pages' => floor(($max_messages - 1) / $modSettings['defaultMaxMessages']) + 1
  526. );
  527. // First work out what messages we need to see - if grouped is a little trickier...
  528. if ($context['display_mode'] == 2)
  529. {
  530. // On a non-default sort due to PostgreSQL we have to do a harder sort.
  531. if ($smcFunc['db_title'] == 'PostgreSQL' && $_GET['sort'] != 'pm.id_pm')
  532. {
  533. $sub_request = $smcFunc['db_query']('', '
  534. SELECT MAX({raw:sort}) AS sort_param, pm.id_pm_head
  535. FROM {db_prefix}personal_messages AS pm' . ($context['folder'] == 'sent' ? ($context['sort_by'] == 'name' ? '
  536. LEFT JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm)' : '') : '
  537. INNER JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm
  538. AND pmr.id_member = {int:current_member}
  539. AND pmr.deleted = {int:not_deleted}
  540. ' . $labelQuery . ')') . ($context['sort_by'] == 'name' ? ( '
  541. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = {raw:id_member})') : '') . '
  542. WHERE ' . ($context['folder'] == 'sent' ? 'pm.id_member_from = {int:current_member}
  543. AND pm.deleted_by_sender = {int:not_deleted}' : '1=1') . (empty($pmsg) ? '' : '
  544. AND pm.id_pm = {int:id_pm}') . '
  545. GROUP BY pm.id_pm_head
  546. ORDER BY sort_param' . ($descending ? ' DESC' : ' ASC') . (empty($pmsg) ? '
  547. LIMIT ' . $_GET['start'] . ', ' . $modSettings['defaultMaxMessages'] : ''),
  548. array(
  549. 'current_member' => $user_info['id'],
  550. 'not_deleted' => 0,
  551. 'id_member' => $context['folder'] == 'sent' ? 'pmr.id_member' : 'pm.id_member_from',
  552. 'id_pm' => isset($pmsg) ? $pmsg : '0',
  553. 'sort' => $_GET['sort'],
  554. )
  555. );
  556. $sub_pms = array();
  557. while ($row = $smcFunc['db_fetch_assoc']($sub_request))
  558. $sub_pms[$row['id_pm_head']] = $row['sort_param'];
  559. $smcFunc['db_free_result']($sub_request);
  560. $request = $smcFunc['db_query']('', '
  561. SELECT pm.id_pm AS id_pm, pm.id_pm_head
  562. FROM {db_prefix}personal_messages AS pm' . ($context['folder'] == 'sent' ? ($context['sort_by'] == 'name' ? '
  563. LEFT JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm)' : '') : '
  564. INNER JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm
  565. AND pmr.id_member = {int:current_member}
  566. AND pmr.deleted = {int:not_deleted}
  567. ' . $labelQuery . ')') . ($context['sort_by'] == 'name' ? ( '
  568. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = {raw:id_member})') : '') . '
  569. WHERE ' . (empty($sub_pms) ? '0=1' : 'pm.id_pm IN ({array_int:pm_list})') . '
  570. ORDER BY ' . ($_GET['sort'] == 'pm.id_pm' && $context['folder'] != 'sent' ? 'id_pm' : '{raw:sort}') . ($descending ? ' DESC' : ' ASC') . (empty($pmsg) ? '
  571. LIMIT ' . $_GET['start'] . ', ' . $modSettings['defaultMaxMessages'] : ''),
  572. array(
  573. 'current_member' => $user_info['id'],
  574. 'pm_list' => array_keys($sub_pms),
  575. 'not_deleted' => 0,
  576. 'sort' => $_GET['sort'],
  577. 'id_member' => $context['folder'] == 'sent' ? 'pmr.id_member' : 'pm.id_member_from',
  578. )
  579. );
  580. }
  581. else
  582. {
  583. $request = $smcFunc['db_query']('pm_conversation_list', '
  584. SELECT MAX(pm.id_pm) AS id_pm, pm.id_pm_head
  585. FROM {db_prefix}personal_messages AS pm' . ($context['folder'] == 'sent' ? ($context['sort_by'] == 'name' ? '
  586. LEFT JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm)' : '') : '
  587. INNER JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm
  588. AND pmr.id_member = {int:current_member}
  589. AND pmr.deleted = {int:deleted_by}
  590. ' . $labelQuery . ')') . ($context['sort_by'] == 'name' ? ( '
  591. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = {raw:pm_member})') : '') . '
  592. WHERE ' . ($context['folder'] == 'sent' ? 'pm.id_member_from = {int:current_member}
  593. AND pm.deleted_by_sender = {int:deleted_by}' : '1=1') . (empty($pmsg) ? '' : '
  594. AND pm.id_pm = {int:pmsg}') . '
  595. GROUP BY pm.id_pm_head
  596. ORDER BY ' . ($_GET['sort'] == 'pm.id_pm' && $context['folder'] != 'sent' ? 'id_pm' : '{raw:sort}') . ($descending ? ' DESC' : ' ASC') . (empty($_GET['pmsg']) ? '
  597. LIMIT ' . $_GET['start'] . ', ' . $modSettings['defaultMaxMessages'] : ''),
  598. array(
  599. 'current_member' => $user_info['id'],
  600. 'deleted_by' => 0,
  601. 'sort' => $_GET['sort'],
  602. 'pm_member' => $context['folder'] == 'sent' ? 'pmr.id_member' : 'pm.id_member_from',
  603. 'pmsg' => isset($pmsg) ? (int) $pmsg : 0,
  604. )
  605. );
  606. }
  607. }
  608. // This is kinda simple!
  609. else
  610. {
  611. // !!!SLOW This query uses a filesort. (inbox only.)
  612. $request = $smcFunc['db_query']('', '
  613. SELECT pm.id_pm, pm.id_pm_head, pm.id_member_from
  614. FROM {db_prefix}personal_messages AS pm' . ($context['folder'] == 'sent' ? '' . ($context['sort_by'] == 'name' ? '
  615. LEFT JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm)' : '') : '
  616. INNER JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm
  617. AND pmr.id_member = {int:current_member}
  618. AND pmr.deleted = {int:is_deleted}
  619. ' . $labelQuery . ')') . ($context['sort_by'] == 'name' ? ( '
  620. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = {raw:pm_member})') : '') . '
  621. WHERE ' . ($context['folder'] == 'sent' ? 'pm.id_member_from = {raw:current_member}
  622. AND pm.deleted_by_sender = {int:is_deleted}' : '1=1') . (empty($pmsg) ? '' : '
  623. AND pm.id_pm = {int:pmsg}') . '
  624. ORDER BY ' . ($_GET['sort'] == 'pm.id_pm' && $context['folder'] != 'sent' ? 'pmr.id_pm' : '{raw:sort}') . ($descending ? ' DESC' : ' ASC') . (empty($pmsg) ? '
  625. LIMIT ' . $_GET['start'] . ', ' . $modSettings['defaultMaxMessages'] : ''),
  626. array(
  627. 'current_member' => $user_info['id'],
  628. 'is_deleted' => 0,
  629. 'sort' => $_GET['sort'],
  630. 'pm_member' => $context['folder'] == 'sent' ? 'pmr.id_member' : 'pm.id_member_from',
  631. 'pmsg' => isset($pmsg) ? (int) $pmsg : 0,
  632. )
  633. );
  634. }
  635. // Load the id_pms and initialize recipients.
  636. $pms = array();
  637. $lastData = array();
  638. $posters = $context['folder'] == 'sent' ? array($user_info['id']) : array();
  639. $recipients = array();
  640. while ($row = $smcFunc['db_fetch_assoc']($request))
  641. {
  642. if (!isset($recipients[$row['id_pm']]))
  643. {
  644. if (isset($row['id_member_from']))
  645. $posters[$row['id_pm']] = $row['id_member_from'];
  646. $pms[$row['id_pm']] = $row['id_pm'];
  647. $recipients[$row['id_pm']] = array(
  648. 'to' => array(),
  649. 'bcc' => array()
  650. );
  651. }
  652. // Keep track of the last message so we know what the head is without another query!
  653. if ((empty($pmID) && (empty($options['view_newest_pm_first']) || !isset($lastData))) || empty($lastData) || (!empty($pmID) && $pmID == $row['id_pm']))
  654. $lastData = array(
  655. 'id' => $row['id_pm'],
  656. 'head' => $row['id_pm_head'],
  657. );
  658. }
  659. $smcFunc['db_free_result']($request);
  660. // Make sure that we have been given a correct head pm id!
  661. if ($context['display_mode'] == 2 && !empty($pmID) && $pmID != $lastData['id'])
  662. fatal_lang_error('no_access', false);
  663. if (!empty($pms))
  664. {
  665. // Select the correct current message.
  666. if (empty($pmID))
  667. $context['current_pm'] = $lastData['id'];
  668. // This is a list of the pm's that are used for "full" display.
  669. if ($context['display_mode'] == 0)
  670. $display_pms = $pms;
  671. else
  672. $display_pms = array($context['current_pm']);
  673. // At this point we know the main id_pm's. But - if we are looking at conversations we need the others!
  674. if ($context['display_mode'] == 2)
  675. {
  676. $request = $smcFunc['db_query']('', '
  677. SELECT pm.id_pm, pm.id_member_from, pm.deleted_by_sender, pmr.id_member, pmr.deleted
  678. FROM {db_prefix}personal_messages AS pm
  679. INNER JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm)
  680. WHERE pm.id_pm_head = {int:id_pm_head}
  681. AND ((pm.id_member_from = {int:current_member} AND pm.deleted_by_sender = {int:not_deleted})
  682. OR (pmr.id_member = {int:current_member} AND pmr.deleted = {int:not_deleted}))
  683. ORDER BY pm.id_pm',
  684. array(
  685. 'current_member' => $user_info['id'],
  686. 'id_pm_head' => $lastData['head'],
  687. 'not_deleted' => 0,
  688. )
  689. );
  690. while ($row = $smcFunc['db_fetch_assoc']($request))
  691. {
  692. // This is, frankly, a joke. We will put in a workaround for people sending to themselves - yawn!
  693. if ($context['folder'] == 'sent' && $row['id_member_from'] == $user_info['id'] && $row['deleted_by_sender'] == 1)
  694. continue;
  695. elseif ($row['id_member'] == $user_info['id'] & $row['deleted'] == 1)
  696. continue;
  697. if (!isset($recipients[$row['id_pm']]))
  698. $recipients[$row['id_pm']] = array(
  699. 'to' => array(),
  700. 'bcc' => array()
  701. );
  702. $display_pms[] = $row['id_pm'];
  703. $posters[$row['id_pm']] = $row['id_member_from'];
  704. }
  705. $smcFunc['db_free_result']($request);
  706. }
  707. // This is pretty much EVERY pm!
  708. $all_pms = array_merge($pms, $display_pms);
  709. $all_pms = array_unique($all_pms);
  710. // Get recipients (don't include bcc-recipients for your inbox, you're not supposed to know :P).
  711. $request = $smcFunc['db_query']('', '
  712. SELECT pmr.id_pm, mem_to.id_member AS id_member_to, mem_to.real_name AS to_name, pmr.bcc, pmr.labels, pmr.is_read
  713. FROM {db_prefix}pm_recipients AS pmr
  714. LEFT JOIN {db_prefix}members AS mem_to ON (mem_to.id_member = pmr.id_member)
  715. WHERE pmr.id_pm IN ({array_int:pm_list})',
  716. array(
  717. 'pm_list' => $all_pms,
  718. )
  719. );
  720. $context['message_labels'] = array();
  721. $context['message_replied'] = array();
  722. $context['message_unread'] = array();
  723. while ($row = $smcFunc['db_fetch_assoc']($request))
  724. {
  725. if ($context['folder'] == 'sent' || empty($row['bcc']))
  726. $recipients[$row['id_pm']][empty($row['bcc']) ? 'to' : 'bcc'][] = empty($row['id_member_to']) ? $txt['guest_title'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member_to'] . '">' . $row['to_name'] . '</a>';
  727. if ($row['id_member_to'] == $user_info['id'] && $context['folder'] != 'sent')
  728. {
  729. $context['message_replied'][$row['id_pm']] = $row['is_read'] & 2;
  730. $context['message_unread'][$row['id_pm']] = $row['is_read'] == 0;
  731. $row['labels'] = $row['labels'] == '' ? array() : explode(',', $row['labels']);
  732. foreach ($row['labels'] as $v)
  733. {
  734. if (isset($context['labels'][(int) $v]))
  735. $context['message_labels'][$row['id_pm']][(int) $v] = array('id' => $v, 'name' => $context['labels'][(int) $v]['name']);
  736. }
  737. }
  738. }
  739. $smcFunc['db_free_result']($request);
  740. // Make sure we don't load unnecessary data.
  741. if ($context['display_mode'] == 1)
  742. {
  743. foreach ($posters as $k => $v)
  744. if (!in_array($k, $display_pms))
  745. unset($posters[$k]);
  746. }
  747. // Load any users....
  748. $posters = array_unique($posters);
  749. if (!empty($posters))
  750. loadMemberData($posters);
  751. // If we're on grouped/restricted view get a restricted list of messages.
  752. if ($context['display_mode'] != 0)
  753. {
  754. // Get the order right.
  755. $orderBy = array();
  756. foreach (array_reverse($pms) as $pm)
  757. $orderBy[] = 'pm.id_pm = ' . $pm;
  758. // Seperate query for these bits!
  759. $subjects_request = $smcFunc['db_query']('', '
  760. SELECT pm.id_pm, pm.subject, pm.id_member_from, pm.msgtime, IFNULL(mem.real_name, pm.from_name) AS from_name,
  761. IFNULL(mem.id_member, 0) AS not_guest
  762. FROM {db_prefix}personal_messages AS pm
  763. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = pm.id_member_from)
  764. WHERE pm.id_pm IN ({array_int:pm_list})
  765. ORDER BY ' . implode(', ', $orderBy) . '
  766. LIMIT ' . count($pms),
  767. array(
  768. 'pm_list' => $pms,
  769. )
  770. );
  771. }
  772. // Execute the query!
  773. $messages_request = $smcFunc['db_query']('', '
  774. SELECT pm.id_pm, pm.subject, pm.id_member_from, pm.body, pm.msgtime, pm.from_name
  775. FROM {db_prefix}personal_messages AS pm' . ($context['folder'] == 'sent' ? '
  776. LEFT JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm)' : '') . ($context['sort_by'] == 'name' ? '
  777. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = {raw:id_member})' : '') . '
  778. WHERE pm.id_pm IN ({array_int:display_pms})' . ($context['folder'] == 'sent' ? '
  779. GROUP BY pm.id_pm, pm.subject, pm.id_member_from, pm.body, pm.msgtime, pm.from_name' : '') . '
  780. ORDER BY ' . ($context['display_mode'] == 2 ? 'pm.id_pm' : $_GET['sort']) . ($descending ? ' DESC' : ' ASC') . '
  781. LIMIT ' . count($display_pms),
  782. array(
  783. 'display_pms' => $display_pms,
  784. 'id_member' => $context['folder'] == 'sent' ? 'pmr.id_member' : 'pm.id_member_from',
  785. )
  786. );
  787. }
  788. else
  789. $messages_request = false;
  790. $context['can_send_pm'] = allowedTo('pm_send');
  791. if (!WIRELESS)
  792. $context['sub_template'] = 'folder';
  793. $context['page_title'] = $txt['pm_inbox'];
  794. // Finally mark the relevant messages as read.
  795. if ($context['folder'] != 'sent' && !empty($context['labels'][(int) $context['current_label_id']]['unread_messages']))
  796. {
  797. // If the display mode is "old sk00l" do them all...
  798. if ($context['display_mode'] == 0)
  799. markMessages(null, $context['current_label_id']);
  800. // Otherwise do just the current one!
  801. elseif (!empty($context['current_pm']))
  802. markMessages($display_pms, $context['current_label_id']);
  803. }
  804. }
  805. // Get a personal message for the theme. (used to save memory.)
  806. function prepareMessageContext($type = 'subject', $reset = false)
  807. {
  808. global $txt, $scripturl, $modSettings, $context, $messages_request, $memberContext, $recipients, $smcFunc;
  809. global $user_info, $subjects_request;
  810. // Count the current message number....
  811. static $counter = null;
  812. if ($counter === null || $reset)
  813. $counter = $context['start'];
  814. static $temp_pm_selected = null;
  815. if ($temp_pm_selected === null)
  816. {
  817. $temp_pm_selected = isset($_SESSION['pm_selected']) ? $_SESSION['pm_selected'] : array();
  818. $_SESSION['pm_selected'] = array();
  819. }
  820. // If we're in non-boring view do something exciting!
  821. if ($context['display_mode'] != 0 && $subjects_request && $type == 'subject')
  822. {
  823. $subject = $smcFunc['db_fetch_assoc']($subjects_request);
  824. if (!$subject)
  825. {
  826. $smcFunc['db_free_result']($subjects_request);
  827. return false;
  828. }
  829. $subject['subject'] = $subject['subject'] == '' ? $txt['no_subject'] : $subject['subject'];
  830. censorText($subject['subject']);
  831. $output = array(
  832. 'id' => $subject['id_pm'],
  833. 'member' => array(
  834. 'id' => $subject['id_member_from'],
  835. 'name' => $subject['from_name'],
  836. 'link' => $subject['not_guest'] ? '<a href="' . $scripturl . '?action=profile;u=' . $subject['id_member_from'] . '">' . $subject['from_name'] . '</a>' : $subject['from_name'],
  837. ),
  838. 'recipients' => &$recipients[$subject['id_pm']],
  839. 'subject' => $subject['subject'],
  840. 'time' => timeformat($subject['msgtime']),
  841. 'timestamp' => forum_time(true, $subject['msgtime']),
  842. 'number_recipients' => count($recipients[$subject['id_pm']]['to']),
  843. 'labels' => &$context['message_labels'][$subject['id_pm']],
  844. 'fully_labeled' => count($context['message_labels'][$subject['id_pm']]) == count($context['labels']),
  845. 'is_replied_to' => &$context['message_replied'][$subject['id_pm']],
  846. 'is_unread' => &$context['message_unread'][$subject['id_pm']],
  847. 'is_selected' => !empty($temp_pm_selected) && in_array($subject['id_pm'], $temp_pm_selected),
  848. );
  849. return $output;
  850. }
  851. // Bail if it's false, ie. no messages.
  852. if ($messages_request == false)
  853. return false;
  854. // Reset the data?
  855. if ($reset == true)
  856. return @$smcFunc['db_data_seek']($messages_request, 0);
  857. // Get the next one... bail if anything goes wrong.
  858. $message = $smcFunc['db_fetch_assoc']($messages_request);
  859. if (!$message)
  860. {
  861. if ($type != 'subject')
  862. $smcFunc['db_free_result']($messages_request);
  863. return false;
  864. }
  865. // Use '(no subject)' if none was specified.
  866. $message['subject'] = $message['subject'] == '' ? $txt['no_subject'] : $message['subject'];
  867. // Load the message's information - if it's not there, load the guest information.
  868. if (!loadMemberContext($message['id_member_from'], true))
  869. {
  870. $memberContext[$message['id_member_from']]['name'] = $message['from_name'];
  871. $memberContext[$message['id_member_from']]['id'] = 0;
  872. // Sometimes the forum sends messages itself (Warnings are an example) - in this case don't label it from a guest.
  873. $memberContext[$message['id_member_from']]['group'] = $message['from_name'] == $context['forum_name'] ? '' : $txt['guest_title'];
  874. $memberContext[$message['id_member_from']]['link'] = $message['from_name'];
  875. $memberContext[$message['id_member_from']]['email'] = '';
  876. $memberContext[$message['id_member_from']]['show_email'] = showEmailAddress(true, 0);
  877. $memberContext[$message['id_member_from']]['is_guest'] = true;
  878. }
  879. else
  880. {
  881. $memberContext[$message['id_member_from']]['can_view_profile'] = allowedTo('profile_view_any') || ($message['id_member_from'] == $user_info['id'] && allowedTo('profile_view_own'));
  882. $memberContext[$message['id_member_from']]['can_see_warning'] = !isset($context['disabled_fields']['warning_status']) && $memberContext[$message['id_member_from']]['warning_status'] && ($context['user']['can_mod'] || (!empty($modSettings['warning_show']) && ($modSettings['warning_show'] > 1 || $message['id_member_from'] == $user_info['id'])));
  883. }
  884. // Censor all the important text...
  885. censorText($message['body']);
  886. censorText($message['subject']);
  887. // Run UBBC interpreter on the message.
  888. $message['body'] = parse_bbc($message['body'], true, 'pm' . $message['id_pm']);
  889. // Send the array.
  890. $output = array(
  891. 'alternate' => $counter % 2,
  892. 'id' => $message['id_pm'],
  893. 'member' => &$memberContext[$message['id_member_from']],
  894. 'subject' => $message['subject'],
  895. 'time' => timeformat($message['msgtime']),
  896. 'timestamp' => forum_time(true, $message['msgtime']),
  897. 'counter' => $counter,
  898. 'body' => $message['body'],
  899. 'recipients' => &$recipients[$message['id_pm']],
  900. 'number_recipients' => count($recipients[$message['id_pm']]['to']),
  901. 'labels' => &$context['message_labels'][$message['id_pm']],
  902. 'fully_labeled' => count($context['message_labels'][$message['id_pm']]) == count($context['labels']),
  903. 'is_replied_to' => &$context['message_replied'][$message['id_pm']],
  904. 'is_unread' => &$context['message_unread'][$message['id_pm']],
  905. 'is_selected' => !empty($temp_pm_selected) && in_array($message['id_pm'], $temp_pm_selected),
  906. );
  907. $counter++;
  908. return $output;
  909. }
  910. function MessageSearch()
  911. {
  912. global $context, $txt, $scripturl, $modSettings, $smcFunc;
  913. if (isset($_REQUEST['params']))
  914. {
  915. $temp_params = explode('|"|', base64_decode(strtr($_REQUEST['params'], array(' ' => '+'))));
  916. $context['search_params'] = array();
  917. foreach ($temp_params as $i => $data)
  918. {
  919. @list ($k, $v) = explode('|\'|', $data);
  920. $context['search_params'][$k] = $v;
  921. }
  922. }
  923. if (isset($_REQUEST['search']))
  924. $context['search_params']['search'] = un_htmlspecialchars($_REQUEST['search']);
  925. if (isset($context['search_params']['search']))
  926. $context['search_params']['search'] = htmlspecialchars($context['search_params']['search']);
  927. if (isset($context['search_params']['userspec']))
  928. $context['search_params']['userspec'] = htmlspecialchars($context['search_params']['userspec']);
  929. if (!empty($context['search_params']['searchtype']))
  930. $context['search_params']['searchtype'] = 2;
  931. if (!empty($context['search_params']['minage']))
  932. $context['search_params']['minage'] = (int) $context['search_params']['minage'];
  933. if (!empty($context['search_params']['maxage']))
  934. $context['search_params']['maxage'] = (int) $context['search_params']['maxage'];
  935. $context['search_params']['subject_only'] = !empty($context['search_params']['subject_only']);
  936. $context['search_params']['show_complete'] = !empty($context['search_params']['show_complete']);
  937. // Create the array of labels to be searched.
  938. $context['search_labels'] = array();
  939. $searchedLabels = isset($context['search_params']['labels']) && $context['search_params']['labels'] != '' ? explode(',', $context['search_params']['labels']) : array();
  940. foreach ($context['labels'] as $label)
  941. {
  942. $context['search_labels'][] = array(
  943. 'id' => $label['id'],
  944. 'name' => $label['name'],
  945. 'checked' => !empty($searchedLabels) ? in_array($label['id'], $searchedLabels) : true,
  946. );
  947. }
  948. // Are all the labels checked?
  949. $context['check_all'] = empty($searchedLabels) || count($context['search_labels']) == count($searchedLabels);
  950. // Load the error text strings if there were errors in the search.
  951. if (!empty($context['search_errors']))
  952. {
  953. loadLanguage('Errors');
  954. $context['search_errors']['messages'] = array();
  955. foreach ($context['search_errors'] as $search_error => $dummy)
  956. {
  957. if ($search_error == 'messages')
  958. continue;
  959. $context['search_errors']['messages'][] = $txt['error_' . $search_error];
  960. }
  961. }
  962. $context['simple_search'] = isset($context['search_params']['advanced']) ? empty($context['search_params']['advanced']) : !empty($modSettings['simpleSearch']) && !isset($_REQUEST['advanced']);
  963. $context['page_title'] = $txt['pm_search_title'];
  964. $context['sub_template'] = 'search';
  965. $context['linktree'][] = array(
  966. 'url' => $scripturl . '?action=pm;sa=search',
  967. 'name' => $txt['pm_search_bar_title'],
  968. );
  969. }
  970. function MessageSearch2()
  971. {
  972. global $scripturl, $modSettings, $user_info, $context, $txt;
  973. global $memberContext, $smcFunc;
  974. if (!empty($context['load_average']) && !empty($modSettings['loadavg_search']) && $context['load_average'] >= $modSettings['loadavg_search'])
  975. fatal_lang_error('loadavg_search_disabled', false);
  976. // !!! For the moment force the folder to the inbox.
  977. $context['folder'] = 'inbox';
  978. // Some useful general permissions.
  979. $context['can_send_pm'] = allowedTo('pm_send');
  980. // Some hardcoded veriables that can be tweaked if required.
  981. $maxMembersToSearch = 500;
  982. // Extract all the search parameters.
  983. $search_params = array();
  984. if (isset($_REQUEST['params']))
  985. {
  986. $temp_params = explode('|"|', base64_decode(strtr($_REQUEST['params'], array(' ' => '+'))));
  987. foreach ($temp_params as $i => $data)
  988. {
  989. @list ($k, $v) = explode('|\'|', $data);
  990. $search_params[$k] = $v;
  991. }
  992. }
  993. $context['start'] = isset($_GET['start']) ? (int) $_GET['start'] : 0;
  994. // Store whether simple search was used (needed if the user wants to do another query).
  995. if (!isset($search_params['advanced']))
  996. $search_params['advanced'] = empty($_REQUEST['advanced']) ? 0 : 1;
  997. // 1 => 'allwords' (default, don't set as param) / 2 => 'anywords'.
  998. if (!empty($search_params['searchtype']) || (!empty($_REQUEST['searchtype']) && $_REQUEST['searchtype'] == 2))
  999. $search_params['searchtype'] = 2;
  1000. // Minimum age of messages. Default to zero (don't set param in that case).
  1001. if (!empty($search_params['minage']) || (!empty($_REQUEST['minage']) && $_REQUEST['minage'] > 0))
  1002. $search_params['minage'] = !empty($search_params['minage']) ? (int) $search_params['minage'] : (int) $_REQUEST['minage'];
  1003. // Maximum age of messages. Default to infinite (9999 days: param not set).
  1004. if (!empty($search_params['maxage']) || (!empty($_REQUEST['maxage']) && $_REQUEST['maxage'] != 9999))
  1005. $search_params['maxage'] = !empty($search_params['maxage']) ? (int) $search_params['maxage'] : (int) $_REQUEST['maxage'];
  1006. $search_params['subject_only'] = !empty($search_params['subject_only']) || !empty($_REQUEST['subject_only']);
  1007. $search_params['show_complete'] = !empty($search_params['show_complete']) || !empty($_REQUEST['show_complete']);
  1008. // Default the user name to a wildcard matching every user (*).
  1009. if (!empty($search_params['user_spec']) || (!empty($_REQUEST['userspec']) && $_REQUEST['userspec'] != '*'))
  1010. $search_params['userspec'] = isset($search_params['userspec']) ? $search_params['userspec'] : $_REQUEST['userspec'];
  1011. // This will be full of all kinds of parameters!
  1012. $searchq_parameters = array();
  1013. // If there's no specific user, then don't mention it in the main query.
  1014. if (empty($search_params['userspec']))
  1015. $userQuery = '';
  1016. else
  1017. {
  1018. $userString = strtr($smcFunc['htmlspecialchars']($search_params['userspec'], ENT_QUOTES), array('&quot;' => '"'));
  1019. $userString = strtr($userString, array('%' => '\%', '_' => '\_', '*' => '%', '?' => '_'));
  1020. preg_match_all('~"([^"]+)"~', $userString, $matches);
  1021. $possible_users = array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $userString)));
  1022. for ($k = 0, $n = count($possible_users); $k < $n; $k++)
  1023. {
  1024. $possible_users[$k] = trim($possible_users[$k]);
  1025. if (strlen($possible_users[$k]) == 0)
  1026. unset($possible_users[$k]);
  1027. }
  1028. // Who matches those criteria?
  1029. // !!! This doesn't support sent item searching.
  1030. $request = $smcFunc['db_query']('', '
  1031. SELECT id_member
  1032. FROM {db_prefix}members
  1033. WHERE real_name LIKE {raw:real_name_implode}',
  1034. array(
  1035. 'real_name_implode' => '\'' . implode('\' OR real_name LIKE \'', $possible_users) . '\'',
  1036. )
  1037. );
  1038. // Simply do nothing if there're too many members matching the criteria.
  1039. if ($smcFunc['db_num_rows']($request) > $maxMembersToSearch)
  1040. $userQuery = '';
  1041. elseif ($smcFunc['db_num_rows']($request) == 0)
  1042. {
  1043. $userQuery = 'AND pm.id_member_from = 0 AND (pm.from_name LIKE {raw:guest_user_name_implode})';
  1044. $searchq_parameters['guest_user_name_implode'] = '\'' . implode('\' OR pm.from_name LIKE \'', $possible_users) . '\'';
  1045. }
  1046. else
  1047. {
  1048. $memberlist = array();
  1049. while ($row = $smcFunc['db_fetch_assoc']($request))
  1050. $memberlist[] = $row['id_member'];
  1051. $userQuery = 'AND (pm.id_member_from IN ({array_int:member_list}) OR (pm.id_member_from = 0 AND (pm.from_name LIKE {raw:guest_user_name_implode})))';
  1052. $searchq_parameters['guest_user_name_implode'] = '\'' . implode('\' OR pm.from_name LIKE \'', $possible_users) . '\'';
  1053. $searchq_parameters['member_list'] = $memberlist;
  1054. }
  1055. $smcFunc['db_free_result']($request);
  1056. }
  1057. // Setup the sorting variables...
  1058. // !!! Add more in here!
  1059. $sort_columns = array(
  1060. 'pm.id_pm',
  1061. );
  1062. if (empty($search_params['sort']) && !empty($_REQUEST['sort']))
  1063. list ($search_params['sort'], $search_params['sort_dir']) = array_pad(explode('|', $_REQUEST['sort']), 2, '');
  1064. $search_params['sort'] = !empty($search_params['sort']) && in_array($search_params['sort'], $sort_columns) ? $search_params['sort'] : 'pm.id_pm';
  1065. $search_params['sort_dir'] = !empty($search_params['sort_dir']) && $search_params['sort_dir'] == 'asc' ? 'asc' : 'desc';
  1066. // Sort out any labels we may be searching by.
  1067. $labelQuery = '';
  1068. if ($context['folder'] == 'inbox' && !empty($search_params['advanced']) && $context['currently_using_labels'])
  1069. {
  1070. // Came here from pagination? Put them back into $_REQUEST for sanitization.
  1071. if (isset($search_params['labels']))
  1072. $_REQUEST['searchlabel'] = explode(',', $search_params['labels']);
  1073. // Assuming we have some labels - make them all integers.
  1074. if (!empty($_REQUEST['searchlabel']) && is_array($_REQUEST['searchlabel']))
  1075. {
  1076. foreach ($_REQUEST['searchlabel'] as $key => $id)
  1077. $_REQUEST['searchlabel'][$key] = (int) $id;
  1078. }
  1079. else
  1080. $_REQUEST['searchlabel'] = array();
  1081. // Now that everything is cleaned up a bit, make the labels a param.
  1082. $search_params['labels'] = implode(',', $_REQUEST['searchlabel']);
  1083. // No labels selected? That must be an error!
  1084. if (empty($_REQUEST['searchlabel']))
  1085. $context['search_errors']['no_labels_selected'] = true;
  1086. // Otherwise prepare the query!
  1087. elseif (count($_REQUEST['searchlabel']) != count($context['labels']))
  1088. {
  1089. $labelQuery = '
  1090. AND {raw:label_implode}';
  1091. $labelStatements = array();
  1092. foreach ($_REQUEST['searchlabel'] as $label)
  1093. $labelStatements[] = $smcFunc['db_quote']('FIND_IN_SET({string:label}, pmr.labels) != 0', array(
  1094. 'label' => $label,
  1095. ));
  1096. $searchq_parameters['label_implode'] = '(' . implode(' OR ', $labelStatements) . ')';
  1097. }
  1098. }
  1099. // What are we actually searching for?
  1100. $search_params['search'] = !empty($search_params['search']) ? $search_params['search'] : (isset($_REQUEST['search']) ? $_REQUEST['search'] : '');
  1101. // If we ain't got nothing - we should error!
  1102. if (!isset($search_params['search']) || $search_params['search'] == '')
  1103. $context['search_errors']['invalid_search_string'] = true;
  1104. // Extract phrase parts first (e.g. some words "this is a phrase" some more words.)
  1105. preg_match_all('~(?:^|\s)([-]?)"([^"]+)"(?:$|\s)~' . ($context['utf8'] ? 'u' : ''), $search_params['search'], $matches, PREG_PATTERN_ORDER);
  1106. $searchArray = $matches[2];
  1107. // Remove the phrase parts and extract the words.
  1108. $tempSearch = explode(' ', preg_replace('~(?:^|\s)(?:[-]?)"(?:[^"]+)"(?:$|\s)~' . ($context['utf8'] ? 'u' : ''), ' ', $search_params['search']));
  1109. // A minus sign in front of a word excludes the word.... so...
  1110. $excludedWords = array();
  1111. // .. first, we check for things like -"some words", but not "-some words".
  1112. foreach ($matches[1] as $index => $word)
  1113. if ($word == '-')
  1114. {
  1115. $word = $smcFunc['strtolower'](trim($searchArray[$index]));
  1116. if (strlen($word) > 0)
  1117. $excludedWords[] = $word;
  1118. unset($searchArray[$index]);
  1119. }
  1120. // Now we look for -test, etc.... normaller.
  1121. foreach ($tempSearch as $index => $word)
  1122. if (strpos(trim($word), '-') === 0)
  1123. {
  1124. $word = substr($smcFunc['strtolower'](trim($word)), 1);
  1125. if (strlen($word) > 0)
  1126. $excludedWords[] = $word;
  1127. unset($tempSearch[$index]);
  1128. }
  1129. $searchArray = array_merge($searchArray, $tempSearch);
  1130. // Trim everything and make sure there are no words that are the same.
  1131. foreach ($searchArray as $index => $value)
  1132. {
  1133. $searchArray[$index] = $smcFunc['strtolower'](trim($value));
  1134. if ($searchArray[$index] == '')
  1135. unset($searchArray[$index]);
  1136. else
  1137. {
  1138. // Sort out entities first.
  1139. $searchArray[$index] = $smcFunc['htmlspecialchars']($searchArray[$index]);
  1140. }
  1141. }
  1142. $searchArray = array_unique($searchArray);
  1143. // Create an array of replacements for highlighting.
  1144. $context['mark'] = array();
  1145. foreach ($searchArray as $word)
  1146. $context['mark'][$word] = '<strong class="highlight">' . $word . '</strong>';
  1147. // This contains *everything*
  1148. $searchWords = array_merge($searchArray, $excludedWords);
  1149. // Make sure at least one word is being searched for.
  1150. if (empty($searchArray))
  1151. $context['search_errors']['invalid_search_string'] = true;
  1152. // Sort out the search query so the user can edit it - if they want.
  1153. $context['search_params'] = $search_params;
  1154. if (isset($context['search_params']['search']))
  1155. $context['search_params']['search'] = htmlspecialchars($context['search_params']['search']);
  1156. if (isset($context['search_params']['userspec']))
  1157. $context['search_params']['userspec'] = htmlspecialchars($context['search_params']['userspec']);
  1158. // Now we have all the parameters, combine them together for pagination and the like...
  1159. $context['params'] = array();
  1160. foreach ($search_params as $k => $v)
  1161. $context['params'][] = $k . '|\'|' . $v;
  1162. $context['params'] = base64_encode(implode('|"|', $context['params']));
  1163. // Compile the subject query part.
  1164. $andQueryParts = array();
  1165. foreach ($searchWords as $index => $word)
  1166. {
  1167. if ($word == '')
  1168. continue;
  1169. if ($search_params['subject_only'])
  1170. $andQueryParts[] = 'pm.subject' . (in_array($word, $excludedWords) ? ' NOT' : '') . ' LIKE {string:search_' . $index . '}';
  1171. else
  1172. $andQueryParts[] = '(pm.subject' . (in_array($word, $excludedWords) ? ' NOT' : '') . ' LIKE {string:search_' . $index . '} ' . (in_array($word, $excludedWords) ? 'AND pm.body NOT' : 'OR pm.body') . ' LIKE {string:search_' . $index . '})';
  1173. $searchq_parameters['search_' . $index] = '%' . strtr($word, array('_' => '\\_', '%' => '\\%')) . '%';
  1174. }
  1175. $searchQuery = ' 1=1';
  1176. if (!empty($andQueryParts))
  1177. $searchQuery = implode(!empty($search_params['searchtype']) && $search_params['searchtype'] == 2 ? ' OR ' : ' AND ', $andQueryParts);
  1178. // Age limits?
  1179. $timeQuery = '';
  1180. if (!empty($search_params['minage']))
  1181. $timeQuery .= ' AND pm.msgtime < ' . (time() - $search_params['minage'] * 86400);
  1182. if (!empty($search_params['maxage']))
  1183. $timeQuery .= ' AND pm.msgtime > ' . (time() - $search_params['maxage'] * 86400);
  1184. // If we have errors - return back to the first screen...
  1185. if (!empty($context['search_errors']))
  1186. {
  1187. $_REQUEST['params'] = $context['params'];
  1188. return MessageSearch();
  1189. }
  1190. // Get the amount of results.
  1191. $request = $smcFunc['db_query']('', '
  1192. SELECT COUNT(*)
  1193. FROM {db_prefix}pm_recipients AS pmr
  1194. INNER JOIN {db_prefix}personal_messages AS pm ON (pm.id_pm = pmr.id_pm)
  1195. WHERE ' . ($context['folder'] == 'inbox' ? '
  1196. pmr.id_member = {int:current_member}
  1197. AND pmr.deleted = {int:not_deleted}' : '
  1198. pm.id_member_from = {int:current_member}
  1199. AND pm.deleted_by_sender = {int:not_deleted}') . '
  1200. ' . $userQuery . $labelQuery . $timeQuery . '
  1201. AND (' . $searchQuery . ')',
  1202. array_merge($searchq_parameters, array(
  1203. 'current_member' => $user_info['id'],
  1204. 'not_deleted' => 0,
  1205. ))
  1206. );
  1207. list ($numResults) = $smcFunc['db_fetch_row']($request);
  1208. $smcFunc['db_free_result']($request);
  1209. // Get all the matching messages... using standard search only (No caching and the like!)
  1210. // !!! This doesn't support sent item searching yet.
  1211. $request = $smcFunc['db_query']('', '
  1212. SELECT pm.id_pm, pm.id_pm_head, pm.id_member_from
  1213. FROM {db_prefix}pm_recipients AS pmr
  1214. INNER JOIN {db_prefix}personal_messages AS pm ON (pm.id_pm = pmr.id_pm)
  1215. WHERE ' . ($context['folder'] == 'inbox' ? '
  1216. pmr.id_member = {int:current_member}
  1217. AND pmr.deleted = {int:not_deleted}' : '
  1218. pm.id_member_from = {int:current_member}
  1219. AND pm.deleted_by_sender = {int:not_deleted}') . '
  1220. ' . $userQuery . $labelQuery . $timeQuery . '
  1221. AND (' . $searchQuery . ')
  1222. ORDER BY ' . $search_params['sort'] . ' ' . $search_params['sort_dir'] . '
  1223. LIMIT ' . $context['start'] . ', ' . $modSettings['search_results_per_page'],
  1224. array_merge($searchq_parameters, array(
  1225. 'current_member' => $user_info['id'],
  1226. 'not_deleted' => 0,
  1227. ))
  1228. );
  1229. $foundMessages = array();
  1230. $posters = array();
  1231. $head_pms = array();
  1232. while ($row = $smcFunc['db_fetch_assoc']($request))
  1233. {
  1234. $foundMessages[] = $row['id_pm'];
  1235. $posters[] = $row['id_member_from'];
  1236. $head_pms[$row['id_pm']] = $row['id_pm_head'];
  1237. }
  1238. $smcFunc['db_free_result']($request);
  1239. // Find the real head pms!
  1240. if ($context['display_mode'] == 2 && !empty($head_pms))
  1241. {
  1242. $request = $smcFunc['db_query']('', '
  1243. SELECT MAX(pm.id_pm) AS id_pm, pm.id_pm_head
  1244. FROM {db_prefix}personal_messages AS pm
  1245. INNER JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm)
  1246. WHERE pm.id_pm_head IN ({array_int:head_pms})
  1247. AND pmr.id_member = {int:current_member}
  1248. AND pmr.deleted = {int:not_deleted}
  1249. GROUP BY pm.id_pm_head
  1250. LIMIT {int:limit}',
  1251. array(
  1252. 'head_pms' => array_unique($head_pms),
  1253. 'current_member' => $user_info['id'],
  1254. 'not_deleted' => 0,
  1255. 'limit' => count($head_pms),
  1256. )
  1257. );
  1258. $real_pm_ids = array();
  1259. while ($row = $smcFunc['db_fetch_assoc']($request))
  1260. $real_pm_ids[$row['id_pm_head']] = $row['id_pm'];
  1261. $smcFunc['db_free_result']($request);
  1262. }
  1263. // Load the users...
  1264. $posters = array_unique($posters);
  1265. if (!empty($posters))
  1266. loadMemberData($posters);
  1267. // Sort out the page index.
  1268. $context['page_index'] = constructPageIndex($scripturl . '?action=pm;sa=search2;params=' . $context['params'], $_GET['start'], $numResults, $modSettings['search_results_per_page'], false);
  1269. $context['message_labels'] = array();
  1270. $context['message_replied'] = array();
  1271. $context['personal_messages'] = array();
  1272. if (!empty($foundMessages))
  1273. {
  1274. // Now get recipients (but don't include bcc-recipients for your inbox, you're not supposed to know :P!)
  1275. $request = $smcFunc['db_query']('', '
  1276. SELECT
  1277. pmr.id_pm, mem_to.id_member AS id_member_to, mem_to.real_name AS to_name,
  1278. pmr.bcc, pmr.labels, pmr.is_read
  1279. FROM {db_prefix}pm_recipients AS pmr
  1280. LEFT JOIN {db_prefix}members AS mem_to ON (mem_to.id_member = pmr.id_member)
  1281. WHERE pmr.id_pm IN ({array_int:message_list})',
  1282. array(
  1283. 'message_list' => $foundMessages,
  1284. )
  1285. );
  1286. while ($row = $smcFunc['db_fetch_assoc']($request))
  1287. {
  1288. if ($context['folder'] == 'sent' || empty($row['bcc']))
  1289. $recipients[$row['id_pm']][empty($row['bcc']) ? 'to' : 'bcc'][] = empty($row['id_member_to']) ? $txt['guest_title'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member_to'] . '">' . $row['to_name'] . '</a>';
  1290. if ($row['id_member_to'] == $user_info['id'] && $context['folder'] != 'sent')
  1291. {
  1292. $context['message_replied'][$row['id_pm']] = $row['is_read'] & 2;
  1293. $row['labels'] = $row['labels'] == '' ? array() : explode(',', $row['labels']);
  1294. // This is a special need for linking to messages.
  1295. foreach ($row['labels'] as $v)
  1296. {
  1297. if (isset($context['labels'][(int) $v]))
  1298. $context['message_labels'][$row['id_pm']][(int) $v] = array('id' => $v, 'name' => $context['labels'][(int) $v]['name']);
  1299. // Here we find the first label on a message - for linking to posts in results
  1300. if (!isset($context['first_label'][$row['id_pm']]) && !in_array('-1', $row['labels']))
  1301. $context['first_label'][$row['id_pm']] = (int) $v;
  1302. }
  1303. }
  1304. }
  1305. // Prepare the query for the callback!
  1306. $request = $smcFunc['db_query']('', '
  1307. SELECT pm.id_pm, pm.subject, pm.id_member_from, pm.body, pm.msgtime, pm.from_name
  1308. FROM {db_prefix}personal_messages AS pm
  1309. WHERE pm.id_pm IN ({array_int:message_list})
  1310. ORDER BY ' . $search_params['sort'] . ' ' . $search_params['sort_dir'] . '
  1311. LIMIT ' . count($foundMessages),
  1312. array(
  1313. 'message_list' => $foundMessages,
  1314. )
  1315. );
  1316. $counter = 0;
  1317. while ($row = $smcFunc['db_fetch_assoc']($request))
  1318. {
  1319. // If there's no message subject, use the default.
  1320. $row['subject'] = $row['subject'] == '' ? $txt['no_subject'] : $row['subject'];
  1321. // Load this posters context info, if it ain't there then fill in the essentials...
  1322. if (!loadMemberContext($row['id_member_from'], true))
  1323. {
  1324. $memberContext[$row['id_member_from']]['name'] = $row['from_name'];
  1325. $memberContext[$row['id_member_from']]['id'] = 0;
  1326. $memberContext[$row['id_member_from']]['group'] = $txt['guest_title'];
  1327. $memberContext[$row['id_member_from']]['link'] = $row['from_name'];
  1328. $memberContext[$row['id_member_from']]['email'] = '';
  1329. $memberContext[$row['id_member_from']]['show_email'] = showEmailAddress(true, 0);
  1330. $memberContext[$row['id_member_from']]['is_guest'] = true;
  1331. }
  1332. // Censor anything we don't want to see...
  1333. censorText($row['body']);
  1334. censorText($row['subject']);
  1335. // Parse out any BBC...
  1336. $row['body'] = parse_bbc($row['body'], true, 'pm' . $row['id_pm']);
  1337. $href = $scripturl . '?action=pm;f=' . $context['folder'] . (isset($context['first_label'][$row['id_pm']]) ? ';l=' . $context['first_label'][$row['id_pm']] : '') . ';pmid=' . ($context['display_mode'] == 2 && isset($real_pm_ids[$head_pms[$row['id_pm']]]) ? $real_pm_ids[$head_pms[$row['id_pm']]] : $row['id_pm']) . '#msg' . $row['id_pm'];
  1338. $context['personal_messages'][] = array(
  1339. 'id' => $row['id_pm'],
  1340. 'member' => &$memberContext[$row['id_member_from']],
  1341. 'subject' => $row['subject'],
  1342. 'body' => $row['body'],
  1343. 'time' => timeformat($row['msgtime']),
  1344. 'recipients' => &$recipients[$row['id_pm']],
  1345. 'labels' => &$context['message_labels'][$row['id_pm']],
  1346. 'fully_labeled' => count($context['message_labels'][$row['id_pm']]) == count($context['labels']),
  1347. 'is_replied_to' => &$context['message_replied'][$row['id_pm']],
  1348. 'href' => $href,
  1349. 'link' => '<a href="' . $href . '">' . $row['subject'] . '</a>',
  1350. 'counter' => ++$counter,
  1351. );
  1352. }
  1353. $smcFunc['db_free_result']($request);
  1354. }
  1355. // Finish off the context.
  1356. $context['page_title'] = $txt['pm_search_title'];
  1357. $context['sub_template'] = 'search_results';
  1358. $context['menu_data_' . $context['pm_menu_id']]['current_area'] = 'search';
  1359. $context['linktree'][] = array(
  1360. 'url' => $scripturl . '?action=pm;sa=search',
  1361. 'name' => $txt['pm_search_bar_title'],
  1362. );
  1363. }
  1364. // Send a new message?
  1365. function MessagePost()
  1366. {
  1367. global $txt, $sourcedir, $scripturl, $modSettings;
  1368. global $context, $options, $smcFunc, $language, $user_info;
  1369. isAllowedTo('pm_send');
  1370. loadLanguage('PersonalMessage');
  1371. // Just in case it was loaded from somewhere else.
  1372. if (!WIRELESS)
  1373. {
  1374. loadTemplate('PersonalMessage');
  1375. $context['sub_template'] = 'send';
  1376. }
  1377. // Extract out the spam settings - cause it's neat.
  1378. list ($modSettings['max_pm_recipients'], $modSettings['pm_posts_verification'], $modSettings['pm_posts_per_hour']) = explode(',', $modSettings['pm_spam_settings']);
  1379. // Set the title...
  1380. $context['page_title'] = $txt['send_message'];
  1381. $context['reply'] = isset($_REQUEST['pmsg']) || isset($_REQUEST['quote']);
  1382. // Check whether we've gone over the limit of messages we can send per hour.
  1383. if (!empty($modSettings['pm_posts_per_hour']) && !allowedTo(array('admin_forum', 'moderate_forum', 'send_mail')) && $user_info['mod_cache']['bq'] == '0=1' && $user_info['mod_cache']['gq'] == '0=1')
  1384. {
  1385. // How many messages have they sent this last hour?
  1386. $request = $smcFunc['db_query']('', '
  1387. SELECT COUNT(pr.id_pm) AS post_count
  1388. FROM {db_prefix}personal_messages AS pm
  1389. INNER JOIN {db_prefix}pm_recipients AS pr ON (pr.id_pm = pm.id_pm)
  1390. WHERE pm.id_member_from = {int:current_member}
  1391. AND pm.msgtime > {int:msgtime}',
  1392. array(
  1393. 'current_member' => $user_info['id'],
  1394. 'msgtime' => time() - 3600,
  1395. )
  1396. );
  1397. list ($postCount) = $smcFunc['db_fetch_row']($request);
  1398. $smcFunc['db_free_result']($request);
  1399. if (!empty($postCount) && $postCount >= $modSettings['pm_posts_per_hour'])
  1400. fatal_lang_error('pm_too_many_per_hour', true, array($modSettings['pm_posts_per_hour']));
  1401. }
  1402. // Quoting/Replying to a message?
  1403. if (!empty($_REQUEST['pmsg']))
  1404. {
  1405. $pmsg = (int) $_REQUEST['pmsg'];
  1406. // Make sure this is yours.
  1407. if (!isAccessiblePM($pmsg))
  1408. fatal_lang_error('no_access', false);
  1409. // Work out whether this is one you've received?
  1410. $request = $smcFunc['db_query']('', '
  1411. SELECT
  1412. id_pm
  1413. FROM {db_prefix}pm_recipients
  1414. WHERE id_pm = {int:id_pm}
  1415. AND id_member = {int:current_member}
  1416. LIMIT 1',
  1417. array(
  1418. 'current_member' => $user_info['id'],
  1419. 'id_pm' => $pmsg,
  1420. )
  1421. );
  1422. $isReceived = $smcFunc['db_num_rows']($request) != 0;
  1423. $smcFunc['db_free_result']($request);
  1424. // Get the quoted message (and make sure you're allowed to see this quote!).
  1425. $request = $smcFunc['db_query']('', '
  1426. SELECT
  1427. pm.id_pm, CASE WHEN pm.id_pm_head = {int:id_pm_head_empty} THEN pm.id_pm ELSE pm.id_pm_head END AS pm_head,
  1428. pm.body, pm.subject, pm.msgtime, mem.member_name, IFNULL(mem.id_member, 0) AS id_member,
  1429. IFNULL(mem.real_name, pm.from_name) AS real_name
  1430. FROM {db_prefix}personal_messages AS pm' . (!$isReceived ? '' : '
  1431. INNER JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = {int:id_pm})') . '
  1432. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = pm.id_member_from)
  1433. WHERE pm.id_pm = {int:id_pm}' . (!$isReceived ? '
  1434. AND pm.id_member_from = {int:current_member}' : '
  1435. AND pmr.id_member = {int:current_member}') . '
  1436. LIMIT 1',
  1437. array(
  1438. 'current_member' => $user_info['id'],
  1439. 'id_pm_head_empty' => 0,
  1440. 'id_pm' => $pmsg,
  1441. )
  1442. );
  1443. if ($smcFunc['db_num_rows']($request) == 0)
  1444. fatal_lang_error('pm_not_yours', false);
  1445. $row_quoted = $smcFunc['db_fetch_assoc']($request);
  1446. $smcFunc['db_free_result']($request);
  1447. // Censor the message.
  1448. censorText($row_quoted['subject']);
  1449. censorText($row_quoted['body']);
  1450. // Add 'Re: ' to it....
  1451. if (!isset($context['response_prefix']) && !($context['response_prefix'] = cache_get_data('response_prefix')))
  1452. {
  1453. if ($language === $user_info['language'])
  1454. $context['response_prefix'] = $txt['response_prefix'];
  1455. else
  1456. {
  1457. loadLanguage('index', $language, false);
  1458. $context['response_prefix'] = $txt['response_prefix'];
  1459. loadLanguage('index');
  1460. }
  1461. cache_put_data('response_prefix', $context['response_prefix'], 600);
  1462. }
  1463. $form_subject = $row_quoted['subject'];
  1464. if ($context['reply'] && trim($context['response_prefix']) != '' && $smcFunc['strpos']($form_subject, trim($context['response_prefix'])) !== 0)
  1465. $form_subject = $context['response_prefix'] . $form_subject;
  1466. if (isset($_REQUEST['quote']))
  1467. {
  1468. // Remove any nested quotes and <br />...
  1469. $form_message = preg_replace('~<br ?/?' . '>~i', "\n", $row_quoted['body']);
  1470. if (!empty($modSettings['removeNestedQuotes']))
  1471. $form_message = preg_replace(array('~\n?\[quote.*?\].+?\[/quote\]\n?~is', '~^\n~', '~\[/quote\]~'), '', $form_message);
  1472. if (empty($row_quoted['id_member']))
  1473. $form_message = '[quote author=&quot;' . $row_quoted['real_name'] . '&quot;]' . "\n" . $form_message . "\n" . '[/quote]';
  1474. else
  1475. $form_message = '[quote author=' . $row_quoted['real_name'] . ' link=action=profile;u=' . $row_quoted['id_member'] . ' date=' . $row_quoted['msgtime'] . ']' . "\n" . $form_message . "\n" . '[/quote]';
  1476. }
  1477. else
  1478. $form_message = '';
  1479. // Do the BBC thang on the message.
  1480. $row_quoted['body'] = parse_bbc($row_quoted['body'], true, 'pm' . $row_quoted['id_pm']);
  1481. // Set up the quoted message array.
  1482. $context['quoted_message'] = array(
  1483. 'id' => $row_quoted['id_pm'],
  1484. 'pm_head' => $row_quoted['pm_head'],
  1485. 'member' => array(
  1486. 'name' => $row_quoted['real_name'],
  1487. 'username' => $row_quoted['member_name'],
  1488. 'id' => $row_quoted['id_member'],
  1489. 'href' => !empty($row_quoted['id_member']) ? $scripturl . '?action=profile;u=' . $row_quoted['id_member'] : '',
  1490. 'link' => !empty($row_quoted['id_member']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row_quoted['id_member'] . '">' . $row_quoted['real_name'] . '</a>' : $row_quoted['real_name'],
  1491. ),
  1492. 'subject' => $row_quoted['subject'],
  1493. 'time' => timeformat($row_quoted['msgtime']),
  1494. 'timestamp' => forum_time(true, $row_quoted['msgtime']),
  1495. 'body' => $row_quoted['body']
  1496. );
  1497. }
  1498. else
  1499. {
  1500. $context['quoted_message'] = false;
  1501. $form_subject = '';
  1502. $form_message = '';
  1503. }
  1504. $context['recipients'] = array(
  1505. 'to' => array(),
  1506. 'bcc' => array(),
  1507. );
  1508. // Sending by ID? Replying to all? Fetch the real_name(s).
  1509. if (isset($_REQUEST['u']))
  1510. {
  1511. // If the user is replying to all, get all the other members this was sent to..
  1512. if ($_REQUEST['u'] == 'all' && isset($row_quoted))
  1513. {
  1514. // Firstly, to reply to all we clearly already have $row_quoted - so have the original member from.
  1515. if ($row_quoted['id_member'] != $user_info['id'])
  1516. $context['recipients']['to'][] = array(
  1517. 'id' => $row_quoted['id_member'],
  1518. 'name' => htmlspecialchars($row_quoted['real_name']),
  1519. );
  1520. // Now to get the others.
  1521. $request = $smcFunc['db_query']('', '
  1522. SELECT mem.id_member, mem.real_name
  1523. FROM {db_prefix}pm_recipients AS pmr
  1524. INNER JOIN {db_prefix}members AS mem ON (mem.id_member = pmr.id_member)
  1525. WHERE pmr.id_pm = {int:id_pm}
  1526. AND pmr.id_member != {int:current_member}
  1527. AND pmr.bcc = {int:not_bcc}',
  1528. array(
  1529. 'current_member' => $user_info['id'],
  1530. 'id_pm' => $pmsg,
  1531. 'not_bcc' => 0,
  1532. )
  1533. );
  1534. while ($row = $smcFunc['db_fetch_assoc']($request))
  1535. $context['recipients']['to'][] = array(
  1536. 'id' => $row['id_member'],
  1537. 'name' => $row['real_name'],
  1538. );
  1539. $smcFunc['db_free_result']($request);
  1540. }
  1541. else
  1542. {
  1543. $_REQUEST['u'] = explode(',', $_REQUEST['u']);
  1544. foreach ($_REQUEST['u'] as $key => $uID)
  1545. $_REQUEST['u'][$key] = (int) $uID;
  1546. $_REQUEST['u'] = array_unique($_REQUEST['u']);
  1547. $request = $smcFunc['db_query']('', '
  1548. SELECT id_member, real_name
  1549. FROM {db_prefix}members
  1550. WHERE id_member IN ({array_int:member_list})
  1551. LIMIT ' . count($_REQUEST['u']),
  1552. array(
  1553. 'member_list' => $_REQUEST['u'],
  1554. )
  1555. );
  1556. while ($row = $smcFunc['db_fetch_assoc']($request))
  1557. $context['recipients']['to'][] = array(
  1558. 'id' => $row['id_member'],
  1559. 'name' => $row['real_name'],
  1560. );
  1561. $smcFunc['db_free_result']($request);
  1562. }
  1563. // Get a literal name list in case the user has JavaScript disabled.
  1564. $names = array();
  1565. foreach ($context['recipients']['to'] as $to)
  1566. $names[] = $to['name'];
  1567. $context['to_value'] = empty($names) ? '' : '&quot;' . implode('&quot;, &quot;', $names) . '&quot;';
  1568. }
  1569. else
  1570. $context['to_value'] = '';
  1571. // Set the defaults...
  1572. $context['subject'] = $form_subject != '' ? $form_subject : $txt['no_subject'];
  1573. $context['message'] = str_replace(array('"', '<', '>', '&nbsp;'), array('&quot;', '&lt;', '&gt;', ' '), $form_message);
  1574. $context['post_error'] = array();
  1575. $context['copy_to_outbox'] = !empty($options['copy_to_outbox']);
  1576. // And build the link tree.
  1577. $context['linktree'][] = array(
  1578. 'url' => $scripturl . '?action=pm;sa=send',
  1579. 'name' => $txt['new_message']
  1580. );
  1581. $modSettings['disable_wysiwyg'] = !empty($modSettings['disable_wysiwyg']) || empty($modSettings['enableBBC']);
  1582. // Needed for the WYSIWYG editor.
  1583. require_once($sourcedir . '/Subs-Editor.php');
  1584. // Now create the editor.
  1585. $editorOptions = array(
  1586. 'id' => 'message',
  1587. 'value' => $context['message'],
  1588. 'height' => '175px',
  1589. 'width' => '100%',
  1590. 'labels' => array(
  1591. 'post_button' => $txt['send_message'],
  1592. ),
  1593. );
  1594. create_control_richedit($editorOptions);
  1595. // Store the ID for old compatibility.
  1596. $context['post_box_name'] = $editorOptions['id'];
  1597. $context['bcc_value'] = '';
  1598. $context['require_verification'] = !$user_info['is_admin'] && !empty($modSettings['pm_posts_verification']) && $user_info['posts'] < $modSettings['pm_posts_verification'];
  1599. if ($context['require_verification'])
  1600. {
  1601. $verificationOptions = array(
  1602. 'id' => 'pm',
  1603. );
  1604. $context['require_verification'] = create_control_verification($verificationOptions);
  1605. $context['visual_verification_id'] = $verificationOptions['id'];
  1606. }
  1607. // Register this form and get a sequence number in $context.
  1608. checkSubmitOnce('register');
  1609. }
  1610. // An error in the message...
  1611. function messagePostError($error_types, $named_recipients, $recipient_ids = array())
  1612. {
  1613. global $txt, $context, $scripturl, $modSettings;
  1614. global $smcFunc, $user_info, $sourcedir;
  1615. $context['menu_data_' . $context['pm_menu_id']]['current_area'] = 'send';
  1616. if (!WIRELESS)
  1617. $context['sub_template'] = 'send';
  1618. $context['page_title'] = $txt['send_message'];
  1619. // Got some known members?
  1620. $context['recipients'] = array(
  1621. 'to' => array(),
  1622. 'bcc' => array(),
  1623. );
  1624. if (!empty($recipient_ids['to']) || !empty($recipient_ids['bcc']))
  1625. {
  1626. $allRecipients = array_merge($recipient_ids['to'], $recipient_ids['bcc']);
  1627. $request = $smcFunc['db_query']('', '
  1628. SELECT id_member, real_name
  1629. FROM {db_prefix}members
  1630. WHERE id_member IN ({array_int:member_list})',
  1631. array(
  1632. 'member_list' => $allRecipients,
  1633. )
  1634. );
  1635. while ($row = $smcFunc['db_fetch_assoc']($request))
  1636. {
  1637. $recipientType = in_array($row['id_member'], $recipient_ids['bcc']) ? 'bcc' : 'to';
  1638. $context['recipients'][$recipientType][] = array(
  1639. 'id' => $row['id_member'],
  1640. 'name' => $row['real_name'],
  1641. );
  1642. }
  1643. $smcFunc['db_free_result']($request);
  1644. }
  1645. // Set everything up like before....
  1646. $context['subject'] = isset($_REQUEST['subject']) ? $smcFunc['htmlspecialchars']($_REQUEST['subject']) : '';
  1647. $context['message'] = isset($_REQUEST['message']) ? str_replace(array(' '), array('&nbsp; '), $smcFunc['htmlspecialchars']($_REQUEST['message'])) : '';
  1648. $context['copy_to_outbox'] = !empty($_REQUEST['outbox']);
  1649. $context['reply'] = !empty($_REQUEST['replied_to']);
  1650. if ($context['reply'])
  1651. {
  1652. $_REQUEST['replied_to'] = (int) $_REQUEST['replied_to'];
  1653. $request = $smcFunc['db_query']('', '
  1654. SELECT
  1655. pm.id_pm, CASE WHEN pm.id_pm_head = {int:no_id_pm_head} THEN pm.id_pm ELSE pm.id_pm_head END AS pm_head,
  1656. pm.body, pm.subject, pm.msgtime, mem.member_name, IFNULL(mem.id_member, 0) AS id_member,
  1657. IFNULL(mem.real_name, pm.from_name) AS real_name
  1658. FROM {db_prefix}personal_messages AS pm' . ($context['folder'] == 'sent' ? '' : '
  1659. INNER JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = {int:replied_to})') . '
  1660. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = pm.id_member_from)
  1661. WHERE pm.id_pm = {int:replied_to}' . ($context['folder'] == 'sent' ? '
  1662. AND pm.id_member_from = {int:current_member}' : '
  1663. AND pmr.id_member = {int:current_member}') . '
  1664. LIMIT 1',
  1665. array(
  1666. 'current_member' => $user_info['id'],
  1667. 'no_id_pm_head' => 0,
  1668. 'replied_to' => $_REQUEST['replied_to'],
  1669. )
  1670. );
  1671. if ($smcFunc['db_num_rows']($request) == 0)
  1672. fatal_lang_error('pm_not_yours', false);
  1673. $row_quoted = $smcFunc['db_fetch_assoc']($request);
  1674. $smcFunc['db_free_result']($request);
  1675. censorText($row_quoted['subject']);
  1676. censorText($row_quoted['body']);
  1677. $context['quoted_message'] = array(
  1678. 'id' => $row_quoted['id_pm'],
  1679. 'pm_head' => $row_quoted['pm_head'],
  1680. 'member' => array(
  1681. 'name' => $row_quoted['real_name'],
  1682. 'username' => $row_quoted['member_name'],
  1683. 'id' => $row_quoted['id_member'],
  1684. 'href' => !empty($row_quoted['id_member']) ? $scripturl . '?action=profile;u=' . $row_quoted['id_member'] : '',
  1685. 'link' => !empty($row_quoted['id_member']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row_quoted['id_member'] . '">' . $row_quoted['real_name'] . '</a>' : $row_quoted['real_name'],
  1686. ),
  1687. 'subject' => $row_quoted['subject'],
  1688. 'time' => timeformat($row_quoted['msgtime']),
  1689. 'timestamp' => forum_time(true, $row_quoted['msgtime']),
  1690. 'body' => parse_bbc($row_quoted['body'], true, 'pm' . $row_quoted['id_pm']),
  1691. );
  1692. }
  1693. // Build the link tree....
  1694. $context['linktree'][] = array(
  1695. 'url' => $scripturl . '?action=pm;sa=send',
  1696. 'name' => $txt['new_message']
  1697. );
  1698. // Set each of the errors for the template.
  1699. loadLanguage('Errors');
  1700. $context['post_error'] = array(
  1701. 'messages' => array(),
  1702. );
  1703. foreach ($error_types as $error_type)
  1704. {
  1705. $context['post_error'][$error_type] = true;
  1706. if (isset($txt['error_' . $error_type]))
  1707. {
  1708. if ($error_type == 'long_message')
  1709. $txt['error_' . $error_type] = sprintf($txt['error_' . $error_type], $modSettings['max_messageLength']);
  1710. $context['post_error']['messages'][] = $txt['error_' . $error_type];
  1711. }
  1712. }
  1713. // We need to load the editor once more.
  1714. require_once($sourcedir . '/Subs-Editor.php');
  1715. // Create it...
  1716. $editorOptions = array(
  1717. 'id' => 'message',
  1718. 'value' => $context['message'],
  1719. 'width' => '90%',
  1720. 'labels' => array(
  1721. 'post_button' => $txt['send_message'],
  1722. ),
  1723. );
  1724. create_control_richedit($editorOptions);
  1725. // ... and store the ID again...
  1726. $context['post_box_name'] = $editorOptions['id'];
  1727. // Check whether we need to show the code again.
  1728. $context['require_verification'] = !$user_info['is_admin'] && !empty($modSettings['pm_posts_verification']) && $user_info['posts'] < $modSettings['pm_posts_verification'];
  1729. if ($context['require_verification'])
  1730. {
  1731. require_once($sourcedir . '/Subs-Editor.php');
  1732. $verificationOptions = array(
  1733. 'id' => 'pm',
  1734. );
  1735. $context['require_verification'] = create_control_verification($verificationOptions);
  1736. $context['visual_verification_id'] = $verificationOptions['id'];
  1737. }
  1738. $context['to_value'] = empty($named_recipients['to']) ? '' : '&quot;' . implode('&quot;, &quot;', $named_recipients['to']) . '&quot;';
  1739. $context['bcc_value'] = empty($named_recipients['bcc']) ? '' : '&quot;' . implode('&quot;, &quot;', $named_recipients['bcc']) . '&quot;';
  1740. // No check for the previous submission is needed.
  1741. checkSubmitOnce('free');
  1742. // Acquire a new form sequence number.
  1743. checkSubmitOnce('register');
  1744. }
  1745. // Send it!
  1746. function MessagePost2()
  1747. {
  1748. global $txt, $context, $sourcedir;
  1749. global $user_info, $modSettings, $scripturl, $smcFunc;
  1750. isAllowedTo('pm_send');
  1751. require_once($sourcedir . '/Subs-Auth.php');
  1752. loadLanguage('PersonalMessage', '', false);
  1753. // Extract out the spam settings - it saves database space!
  1754. list ($modSettings['max_pm_recipients'], $modSettings['pm_posts_verification'], $modSettings['pm_posts_per_hour']) = explode(',', $modSettings['pm_spam_settings']);
  1755. // Check whether we've gone over the limit of messages we can send per hour - fatal error if fails!
  1756. if (!empty($modSettings['pm_posts_per_hour']) && !allowedTo(array('admin_forum', 'moderate_forum', 'send_mail')) && $user_info['mod_cache']['bq'] == '0=1' && $user_info['mod_cache']['gq'] == '0=1')
  1757. {
  1758. // How many have they sent this last hour?
  1759. $request = $smcFunc['db_query']('', '
  1760. SELECT COUNT(pr.id_pm) AS post_count
  1761. FROM {db_prefix}personal_messages AS pm
  1762. INNER JOIN {db_prefix}pm_recipients AS pr ON (pr.id_pm = pm.id_pm)
  1763. WHERE pm.id_member_from = {int:current_member}
  1764. AND pm.msgtime > {int:msgtime}',
  1765. array(
  1766. 'current_member' => $user_info['id'],
  1767. 'msgtime' => time() - 3600,
  1768. )
  1769. );
  1770. list ($postCount) = $smcFunc['db_fetch_row']($request);
  1771. $smcFunc['db_free_result']($request);
  1772. if (!empty($postCount) && $postCount >= $modSettings['pm_posts_per_hour'])
  1773. fatal_lang_error('pm_too_many_per_hour', true, array($modSettings['pm_posts_per_hour']));
  1774. }
  1775. // If we came from WYSIWYG then turn it back into BBC regardless.
  1776. if (!empty($_POST['message_mode']) && isset($_POST['message']))
  1777. {
  1778. require_once($sourcedir . '/Subs-Editor.php');
  1779. $_POST['message'] = html_to_bbc($_POST['message']);
  1780. // We need to unhtml it now as it gets done shortly.
  1781. $_POST['message'] = un_htmlspecialchars($_POST['message']);
  1782. // We need this in case of errors etc.
  1783. $_REQUEST['message'] = $_POST['message'];
  1784. }
  1785. // Initialize the errors we're about to make.
  1786. $post_errors = array();
  1787. // If your session timed out, show an error, but do allow to re-submit.
  1788. if (checkSession('post', '', false) != '')
  1789. $post_errors[] = 'session_timeout';
  1790. $_REQUEST['subject'] = isset($_REQUEST['subject']) ? trim($_REQUEST['subject']) : '';
  1791. $_REQUEST['to'] = empty($_POST['to']) ? (empty($_GET['to']) ? '' : $_GET['to']) : $_POST['to'];
  1792. $_REQUEST['bcc'] = empty($_POST['bcc']) ? (empty($_GET['bcc']) ? '' : $_GET['bcc']) : $_POST['bcc'];
  1793. // Route the input from the 'u' parameter to the 'to'-list.
  1794. if (!empty($_POST['u']))
  1795. $_POST['recipient_to'] = explode(',', $_POST['u']);
  1796. // Construct the list of recipients.
  1797. $recipientList = array();
  1798. $namedRecipientList = array();
  1799. $namesNotFound = array();
  1800. foreach (array('to', 'bcc') as $recipientType)
  1801. {
  1802. // First, let's see if there's user ID's given.
  1803. $recipientList[$recipientType] = array();
  1804. if (!empty($_POST['recipient_' . $recipientType]) && is_array($_POST['recipient_' . $recipientType]))
  1805. {
  1806. foreach ($_POST['recipient_' . $recipientType] as $recipient)
  1807. $recipientList[$recipientType][] = (int) $recipient;
  1808. }
  1809. // Are there also literal names set?
  1810. if (!empty($_REQUEST[$recipientType]))
  1811. {
  1812. // We're going to take out the "s anyway ;).
  1813. $recipientString = strtr($_REQUEST[$recipientType], array('\\"' => '"'));
  1814. preg_match_all('~"([^"]+)"~', $recipientString, $matches);
  1815. $namedRecipientList[$recipientType] = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $recipientString))));
  1816. foreach ($namedRecipientList[$recipientType] as $index => $recipient)
  1817. {
  1818. if (strlen(trim($recipient)) > 0)
  1819. $namedRecipientList[$recipientType][$index] = $smcFunc['htmlspecialchars']($smcFunc['strtolower'](trim($recipient)));
  1820. else
  1821. unset($namedRecipientList[$recipientType][$index]);
  1822. }
  1823. if (!empty($namedRecipientList[$recipientType]))
  1824. {
  1825. $foundMembers = findMembers($namedRecipientList[$recipientType]);
  1826. // Assume all are not found, until proven otherwise.
  1827. $namesNotFound[$recipientType] = $namedRecipientList[$recipientType];
  1828. foreach ($foundMembers as $member)
  1829. {
  1830. $testNames = array(
  1831. $smcFunc['strtolower']($member['username']),
  1832. $smcFunc['strtolower']($member['name']),
  1833. $smcFunc['strtolower']($member['email']),
  1834. );
  1835. if (count(array_intersect($testNames, $namedRecipientList[$recipientType])) !== 0)
  1836. {
  1837. $recipientList[$recipientType][] = $member['id'];
  1838. // Get rid of this username, since we found it.
  1839. $namesNotFound[$recipientType] = array_diff($namesNotFound[$recipientType], $testNames);
  1840. }
  1841. }
  1842. }
  1843. }
  1844. // Selected a recipient to be deleted? Remove them now.
  1845. if (!empty($_POST['delete_recipient']))
  1846. $recipientList[$recipientType] = array_diff($recipientList[$recipientType], array((int) $_POST['delete_recipient']));
  1847. // Make sure we don't include the same name twice
  1848. $recipientList[$recipientType] = array_unique($recipientList[$recipientType]);
  1849. }
  1850. // Are we changing the recipients some how?
  1851. $is_recipient_change = !empty($_POST['delete_recipient']) || !empty($_POST['to_submit']) || !empty($_POST['bcc_submit']);
  1852. // Check if there's at least one recipient.
  1853. if (empty($recipientList['to']) && empty($recipientList['bcc']))
  1854. $post_errors[] = 'no_to';
  1855. // Make sure that we remove the members who did get it from the screen.
  1856. if (!$is_recipient_change)
  1857. {
  1858. foreach ($recipientList as $recipientType => $dummy)
  1859. {
  1860. if (!empty($namesNotFound[$recipientType]))
  1861. {
  1862. $post_errors[] = 'bad_' . $recipientType;
  1863. // Since we already have a post error, remove the previous one.
  1864. $post_errors = array_diff($post_errors, array('no_to'));
  1865. foreach ($namesNotFound[$recipientType] as $name)
  1866. $context['send_log']['failed'][] = sprintf($txt['pm_error_user_not_found'], $name);
  1867. }
  1868. }
  1869. }
  1870. // Did they make any mistakes?
  1871. if ($_REQUEST['subject'] == '')
  1872. $post_errors[] = 'no_subject';
  1873. if (!isset($_REQUEST['message']) || $_REQUEST['message'] == '')
  1874. $post_errors[] = 'no_message';
  1875. elseif (!empty($modSettings['max_messageLength']) && $smcFunc['strlen']($_REQUEST['message']) > $modSettings['max_messageLength'])
  1876. $post_errors[] = 'long_message';
  1877. else
  1878. {
  1879. // Preparse the message.
  1880. $message = $_REQUEST['message'];
  1881. preparsecode($message);
  1882. // Make sure there's still some content left without the tags.
  1883. if ($smcFunc['htmltrim'](strip_tags(parse_bbc($smcFunc['htmlspecialchars']($message, ENT_QUOTES), false), '<img>')) === '' && (!allowedTo('admin_forum') || strpos($message, '[html]') === false))
  1884. $post_errors[] = 'no_message';
  1885. }
  1886. // Wrong verification code?
  1887. if (!$user_info['is_admin'] && !empty($modSettings['pm_posts_verification']) && $user_info['posts'] < $modSettings['pm_posts_verification'])
  1888. {
  1889. require_once($sourcedir . '/Subs-Editor.php');
  1890. $verificationOptions = array(
  1891. 'id' => 'pm',
  1892. );
  1893. $context['require_verification'] = create_control_verification($verificationOptions, true);
  1894. if (is_array($context['require_verification']))
  1895. {
  1896. $post_errors = array_merge($post_errors, $context['require_verification']);
  1897. }
  1898. }
  1899. // If they did, give a chance to make ammends.
  1900. if (!empty($post_errors) && !$is_recipient_change && !isset($_REQUEST['preview']))
  1901. return messagePostError($post_errors, $namedRecipientList, $recipientList);
  1902. // Want to take a second glance before you send?
  1903. if (isset($_REQUEST['preview']))
  1904. {
  1905. // Set everything up to be displayed.
  1906. $context['preview_subject'] = $smcFunc['htmlspecialchars']($_REQUEST['subject']);
  1907. $context['preview_message'] = $smcFunc['htmlspecialchars']($_REQUEST['message'], ENT_QUOTES);
  1908. preparsecode($context['preview_message'], true);
  1909. // Parse out the BBC if it is enabled.
  1910. $context['preview_message'] = parse_bbc($context['preview_message']);
  1911. // Censor, as always.
  1912. censorText($context['preview_subject']);
  1913. censorText($context['preview_message']);
  1914. // Set a descriptive title.
  1915. $context['page_title'] = $txt['preview'] . ' - ' . $context['preview_subject'];
  1916. // Pretend they messed up but don't ignore if they really did :P.
  1917. return messagePostError($post_errors, $namedRecipientList, $recipientList);
  1918. }
  1919. // Adding a recipient cause javascript ain't working?
  1920. elseif ($is_recipient_change)
  1921. {
  1922. // Maybe we couldn't find one?
  1923. foreach ($namesNotFound as $recipientType => $names)
  1924. {
  1925. $post_errors[] = 'bad_' . $recipientType;
  1926. foreach ($names as $name)
  1927. $context['send_log']['failed'][] = sprintf($txt['pm_error_user_not_found'], $name);
  1928. }
  1929. return messagePostError(array(), $namedRecipientList, $recipientList);
  1930. }
  1931. // Before we send the PM, let's make sure we don't have an abuse of numbers.
  1932. elseif (!empty($modSettings['max_pm_recipients']) && count($recipientList['to']) + count($recipientList['bcc']) > $modSettings['max_pm_recipients'] && !allowedTo(array('moderate_forum', 'send_mail', 'admin_forum')))
  1933. {
  1934. $context['send_log'] = array(
  1935. 'sent' => array(),
  1936. 'failed' => array(sprintf($txt['pm_too_many_recipients'], $modSettings['max_pm_recipients'])),
  1937. );
  1938. return messagePostError($post_errors, $namedRecipientList, $recipientList);
  1939. }
  1940. // Protect from message spamming.
  1941. spamProtection('pm');
  1942. // Prevent double submission of this form.
  1943. checkSubmitOnce('check');
  1944. // Do the actual sending of the PM.
  1945. if (!empty($recipientList['to']) || !empty($recipientList['bcc']))
  1946. $context['send_log'] = sendpm($recipientList, $_REQUEST['subject'], $_REQUEST['message'], !empty($_REQUEST['outbox']), null, !empty($_REQUEST['pm_head']) ? (int) $_REQUEST['pm_head'] : 0);
  1947. else
  1948. $context['send_log'] = array(
  1949. 'sent' => array(),
  1950. 'failed' => array()
  1951. );
  1952. // Mark the message as "replied to".
  1953. if (!empty($context['send_log']['sent']) && !empty($_REQUEST['replied_to']) && isset($_REQUEST['f']) && $_REQUEST['f'] == 'inbox')
  1954. {
  1955. $smcFunc['db_query']('', '
  1956. UPDATE {db_prefix}pm_recipients
  1957. SET is_read = is_read | 2
  1958. WHERE id_pm = {int:replied_to}
  1959. AND id_member = {int:current_member}',
  1960. array(
  1961. 'current_member' => $user_info['id'],
  1962. 'replied_to' => (int) $_REQUEST['replied_to'],
  1963. )
  1964. );
  1965. }
  1966. // If one or more of the recipient were invalid, go back to the post screen with the failed usernames.
  1967. if (!empty($context['send_log']['failed']))
  1968. return messagePostError($post_errors, $namesNotFound, array(
  1969. 'to' => array_intersect($recipientList['to'], $context['send_log']['failed']),
  1970. 'bcc' => array_intersect($recipientList['bcc'], $context['send_log']['failed'])
  1971. ));
  1972. // Message sent successfully?
  1973. if (!empty($context['send_log']) && empty($context['send_log']['failed']))
  1974. $context['current_label_redirect'] = $context['current_label_redirect'] . ';done=sent';
  1975. // Go back to the where they sent from, if possible...
  1976. redirectexit($context['current_label_redirect']);
  1977. }
  1978. // This function lists all buddies for wireless protocols.
  1979. function WirelessAddBuddy()
  1980. {
  1981. global $scripturl, $txt, $user_info, $context, $smcFunc;
  1982. isAllowedTo('pm_send');
  1983. $context['page_title'] = $txt['wireless_pm_add_buddy'];
  1984. $current_buddies = empty($_REQUEST['u']) ? array() : explode(',', $_REQUEST['u']);
  1985. foreach ($current_buddies as $key => $buddy)
  1986. $current_buddies[$key] = (int) $buddy;
  1987. $base_url = $scripturl . '?action=pm;sa=send;u=' . (empty($current_buddies) ? '' : implode(',', $current_buddies) . ',');
  1988. $context['pm_href'] = $scripturl . '?action=pm;sa=send' . (empty($current_buddies) ? '' : ';u=' . implode(',', $current_buddies));
  1989. $context['buddies'] = array();
  1990. if (!empty($user_info['buddies']))
  1991. {
  1992. $request = $smcFunc['db_query']('', '
  1993. SELECT id_member, real_name
  1994. FROM {db_prefix}members
  1995. WHERE id_member IN ({array_int:buddy_list})
  1996. ORDER BY real_name
  1997. LIMIT ' . count($user_info['buddies']),
  1998. array(
  1999. 'buddy_list' => $user_info['buddies'],
  2000. )
  2001. );
  2002. while ($row = $smcFunc['db_fetch_assoc']($request))
  2003. $context['buddies'][] = array(
  2004. 'id' => $row['id_member'],
  2005. 'name' => $row['real_name'],
  2006. 'selected' => in_array($row['id_member'], $current_buddies),
  2007. 'add_href' => $base_url . $row['id_member'],
  2008. );
  2009. $smcFunc['db_free_result']($request);
  2010. }
  2011. }
  2012. // This function performs all additional stuff...
  2013. function MessageActionsApply()
  2014. {
  2015. global $txt, $context, $user_info, $options, $smcFunc;
  2016. checkSession('request');
  2017. if (isset($_REQUEST['del_selected']))
  2018. $_REQUEST['pm_action'] = 'delete';
  2019. if (isset($_REQUEST['pm_action']) && $_REQUEST['pm_action'] != '' && !empty($_REQUEST['pms']) && is_array($_REQUEST['pms']))
  2020. {
  2021. foreach ($_REQUEST['pms'] as $pm)
  2022. $_REQUEST['pm_actions'][(int) $pm] = $_REQUEST['pm_action'];
  2023. }
  2024. if (empty($_REQUEST['pm_actions']))
  2025. redirectexit($context['current_label_redirect']);
  2026. // If we are in conversation, we may need to apply this to every message in the conversation.
  2027. if ($context['display_mode'] == 2 && isset($_REQUEST['conversation']))
  2028. {
  2029. $id_pms = array();
  2030. foreach ($_REQUEST['pm_actions'] as $pm => $dummy)
  2031. $id_pms[] = (int) $pm;
  2032. $request = $smcFunc['db_query']('', '
  2033. SELECT id_pm_head, id_pm
  2034. FROM {db_prefix}personal_messages
  2035. WHERE id_pm IN ({array_int:id_pms})',
  2036. array(
  2037. 'id_pms' => $id_pms,
  2038. )
  2039. );
  2040. $pm_heads = array();
  2041. while ($row = $smcFunc['db_fetch_assoc']($request))
  2042. $pm_heads[$row['id_pm_head']] = $row['id_pm'];
  2043. $smcFunc['db_free_result']($request);
  2044. $request = $smcFunc['db_query']('', '
  2045. SELECT id_pm, id_pm_head
  2046. FROM {db_prefix}personal_messages
  2047. WHERE id_pm_head IN ({array_int:pm_heads})',
  2048. array(
  2049. 'pm_heads' => array_keys($pm_heads),
  2050. )
  2051. );
  2052. // Copy the action from the single to PM to the others.
  2053. while ($row = $smcFunc['db_fetch_assoc']($request))
  2054. {
  2055. if (isset($pm_heads[$row['id_pm_head']]) && isset($_REQUEST['pm_actions'][$pm_heads[$row['id_pm_head']]]))
  2056. $_REQUEST['pm_actions'][$row['id_pm']] = $_REQUEST['pm_actions'][$pm_heads[$row['id_pm_head']]];
  2057. }
  2058. $smcFunc['db_free_result']($request);
  2059. }
  2060. $to_delete = array();
  2061. $to_label = array();
  2062. $label_type = array();
  2063. foreach ($_REQUEST['pm_actions'] as $pm => $action)
  2064. {
  2065. if ($action === 'delete')
  2066. $to_delete[] = (int) $pm;
  2067. else
  2068. {
  2069. if (substr($action, 0, 4) == 'add_')
  2070. {
  2071. $type = 'add';
  2072. $action = substr($action, 4);
  2073. }
  2074. elseif (substr($action, 0, 4) == 'rem_')
  2075. {
  2076. $type = 'rem';
  2077. $action = substr($action, 4);
  2078. }
  2079. else
  2080. $type = 'unk';
  2081. if ($action == '-1' || $action == '0' || (int) $action > 0)
  2082. {
  2083. $to_label[(int) $pm] = (int) $action;
  2084. $label_type[(int) $pm] = $type;
  2085. }
  2086. }
  2087. }
  2088. // Deleting, it looks like?
  2089. if (!empty($to_delete))
  2090. deleteMessages($to_delete, $context['display_mode'] == 2 ? null : $context['folder']);
  2091. // Are we labeling anything?
  2092. if (!empty($to_label) && $context['folder'] == 'inbox')
  2093. {
  2094. $updateErrors = 0;
  2095. // Get information about each message...
  2096. $request = $smcFunc['db_query']('', '
  2097. SELECT id_pm, labels
  2098. FROM {db_prefix}pm_recipients
  2099. WHERE id_member = {int:current_member}
  2100. AND id_pm IN ({array_int:to_label})
  2101. LIMIT ' . count($to_label),
  2102. array(
  2103. 'current_member' => $user_info['id'],
  2104. 'to_label' => array_keys($to_label),
  2105. )
  2106. );
  2107. while ($row = $smcFunc['db_fetch_assoc']($request))
  2108. {
  2109. $labels = $row['labels'] == '' ? array('-1') : explode(',', trim($row['labels']));
  2110. // Already exists? Then... unset it!
  2111. $ID_LABEL = array_search($to_label[$row['id_pm']], $labels);
  2112. if ($ID_LABEL !== false && $label_type[$row['id_pm']] !== 'add')
  2113. unset($labels[$ID_LABEL]);
  2114. elseif ($label_type[$row['id_pm']] !== 'rem')
  2115. $labels[] = $to_label[$row['id_pm']];
  2116. if (!empty($options['pm_remove_inbox_label']) && $to_label[$row['id_pm']] != '-1' && ($key = array_search('-1', $labels)) !== false)
  2117. unset($labels[$key]);
  2118. $set = implode(',', array_unique($labels));
  2119. if ($set == '')
  2120. $set = '-1';
  2121. // Check that this string isn't going to be too large for the database.
  2122. if ($set > 60)
  2123. $updateErrors++;
  2124. else
  2125. {
  2126. $smcFunc['db_query']('', '
  2127. UPDATE {db_prefix}pm_recipients
  2128. SET labels = {string:labels}
  2129. WHERE id_pm = {int:id_pm}
  2130. AND id_member = {int:current_member}',
  2131. array(
  2132. 'current_member' => $user_info['id'],
  2133. 'id_pm' => $row['id_pm'],
  2134. 'labels' => $set,
  2135. )
  2136. );
  2137. }
  2138. }
  2139. $smcFunc['db_free_result']($request);
  2140. // Any errors?
  2141. // !!! Separate the sprintf?
  2142. if (!empty($updateErrors))
  2143. fatal_lang_error('labels_too_many', true, array($updateErrors));
  2144. }
  2145. // Back to the folder.
  2146. $_SESSION['pm_selected'] = array_keys($to_label);
  2147. redirectexit($context['current_label_redirect'] . (count($to_label) == 1 ? '#msg' . $_SESSION['pm_selected'][0] : ''), count($to_label) == 1 && $context['browser']['is_ie']);
  2148. }
  2149. // Are you sure you want to PERMANENTLY (mostly) delete ALL your messages?
  2150. function MessageKillAllQuery()
  2151. {
  2152. global $txt, $context;
  2153. // Only have to set up the template....
  2154. $context['sub_template'] = 'ask_delete';
  2155. $context['page_title'] = $txt['delete_all'];
  2156. $context['delete_all'] = $_REQUEST['f'] == 'all';
  2157. // And set the folder name...
  2158. $txt['delete_all'] = str_replace('PMBOX', $context['folder'] != 'sent' ? $txt['inbox'] : $txt['sent_items'], $txt['delete_all']);
  2159. }
  2160. // Delete ALL the messages!
  2161. function MessageKillAll()
  2162. {
  2163. global $context;
  2164. checkSession('get');
  2165. // If all then delete all messages the user has.
  2166. if ($_REQUEST['f'] == 'all')
  2167. deleteMessages(null, null);
  2168. // Otherwise just the selected folder.
  2169. else
  2170. deleteMessages(null, $_REQUEST['f'] != 'sent' ? 'inbox' : 'sent');
  2171. // Done... all gone.
  2172. redirectexit($context['current_label_redirect']);
  2173. }
  2174. // This function allows the user to delete all messages older than so many days.
  2175. function MessagePrune()
  2176. {
  2177. global $txt, $context, $user_info, $scripturl, $smcFunc;
  2178. // Actually delete the messages.
  2179. if (isset($_REQUEST['age']))
  2180. {
  2181. checkSession();
  2182. // Calculate the time to delete before.
  2183. $deleteTime = max(0, time() - (86400 * (int) $_REQUEST['age']));
  2184. // Array to store the IDs in.
  2185. $toDelete = array();
  2186. // Select all the messages they have sent older than $deleteTime.
  2187. $request = $smcFunc['db_query']('', '
  2188. SELECT id_pm
  2189. FROM {db_prefix}personal_messages
  2190. WHERE deleted_by_sender = {int:not_deleted}
  2191. AND id_member_from = {int:current_member}
  2192. AND msgtime < {int:msgtime}',
  2193. array(
  2194. 'current_member' => $user_info['id'],
  2195. 'not_deleted' => 0,
  2196. 'msgtime' => $deleteTime,
  2197. )
  2198. );
  2199. while ($row = $smcFunc['db_fetch_row']($request))
  2200. $toDelete[] = $row[0];
  2201. $smcFunc['db_free_result']($request);
  2202. // Select all messages in their inbox older than $deleteTime.
  2203. $request = $smcFunc['db_query']('', '
  2204. SELECT pmr.id_pm
  2205. FROM {db_prefix}pm_recipients AS pmr
  2206. INNER JOIN {db_prefix}personal_messages AS pm ON (pm.id_pm = pmr.id_pm)
  2207. WHERE pmr.deleted = {int:not_deleted}
  2208. AND pmr.id_member = {int:current_member}
  2209. AND pm.msgtime < {int:msgtime}',
  2210. array(
  2211. 'current_member' => $user_info['id'],
  2212. 'not_deleted' => 0,
  2213. 'msgtime' => $deleteTime,
  2214. )
  2215. );
  2216. while ($row = $smcFunc['db_fetch_assoc']($request))
  2217. $toDelete[] = $row['id_pm'];
  2218. $smcFunc['db_free_result']($request);
  2219. // Delete the actual messages.
  2220. deleteMessages($toDelete);
  2221. // Go back to their inbox.
  2222. redirectexit($context['current_label_redirect']);
  2223. }
  2224. // Build the link tree elements.
  2225. $context['linktree'][] = array(
  2226. 'url' => $scripturl . '?action=pm;sa=prune',
  2227. 'name' => $txt['pm_prune']
  2228. );
  2229. $context['sub_template'] = 'prune';
  2230. $context['page_title'] = $txt['pm_prune'];
  2231. }
  2232. // Delete the specified personal messages.
  2233. function deleteMessages($personal_messages, $folder = null, $owner = null)
  2234. {
  2235. global $user_info, $smcFunc;
  2236. if ($owner === null)
  2237. $owner = array($user_info['id']);
  2238. elseif (empty($owner))
  2239. return;
  2240. elseif (!is_array($owner))
  2241. $owner = array($owner);
  2242. if ($personal_messages !== null)
  2243. {
  2244. if (empty($personal_messages) || !is_array($personal_messages))
  2245. return;
  2246. foreach ($personal_messages as $index => $delete_id)
  2247. $personal_messages[$index] = (int) $delete_id;
  2248. $where = '
  2249. AND id_pm IN ({array_int:pm_list})';
  2250. }
  2251. else
  2252. $where = '';
  2253. if ($folder == 'sent' || $folder === null)
  2254. {
  2255. $smcFunc['db_query']('', '
  2256. UPDATE {db_prefix}personal_messages
  2257. SET deleted_by_sender = {int:is_deleted}
  2258. WHERE id_member_from IN ({array_int:member_list})
  2259. AND deleted_by_sender = {int:not_deleted}' . $where,
  2260. array(
  2261. 'member_list' => $owner,
  2262. 'is_deleted' => 1,
  2263. 'not_deleted' => 0,
  2264. 'pm_list' => $personal_messages !== null ? array_unique($personal_messages) : array(),
  2265. )
  2266. );
  2267. }
  2268. if ($folder != 'sent' || $folder === null)
  2269. {
  2270. // Calculate the number of messages each member's gonna lose...
  2271. $request = $smcFunc['db_query']('', '
  2272. SELECT id_member, COUNT(*) AS num_deleted_messages, CASE WHEN is_read & 1 >= 1 THEN 1 ELSE 0 END AS is_read
  2273. FROM {db_prefix}pm_recipients
  2274. WHERE id_member IN ({array_int:member_list})
  2275. AND deleted = {int:not_deleted}' . $where . '
  2276. GROUP BY id_member, is_read',
  2277. array(
  2278. 'member_list' => $owner,
  2279. 'not_deleted' => 0,
  2280. 'pm_list' => $personal_messages !== null ? array_unique($personal_messages) : array(),
  2281. )
  2282. );
  2283. // ...And update the statistics accordingly - now including unread messages!.
  2284. while ($row = $smcFunc['db_fetch_assoc']($request))
  2285. {
  2286. if ($row['is_read'])
  2287. updateMemberData($row['id_member'], array('instant_messages' => $where == '' ? 0 : 'instant_messages - ' . $row['num_deleted_messages']));
  2288. else
  2289. updateMemberData($row['id_member'], array('instant_messages' => $where == '' ? 0 : 'instant_messages - ' . $row['num_deleted_messages'], 'unread_messages' => $where == '' ? 0 : 'unread_messages - ' . $row['num_deleted_messages']));
  2290. // If this is the current member we need to make their message count correct.
  2291. if ($user_info['id'] == $row['id_member'])
  2292. {
  2293. $user_info['messages'] -= $row['num_deleted_messages'];
  2294. if (!($row['is_read']))
  2295. $user_info['unread_messages'] -= $row['num_deleted_messages'];
  2296. }
  2297. }
  2298. $smcFunc['db_free_result']($request);
  2299. // Do the actual deletion.
  2300. $smcFunc['db_query']('', '
  2301. UPDATE {db_prefix}pm_recipients
  2302. SET deleted = {int:is_deleted}
  2303. WHERE id_member IN ({array_int:member_list})
  2304. AND deleted = {int:not_deleted}' . $where,
  2305. array(
  2306. 'member_list' => $owner,
  2307. 'is_deleted' => 1,
  2308. 'not_deleted' => 0,
  2309. 'pm_list' => $personal_messages !== null ? array_unique($personal_messages) : array(),
  2310. )
  2311. );
  2312. }
  2313. // If sender and recipients all have deleted their message, it can be removed.
  2314. $request = $smcFunc['db_query']('', '
  2315. SELECT pm.id_pm AS sender, pmr.id_pm
  2316. FROM {db_prefix}personal_messages AS pm
  2317. LEFT JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm AND pmr.deleted = {int:not_deleted})
  2318. WHERE pm.deleted_by_sender = {int:is_deleted}
  2319. ' . str_replace('id_pm', 'pm.id_pm', $where) . '
  2320. GROUP BY sender, pmr.id_pm
  2321. HAVING pmr.id_pm IS null',
  2322. array(
  2323. 'not_deleted' => 0,
  2324. 'is_deleted' => 1,
  2325. 'pm_list' => $personal_messages !== null ? array_unique($personal_messages) : array(),
  2326. )
  2327. );
  2328. $remove_pms = array();
  2329. while ($row = $smcFunc['db_fetch_assoc']($request))
  2330. $remove_pms[] = $row['sender'];
  2331. $smcFunc['db_free_result']($request);
  2332. if (!empty($remove_pms))
  2333. {
  2334. $smcFunc['db_query']('', '
  2335. DELETE FROM {db_prefix}personal_messages
  2336. WHERE id_pm IN ({array_int:pm_list})',
  2337. array(
  2338. 'pm_list' => $remove_pms,
  2339. )
  2340. );
  2341. $smcFunc['db_query']('', '
  2342. DELETE FROM {db_prefix}pm_recipients
  2343. WHERE id_pm IN ({array_int:pm_list})',
  2344. array(
  2345. 'pm_list' => $remove_pms,
  2346. )
  2347. );
  2348. }
  2349. // Any cached numbers may be wrong now.
  2350. cache_put_data('labelCounts:' . $user_info['id'], null, 720);
  2351. }
  2352. // Mark personal messages read.
  2353. function markMessages($personal_messages = null, $label = null, $owner = null)
  2354. {
  2355. global $user_info, $context, $smcFunc;
  2356. if ($owner === null)
  2357. $owner = $user_info['id'];
  2358. $smcFunc['db_query']('', '
  2359. UPDATE {db_prefix}pm_recipients
  2360. SET is_read = is_read | 1
  2361. WHERE id_member = {int:id_member}
  2362. AND NOT (is_read & 1 >= 1)' . ($label === null ? '' : '
  2363. AND FIND_IN_SET({string:label}, labels) != 0') . ($personal_messages !== null ? '
  2364. AND id_pm IN ({array_int:personal_messages})' : ''),
  2365. array(
  2366. 'personal_messages' => $personal_messages,
  2367. 'id_member' => $owner,
  2368. 'label' => $label,
  2369. )
  2370. );
  2371. // If something wasn't marked as read, get the number of unread messages remaining.
  2372. if ($smcFunc['db_affected_rows']() > 0)
  2373. {
  2374. if ($owner == $user_info['id'])
  2375. {
  2376. foreach ($context['labels'] as $label)
  2377. $context['labels'][(int) $label['id']]['unread_messages'] = 0;
  2378. }
  2379. $result = $smcFunc['db_query']('', '
  2380. SELECT labels, COUNT(*) AS num
  2381. FROM {db_prefix}pm_recipients
  2382. WHERE id_member = {int:id_member}
  2383. AND NOT (is_read & 1 >= 1)
  2384. AND deleted = {int:is_not_deleted}
  2385. GROUP BY labels',
  2386. array(
  2387. 'id_member' => $owner,
  2388. 'is_not_deleted' => 0,
  2389. )
  2390. );
  2391. $total_unread = 0;
  2392. while ($row = $smcFunc['db_fetch_assoc']($result))
  2393. {
  2394. $total_unread += $row['num'];
  2395. if ($owner != $user_info['id'])
  2396. continue;
  2397. $this_labels = explode(',', $row['labels']);
  2398. foreach ($this_labels as $this_label)
  2399. $context['labels'][(int) $this_label]['unread_messages'] += $row['num'];
  2400. }
  2401. $smcFunc['db_free_result']($result);
  2402. // Need to store all this.
  2403. cache_put_data('labelCounts:' . $owner, $context['labels'], 720);
  2404. updateMemberData($owner, array('unread_messages' => $total_unread));
  2405. // If it was for the current member, reflect this in the $user_info array too.
  2406. if ($owner == $user_info['id'])
  2407. $user_info['unread_messages'] = $total_unread;
  2408. }
  2409. }
  2410. // This function handles adding, deleting and editing labels on messages.
  2411. function ManageLabels()
  2412. {
  2413. global $txt, $context, $user_info, $scripturl, $smcFunc;
  2414. // Build the link tree elements...
  2415. $context['linktree'][] = array(
  2416. 'url' => $scripturl . '?action=pm;sa=manlabels',
  2417. 'name' => $txt['pm_manage_labels']
  2418. );
  2419. $context['page_title'] = $txt['pm_manage_labels'];
  2420. $context['sub_template'] = 'labels';
  2421. $the_labels = array();
  2422. // Add all existing labels to the array to save, slashing them as necessary...
  2423. foreach ($context['labels'] as $label)
  2424. {
  2425. if ($label['id'] != -1)
  2426. $the_labels[$label['id']] = $label['name'];
  2427. }
  2428. if (isset($_POST[$context['session_var']]))
  2429. {
  2430. checkSession('post');
  2431. // This will be for updating messages.
  2432. $message_changes = array();
  2433. $new_labels = array();
  2434. $rule_changes = array();
  2435. // Will most likely need this.
  2436. LoadRules();
  2437. // Adding a new label?
  2438. if (isset($_POST['add']))
  2439. {
  2440. $_POST['label'] = strtr($smcFunc['htmlspecialchars'](trim($_POST['label'])), array(',' => '&#044;'));
  2441. if ($smcFunc['strlen']($_POST['label']) > 30)
  2442. $_POST['label'] = $smcFunc['substr']($_POST['label'], 0, 30);
  2443. if ($_POST['label'] != '')
  2444. $the_labels[] = $_POST['label'];
  2445. }
  2446. // Deleting an existing label?
  2447. elseif (isset($_POST['delete'], $_POST['delete_label']))
  2448. {
  2449. $i = 0;
  2450. foreach ($the_labels as $id => $name)
  2451. {
  2452. if (isset($_POST['delete_label'][$id]))
  2453. {
  2454. unset($the_labels[$id]);
  2455. $message_changes[$id] = true;
  2456. }
  2457. else
  2458. $new_labels[$id] = $i++;
  2459. }
  2460. }
  2461. // The hardest one to deal with... changes.
  2462. elseif (isset($_POST['save']) && !empty($_POST['label_name']))
  2463. {
  2464. $i = 0;
  2465. foreach ($the_labels as $id => $name)
  2466. {
  2467. if ($id == -1)
  2468. continue;
  2469. elseif (isset($_POST['label_name'][$id]))
  2470. {
  2471. $_POST['label_name'][$id] = trim(strtr($smcFunc['htmlspecialchars']($_POST['label_name'][$id]), array(',' => '&#044;')));
  2472. if ($smcFunc['strlen']($_POST['label_name'][$id]) > 30)
  2473. $_POST['label_name'][$id] = $smcFunc['substr']($_POST['label_name'][$id], 0, 30);
  2474. if ($_POST['label_name'][$id] != '')
  2475. {
  2476. $the_labels[(int) $id] = $_POST['label_name'][$id];
  2477. $new_labels[$id] = $i++;
  2478. }
  2479. else
  2480. {
  2481. unset($the_labels[(int) $id]);
  2482. $message_changes[(int) $id] = true;
  2483. }
  2484. }
  2485. else
  2486. $new_labels[$id] = $i++;
  2487. }
  2488. }
  2489. // Save the label status.
  2490. updateMemberData($user_info['id'], array('message_labels' => implode(',', $the_labels)));
  2491. // Update all the messages currently with any label changes in them!
  2492. if (!empty($message_changes))
  2493. {
  2494. $searchArray = array_keys($message_changes);
  2495. if (!empty($new_labels))
  2496. {
  2497. for ($i = max($searchArray) + 1, $n = max(array_keys($new_labels)); $i <= $n; $i++)
  2498. $searchArray[] = $i;
  2499. }
  2500. // Now find the messages to change.
  2501. $request = $smcFunc['db_query']('', '
  2502. SELECT id_pm, labels
  2503. FROM {db_prefix}pm_recipients
  2504. WHERE FIND_IN_SET({raw:find_label_implode}, labels) != 0
  2505. AND id_member = {int:current_member}',
  2506. array(
  2507. 'current_member' => $user_info['id'],
  2508. 'find_label_implode' => '\'' . implode('\', labels) != 0 OR FIND_IN_SET(\'', $searchArray) . '\'',
  2509. )
  2510. );
  2511. while ($row = $smcFunc['db_fetch_assoc']($request))
  2512. {
  2513. // Do the long task of updating them...
  2514. $toChange = explode(',', $row['labels']);
  2515. foreach ($toChange as $key => $value)
  2516. if (in_array($value, $searchArray))
  2517. {
  2518. if (isset($new_labels[$value]))
  2519. $toChange[$key] = $new_labels[$value];
  2520. else
  2521. unset($toChange[$key]);
  2522. }
  2523. if (empty($toChange))
  2524. $toChange[] = '-1';
  2525. // Update the message.
  2526. $smcFunc['db_query']('', '
  2527. UPDATE {db_prefix}pm_recipients
  2528. SET labels = {string:new_labels}
  2529. WHERE id_pm = {int:id_pm}
  2530. AND id_member = {int:current_member}',
  2531. array(
  2532. 'current_member' => $user_info['id'],
  2533. 'id_pm' => $row['id_pm'],
  2534. 'new_labels' => implode(',', array_unique($toChange)),
  2535. )
  2536. );
  2537. }
  2538. $smcFunc['db_free_result']($request);
  2539. // Now do the same the rules - check through each rule.
  2540. foreach ($context['rules'] as $k => $rule)
  2541. {
  2542. // Each action...
  2543. foreach ($rule['actions'] as $k2 => $action)
  2544. {
  2545. if ($action['t'] != 'lab' || !in_array($action['v'], $searchArray))
  2546. continue;
  2547. $rule_changes[] = $rule['id'];
  2548. // If we're here we have a label which is either changed or gone...
  2549. if (isset($new_labels[$action['v']]))
  2550. $context['rules'][$k]['actions'][$k2]['v'] = $new_labels[$action['v']];
  2551. else
  2552. unset($context['rules'][$k]['actions'][$k2]);
  2553. }
  2554. }
  2555. }
  2556. // If we have rules to change do so now.
  2557. if (!empty($rule_changes))
  2558. {
  2559. $rule_changes = array_unique($rule_changes);
  2560. // Update/delete as appropriate.
  2561. foreach ($rule_changes as $k => $id)
  2562. if (!empty($context['rules'][$id]['actions']))
  2563. {
  2564. $smcFunc['db_query']('', '
  2565. UPDATE {db_prefix}pm_rules
  2566. SET actions = {string:actions}
  2567. WHERE id_rule = {int:id_rule}
  2568. AND id_member = {int:current_member}',
  2569. array(
  2570. 'current_member' => $user_info['id'],
  2571. 'id_rule' => $id,
  2572. 'actions' => serialize($context['rules'][$id]['actions']),
  2573. )
  2574. );
  2575. unset($rule_changes[$k]);
  2576. }
  2577. // Anything left here means it's lost all actions...
  2578. if (!empty($rule_changes))
  2579. $smcFunc['db_query']('', '
  2580. DELETE FROM {db_prefix}pm_rules
  2581. WHERE id_rule IN ({array_int:rule_list})
  2582. AND id_member = {int:current_member}',
  2583. array(
  2584. 'current_member' => $user_info['id'],
  2585. 'rule_list' => $rule_changes,
  2586. )
  2587. );
  2588. }
  2589. // Make sure we're not caching this!
  2590. cache_put_data('labelCounts:' . $user_info['id'], null, 720);
  2591. // To make the changes appear right away, redirect.
  2592. redirectexit('action=pm;sa=manlabels');
  2593. }
  2594. }
  2595. // Edit Personal Message Settings
  2596. function MessageSettings()
  2597. {
  2598. global $txt, $user_settings, $user_info, $context, $sourcedir, $smcFunc;
  2599. global $scripturl, $profile_vars, $cur_profile, $user_profile;
  2600. // Need this for the display.
  2601. require_once($sourcedir . '/Profile.php');
  2602. require_once($sourcedir . '/Profile-Modify.php');
  2603. // We want them to submit back to here.
  2604. $context['profile_custom_submit_url'] = $scripturl . '?action=pm;sa=settings;save';
  2605. loadMemberData($user_info['id'], false, 'profile');
  2606. $cur_profile = $user_profile[$user_info['id']];
  2607. loadLanguage('Profile');
  2608. loadTemplate('Profile');
  2609. $context['page_title'] = $txt['pm_settings'];
  2610. $context['user']['is_owner'] = true;
  2611. $context['id_member'] = $user_info['id'];
  2612. $context['require_password'] = false;
  2613. $context['menu_item_selected'] = 'settings';
  2614. $context['submit_button_text'] = $txt['pm_settings'];
  2615. $context['profile_header_text'] = $txt['personal_messages'];
  2616. // Add our position to the linktree.
  2617. $context['linktree'][] = array(
  2618. 'url' => $scripturl . '?action=pm;sa=settings',
  2619. 'name' => $txt['pm_settings']
  2620. );
  2621. // Are they saving?
  2622. if (isset($_REQUEST['save']))
  2623. {
  2624. checkSession('post');
  2625. // Mimic what profile would do.
  2626. $_POST = htmltrim__recursive($_POST);
  2627. $_POST = htmlspecialchars__recursive($_POST);
  2628. // Save the fields.
  2629. saveProfileFields();
  2630. if (!empty($profile_vars))
  2631. updateMemberData($user_info['id'], $profile_vars);
  2632. }
  2633. // Load up the fields.
  2634. pmprefs($user_info['id']);
  2635. }
  2636. // Allows a user to report a personal message they receive to the administrator.
  2637. function ReportMessage()
  2638. {
  2639. global $txt, $context, $scripturl, $sourcedir;
  2640. global $user_info, $language, $modSettings, $smcFunc;
  2641. // Check that this feature is even enabled!
  2642. if (empty($modSettings['enableReportPM']) || empty($_REQUEST['pmsg']))
  2643. fatal_lang_error('no_access', false);
  2644. $pmsg = (int) $_REQUEST['pmsg'];
  2645. if (!isAccessiblePM($pmsg, 'inbox'))
  2646. fatal_lang_error('no_access', false);
  2647. $context['pm_id'] = $pmsg;
  2648. $context['page_title'] = $txt['pm_report_title'];
  2649. // If we're here, just send the user to the template, with a few useful context bits.
  2650. if (!isset($_POST['report']))
  2651. {
  2652. $context['sub_template'] = 'report_message';
  2653. // !!! I don't like being able to pick who to send it to. Favoritism, etc. sucks.
  2654. // Now, get all the administrators.
  2655. $request = $smcFunc['db_query']('', '
  2656. SELECT id_member, real_name
  2657. FROM {db_prefix}members
  2658. WHERE id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0
  2659. ORDER BY real_name',
  2660. array(
  2661. 'admin_group' => 1,
  2662. )
  2663. );
  2664. $context['admins'] = array();
  2665. while ($row = $smcFunc['db_fetch_assoc']($request))
  2666. $context['admins'][$row['id_member']] = $row['real_name'];
  2667. $smcFunc['db_free_result']($request);
  2668. // How many admins in total?
  2669. $context['admin_count'] = count($context['admins']);
  2670. }
  2671. // Otherwise, let's get down to the sending stuff.
  2672. else
  2673. {
  2674. // Check the session before proceeding any further!
  2675. checkSession('post');
  2676. // First, pull out the message contents, and verify it actually went to them!
  2677. $request = $smcFunc['db_query']('', '
  2678. SELECT pm.subject, pm.body, pm.msgtime, pm.id_member_from, IFNULL(m.real_name, pm.from_name) AS sender_name
  2679. FROM {db_prefix}personal_messages AS pm
  2680. INNER JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm)
  2681. LEFT JOIN {db_prefix}members AS m ON (m.id_member = pm.id_member_from)
  2682. WHERE pm.id_pm = {int:id_pm}
  2683. AND pmr.id_member = {int:current_member}
  2684. AND pmr.deleted = {int:not_deleted}
  2685. LIMIT 1',
  2686. array(
  2687. 'current_member' => $user_info['id'],
  2688. 'id_pm' => $context['pm_id'],
  2689. 'not_deleted' => 0,
  2690. )
  2691. );
  2692. // Can only be a hacker here!
  2693. if ($smcFunc['db_num_rows']($request) == 0)
  2694. fatal_lang_error('no_access', false);
  2695. list ($subject, $body, $time, $memberFromID, $memberFromName) = $smcFunc['db_fetch_row']($request);
  2696. $smcFunc['db_free_result']($request);
  2697. // Remove the line breaks...
  2698. $body = preg_replace('~<br ?/?' . '>~i', "\n", $body);
  2699. // Get any other recipients of the email.
  2700. $request = $smcFunc['db_query']('', '
  2701. SELECT mem_to.id_member AS id_member_to, mem_to.real_name AS to_name, pmr.bcc
  2702. FROM {db_prefix}pm_recipients AS pmr
  2703. LEFT JOIN {db_prefix}members AS mem_to ON (mem_to.id_member = pmr.id_member)
  2704. WHERE pmr.id_pm = {int:id_pm}
  2705. AND pmr.id_member != {int:current_member}',
  2706. array(
  2707. 'current_member' => $user_info['id'],
  2708. 'id_pm' => $context['pm_id'],
  2709. )
  2710. );
  2711. $recipients = array();
  2712. $hidden_recipients = 0;
  2713. while ($row = $smcFunc['db_fetch_assoc']($request))
  2714. {
  2715. // If it's hidden still don't reveal their names - privacy after all ;)
  2716. if ($row['bcc'])
  2717. $hidden_recipients++;
  2718. else
  2719. $recipients[] = '[url=' . $scripturl . '?action=profile;u=' . $row['id_member_to'] . ']' . $row['to_name'] . '[/url]';
  2720. }
  2721. $smcFunc['db_free_result']($request);
  2722. if ($hidden_recipients)
  2723. $recipients[] = sprintf($txt['pm_report_pm_hidden'], $hidden_recipients);
  2724. // Now let's get out and loop through the admins.
  2725. $request = $smcFunc['db_query']('', '
  2726. SELECT id_member, real_name, lngfile
  2727. FROM {db_prefix}members
  2728. WHERE (id_group = {int:admin_id} OR FIND_IN_SET({int:admin_id}, additional_groups) != 0)
  2729. ' . (empty($_POST['ID_ADMIN']) ? '' : 'AND id_member = {int:specific_admin}') . '
  2730. ORDER BY lngfile',
  2731. array(
  2732. 'admin_id' => 1,
  2733. 'specific_admin' => isset($_POST['ID_ADMIN']) ? (int) $_POST['ID_ADMIN'] : 0,
  2734. )
  2735. );
  2736. // Maybe we shouldn't advertise this?
  2737. if ($smcFunc['db_num_rows']($request) == 0)
  2738. fatal_lang_error('no_access', false);
  2739. $memberFromName = un_htmlspecialchars($memberFromName);
  2740. // Prepare the message storage array.
  2741. $messagesToSend = array();
  2742. // Loop through each admin, and add them to the right language pile...
  2743. while ($row = $smcFunc['db_fetch_assoc']($request))
  2744. {
  2745. // Need to send in the correct language!
  2746. $cur_language = empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile'];
  2747. if (!isset($messagesToSend[$cur_language]))
  2748. {
  2749. loadLanguage('PersonalMessage', $cur_language, false);
  2750. // Make the body.
  2751. $report_body = str_replace(array('{REPORTER}', '{SENDER}'), array(un_htmlspecialchars($user_info['name']), $memberFromName), $txt['pm_report_pm_user_sent']);
  2752. $report_body .= "\n" . '[b]' . $_POST['reason'] . '[/b]' . "\n\n";
  2753. if (!empty($recipients))
  2754. $report_body .= $txt['pm_report_pm_other_recipients'] . ' ' . implode(', ', $recipients) . "\n\n";
  2755. $report_body .= $txt['pm_report_pm_unedited_below'] . "\n" . '[quote author=' . (empty($memberFromID) ? '&quot;' . $memberFromName . '&quot;' : $memberFromName . ' link=action=profile;u=' . $memberFromID . ' date=' . $time) . ']' . "\n" . un_htmlspecialchars($body) . '[/quote]';
  2756. // Plonk it in the array ;)
  2757. $messagesToSend[$cur_language] = array(
  2758. 'subject' => ($smcFunc['strpos']($subject, $txt['pm_report_pm_subject']) === false ? $txt['pm_report_pm_subject'] : '') . un_htmlspecialchars($subject),
  2759. 'body' => $report_body,
  2760. 'recipients' => array(
  2761. 'to' => array(),
  2762. 'bcc' => array()
  2763. ),
  2764. );
  2765. }
  2766. // Add them to the list.
  2767. $messagesToSend[$cur_language]['recipients']['to'][$row['id_member']] = $row['id_member'];
  2768. }
  2769. $smcFunc['db_free_result']($request);
  2770. // Send a different email for each language.
  2771. foreach ($messagesToSend as $lang => $message)
  2772. sendpm($message['recipients'], $message['subject'], $message['body']);
  2773. // Give the user their own language back!
  2774. if (!empty($modSettings['userLanguage']))
  2775. loadLanguage('PersonalMessage', '', false);
  2776. // Leave them with a template.
  2777. $context['sub_template'] = 'report_message_complete';
  2778. }
  2779. }
  2780. // List all rules, and allow adding/entering etc....
  2781. function ManageRules()
  2782. {
  2783. global $txt, $context, $user_info, $scripturl, $smcFunc;
  2784. // The link tree - gotta have this :o
  2785. $context['linktree'][] = array(
  2786. 'url' => $scripturl . '?action=pm;sa=manrules',
  2787. 'name' => $txt['pm_manage_rules']
  2788. );
  2789. $context['page_title'] = $txt['pm_manage_rules'];
  2790. $context['sub_template'] = 'rules';
  2791. // Load them... load them!!
  2792. LoadRules();
  2793. // Likely to need all the groups!
  2794. $request = $smcFunc['db_query']('', '
  2795. SELECT mg.id_group, mg.group_name, IFNULL(gm.id_member, 0) AS can_moderate, mg.hidden
  2796. FROM {db_prefix}membergroups AS mg
  2797. LEFT JOIN {db_prefix}group_moderators AS gm ON (gm.id_group = mg.id_group AND gm.id_member = {int:current_member})
  2798. WHERE mg.min_posts = {int:min_posts}
  2799. AND mg.id_group != {int:moderator_group}
  2800. AND mg.hidden = {int:not_hidden}
  2801. ORDER BY mg.group_name',
  2802. array(
  2803. 'current_member' => $user_info['id'],
  2804. 'min_posts' => -1,
  2805. 'moderator_group' => 3,
  2806. 'not_hidden' => 0,
  2807. )
  2808. );
  2809. $context['groups'] = array();
  2810. while ($row = $smcFunc['db_fetch_assoc']($request))
  2811. {
  2812. // Hide hidden groups!
  2813. if ($row['hidden'] && !$row['can_moderate'] && !allowedTo('manage_membergroups'))
  2814. continue;
  2815. $context['groups'][$row['id_group']] = $row['group_name'];
  2816. }
  2817. $smcFunc['db_free_result']($request);
  2818. // Applying all rules?
  2819. if (isset($_GET['apply']))
  2820. {
  2821. checkSession('get');
  2822. ApplyRules(true);
  2823. redirectexit('action=pm;sa=manrules');
  2824. }
  2825. // Editing a specific one?
  2826. if (isset($_GET['add']))
  2827. {
  2828. $context['rid'] = isset($_GET['rid']) && isset($context['rules'][$_GET['rid']])? (int) $_GET['rid'] : 0;
  2829. $context['sub_template'] = 'add_rule';
  2830. // Current rule information...
  2831. if ($context['rid'])
  2832. {
  2833. $context['rule'] = $context['rules'][$context['rid']];
  2834. $members = array();
  2835. // Need to get member names!
  2836. foreach ($context['rule']['criteria'] as $k => $criteria)
  2837. if ($criteria['t'] == 'mid' && !empty($criteria['v']))
  2838. $members[(int) $criteria['v']] = $k;
  2839. if (!empty($members))
  2840. {
  2841. $request = $smcFunc['db_query']('', '
  2842. SELECT id_member, member_name
  2843. FROM {db_prefix}members
  2844. WHERE id_member IN ({array_int:member_list})',
  2845. array(
  2846. 'member_list' => array_keys($members),
  2847. )
  2848. );
  2849. while ($row = $smcFunc['db_fetch_assoc']($request))
  2850. $context['rule']['criteria'][$members[$row['id_member']]]['v'] = $row['member_name'];
  2851. $smcFunc['db_free_result']($request);
  2852. }
  2853. }
  2854. else
  2855. $context['rule'] = array(
  2856. 'id' => '',
  2857. 'name' => '',
  2858. 'criteria' => array(),
  2859. 'actions' => array(),
  2860. 'logic' => 'and',
  2861. );
  2862. }
  2863. // Saving?
  2864. elseif (isset($_GET['save']))
  2865. {
  2866. checkSession('post');
  2867. $context['rid'] = isset($_GET['rid']) && isset($context['rules'][$_GET['rid']])? (int) $_GET['rid'] : 0;
  2868. // Name is easy!
  2869. $ruleName = $smcFunc['htmlspecialchars'](trim($_POST['rule_name']));
  2870. if (empty($ruleName))
  2871. fatal_lang_error('pm_rule_no_name', false);
  2872. // Sanity check...
  2873. if (empty($_POST['ruletype']) || empty($_POST['acttype']))
  2874. fatal_lang_error('pm_rule_no_criteria', false);
  2875. // Let's do the criteria first - it's also hardest!
  2876. $criteria = array();
  2877. foreach ($_POST['ruletype'] as $ind => $type)
  2878. {
  2879. // Check everything is here...
  2880. if ($type == 'gid' && (!isset($_POST['ruledefgroup'][$ind]) || !isset($context['groups'][$_POST['ruledefgroup'][$ind]])))
  2881. continue;
  2882. elseif ($type != 'bud' && !isset($_POST['ruledef'][$ind]))
  2883. continue;
  2884. // Members need to be found.
  2885. if ($type == 'mid')
  2886. {
  2887. $name = trim($_POST['ruledef'][$ind]);
  2888. $request = $smcFunc['db_query']('', '
  2889. SELECT id_member
  2890. FROM {db_prefix}members
  2891. WHERE real_name = {string:member_name}
  2892. OR member_name = {string:member_name}',
  2893. array(
  2894. 'member_name' => $name,
  2895. )
  2896. );
  2897. if ($smcFunc['db_num_rows']($request) == 0)
  2898. continue;
  2899. list ($memID) = $smcFunc['db_fetch_row']($request);
  2900. $smcFunc['db_free_result']($request);
  2901. $criteria[] = array('t' => 'mid', 'v' => $memID);
  2902. }
  2903. elseif ($type == 'bud')
  2904. $criteria[] = array('t' => 'bud', 'v' => 1);
  2905. elseif ($type == 'gid')
  2906. $criteria[] = array('t' => 'gid', 'v' => (int) $_POST['ruledefgroup'][$ind]);
  2907. elseif (in_array($type, array('sub', 'msg')) && trim($_POST['ruledef'][$ind]) != '')
  2908. $criteria[] = array('t' => $type, 'v' => $smcFunc['htmlspecialchars'](trim($_POST['ruledef'][$ind])));
  2909. }
  2910. // Also do the actions!
  2911. $actions = array();
  2912. $doDelete = 0;
  2913. $isOr = $_POST['rule_logic'] == 'or' ? 1 : 0;
  2914. foreach ($_POST['acttype'] as $ind => $type)
  2915. {
  2916. // Picking a valid label?
  2917. if ($type == 'lab' && (!isset($_POST['labdef'][$ind]) || !isset($context['labels'][$_POST['labdef'][$ind] - 1])))
  2918. continue;
  2919. // Record what we're doing.
  2920. if ($type == 'del')
  2921. $doDelete = 1;
  2922. elseif ($type == 'lab')
  2923. $actions[] = array('t' => 'lab', 'v' => (int) $_POST['labdef'][$ind] - 1);
  2924. }
  2925. if (empty($criteria) || (empty($actions) && !$doDelete))
  2926. fatal_lang_error('pm_rule_no_criteria', false);
  2927. // What are we storing?
  2928. $criteria = serialize($criteria);
  2929. $actions = serialize($actions);
  2930. // Create the rule?
  2931. if (empty($context['rid']))
  2932. $smcFunc['db_insert']('',
  2933. '{db_prefix}pm_rules',
  2934. array(
  2935. 'id_member' => 'int', 'rule_name' => 'string', 'criteria' => 'string', 'actions' => 'string',
  2936. 'delete_pm' => 'int', 'is_or' => 'int',
  2937. ),
  2938. array(
  2939. $user_info['id'], $ruleName, $criteria, $actions, $doDelete, $isOr,
  2940. ),
  2941. array('id_rule')
  2942. );
  2943. else
  2944. $smcFunc['db_query']('', '
  2945. UPDATE {db_prefix}pm_rules
  2946. SET rule_name = {string:rule_name}, criteria = {string:criteria}, actions = {string:actions},
  2947. delete_pm = {int:delete_pm}, is_or = {int:is_or}
  2948. WHERE id_rule = {int:id_rule}
  2949. AND id_member = {int:current_member}',
  2950. array(
  2951. 'current_member' => $user_info['id'],
  2952. 'delete_pm' => $doDelete,
  2953. 'is_or' => $isOr,
  2954. 'id_rule' => $context['rid'],
  2955. 'rule_name' => $ruleName,
  2956. 'criteria' => $criteria,
  2957. 'actions' => $actions,
  2958. )
  2959. );
  2960. redirectexit('action=pm;sa=manrules');
  2961. }
  2962. // Deleting?
  2963. elseif (isset($_POST['delselected']) && !empty($_POST['delrule']))
  2964. {
  2965. checkSession('post');
  2966. $toDelete = array();
  2967. foreach ($_POST['delrule'] as $k => $v)
  2968. $toDelete[] = (int) $k;
  2969. if (!empty($toDelete))
  2970. $smcFunc['db_query']('', '
  2971. DELETE FROM {db_prefix}pm_rules
  2972. WHERE id_rule IN ({array_int:delete_list})
  2973. AND id_member = {int:current_member}',
  2974. array(
  2975. 'current_member' => $user_info['id'],
  2976. 'delete_list' => $toDelete,
  2977. )
  2978. );
  2979. redirectexit('action=pm;sa=manrules');
  2980. }
  2981. }
  2982. // This will apply rules to all unread messages. If all_messages is set will, clearly, do it to all!
  2983. function ApplyRules($all_messages = false)
  2984. {
  2985. global $user_info, $smcFunc, $context, $options;
  2986. // Want this - duh!
  2987. loadRules();
  2988. // No rules?
  2989. if (empty($context['rules']))
  2990. return;
  2991. // Just unread ones?
  2992. $ruleQuery = $all_messages ? '' : ' AND pmr.is_new = 1';
  2993. //!!! Apply all should have timeout protection!
  2994. // Get all the messages that match this.
  2995. $request = $smcFunc['db_query']('', '
  2996. SELECT
  2997. pmr.id_pm, pm.id_member_from, pm.subject, pm.body, mem.id_group, pmr.labels
  2998. FROM {db_prefix}pm_recipients AS pmr
  2999. INNER JOIN {db_prefix}personal_messages AS pm ON (pm.id_pm = pmr.id_pm)
  3000. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = pm.id_member_from)
  3001. WHERE pmr.id_member = {int:current_member}
  3002. AND pmr.deleted = {int:not_deleted}
  3003. ' . $ruleQuery,
  3004. array(
  3005. 'current_member' => $user_info['id'],
  3006. 'not_deleted' => 0,
  3007. )
  3008. );
  3009. $actions = array();
  3010. while ($row = $smcFunc['db_fetch_assoc']($request))
  3011. {
  3012. foreach ($context['rules'] as $rule)
  3013. {
  3014. $match = false;
  3015. // Loop through all the criteria hoping to make a match.
  3016. foreach ($rule['criteria'] as $criterium)
  3017. {
  3018. if (($criterium['t'] == 'mid' && $criterium['v'] == $row['id_member_from']) || ($criterium['t'] == 'gid' && $criterium['v'] == $row['id_group']) || ($criterium['t'] == 'sub' && strpos($row['subject'], $criterium['v']) !== false) || ($criterium['t'] == 'msg' && strpos($row['body'], $criterium['v']) !== false))
  3019. $match = true;
  3020. // If we're adding and one criteria don't match then we stop!
  3021. elseif ($rule['logic'] == 'and')
  3022. {
  3023. $match = false;
  3024. break;
  3025. }
  3026. }
  3027. // If we have a match the rule must be true - act!
  3028. if ($match)
  3029. {
  3030. if ($rule['delete'])
  3031. $actions['deletes'][] = $row['id_pm'];
  3032. else
  3033. {
  3034. foreach ($rule['actions'] as $ruleAction)
  3035. {
  3036. if ($ruleAction['t'] == 'lab')
  3037. {
  3038. // Get a basic pot started!
  3039. if (!isset($actions['labels'][$row['id_pm']]))
  3040. $actions['labels'][$row['id_pm']] = empty($row['labels']) ? array() : explode(',', $row['labels']);
  3041. $actions['labels'][$row['id_pm']][] = $ruleAction['v'];
  3042. }
  3043. }
  3044. }
  3045. }
  3046. }
  3047. }
  3048. $smcFunc['db_free_result']($request);
  3049. // Deletes are easy!
  3050. if (!empty($actions['deletes']))
  3051. deleteMessages($actions['deletes']);
  3052. // Relabel?
  3053. if (!empty($actions['labels']))
  3054. {
  3055. foreach ($actions['labels'] as $pm => $labels)
  3056. {
  3057. // Quickly check each label is valid!
  3058. $realLabels = array();
  3059. foreach ($context['labels'] as $label)
  3060. if (in_array($label['id'], $labels) && ($label['id'] != -1 || empty($options['pm_remove_inbox_label'])))
  3061. $realLabels[] = $label['id'];
  3062. $smcFunc['db_query']('', '
  3063. UPDATE {db_prefix}pm_recipients
  3064. SET labels = {string:new_labels}
  3065. WHERE id_pm = {int:id_pm}
  3066. AND id_member = {int:current_member}',
  3067. array(
  3068. 'current_member' => $user_info['id'],
  3069. 'id_pm' => $pm,
  3070. 'new_labels' => empty($realLabels) ? '' : implode(',', $realLabels),
  3071. )
  3072. );
  3073. }
  3074. }
  3075. }
  3076. // Load up all the rules for the current user.
  3077. function LoadRules($reload = false)
  3078. {
  3079. global $user_info, $context, $smcFunc;
  3080. if (isset($context['rules']) && !$reload)
  3081. return;
  3082. $request = $smcFunc['db_query']('', '
  3083. SELECT
  3084. id_rule, rule_name, criteria, actions, delete_pm, is_or
  3085. FROM {db_prefix}pm_rules
  3086. WHERE id_member = {int:current_member}',
  3087. array(
  3088. 'current_member' => $user_info['id'],
  3089. )
  3090. );
  3091. $context['rules'] = array();
  3092. // Simply fill in the data!
  3093. while ($row = $smcFunc['db_fetch_assoc']($request))
  3094. {
  3095. $context['rules'][$row['id_rule']] = array(
  3096. 'id' => $row['id_rule'],
  3097. 'name' => $row['rule_name'],
  3098. 'criteria' => unserialize($row['criteria']),
  3099. 'actions' => unserialize($row['actions']),
  3100. 'delete' => $row['delete_pm'],
  3101. 'logic' => $row['is_or'] ? 'or' : 'and',
  3102. );
  3103. if ($row['delete_pm'])
  3104. $context['rules'][$row['id_rule']]['actions'][] = array('t' => 'del', 'v' => 1);
  3105. }
  3106. $smcFunc['db_free_result']($request);
  3107. }
  3108. // Check if the PM is available to the current user.
  3109. function isAccessiblePM($pmID, $validFor = 'in_or_outbox')
  3110. {
  3111. global $user_info, $smcFunc;
  3112. $request = $smcFunc['db_query']('', '
  3113. SELECT
  3114. pm.id_member_from = {int:id_current_member} AND pm.deleted_by_sender = {int:not_deleted} AS valid_for_outbox,
  3115. pmr.id_pm IS NOT NULL AS valid_for_inbox
  3116. FROM {db_prefix}personal_messages AS pm
  3117. LEFT JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm AND pmr.id_member = {int:id_current_member} AND pmr.deleted = {int:not_deleted})
  3118. WHERE pm.id_pm = {int:id_pm}
  3119. AND ((pm.id_member_from = {int:id_current_member} AND pm.deleted_by_sender = {int:not_deleted}) OR pmr.id_pm IS NOT NULL)',
  3120. array(
  3121. 'id_pm' => $pmID,
  3122. 'id_current_member' => $user_info['id'],
  3123. 'not_deleted' => 0,
  3124. )
  3125. );
  3126. if ($smcFunc['db_num_rows']($request) === 0)
  3127. {
  3128. $smcFunc['db_free_result']($request);
  3129. return false;
  3130. }
  3131. $validationResult = $smcFunc['db_fetch_assoc']($request);
  3132. $smcFunc['db_free_result']($request);
  3133. switch ($validFor)
  3134. {
  3135. case 'inbox':
  3136. return !empty($validationResult['valid_for_inbox']);
  3137. break;
  3138. case 'outbox':
  3139. return !empty($validationResult['valid_for_outbox']);
  3140. break;
  3141. case 'in_or_outbox':
  3142. return !empty($validationResult['valid_for_inbox']) || !empty($validationResult['valid_for_outbox']);
  3143. break;
  3144. default:
  3145. trigger_error('Undefined validation type given', E_USER_ERROR);
  3146. break;
  3147. }
  3148. }
  3149. ?>