PageRenderTime 45ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/php/Sources/PersonalMessage.php

https://github.com/dekoza/openshift-smf-2.0.7
PHP | 3621 lines | 2729 code | 447 blank | 445 comment | 621 complexity | f1ab7466f39b46dfab708e048d5b1a44 MD5 | raw file
Possible License(s): BSD-3-Clause

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

  1. <?php
  2. /**
  3. * Simple Machines Forum (SMF)
  4. *
  5. * @package SMF
  6. * @author Simple Machines http://www.simplemachines.org
  7. * @copyright 2011 Simple Machines
  8. * @license http://www.simplemachines.org/about/smf/license.php BSD
  9. *
  10. * @version 2.0.5
  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. {
  230. $_REQUEST['sa'] = '';
  231. MessageFolder();
  232. }
  233. else
  234. {
  235. messageIndexBar($_REQUEST['sa']);
  236. $subActions[$_REQUEST['sa']]();
  237. }
  238. }
  239. // A sidebar to easily access different areas of the section
  240. function messageIndexBar($area)
  241. {
  242. global $txt, $context, $scripturl, $sourcedir, $sc, $modSettings, $settings, $user_info, $options;
  243. $pm_areas = array(
  244. 'folders' => array(
  245. 'title' => $txt['pm_messages'],
  246. 'areas' => array(
  247. 'send' => array(
  248. 'label' => $txt['new_message'],
  249. 'custom_url' => $scripturl . '?action=pm;sa=send',
  250. 'permission' => allowedTo('pm_send'),
  251. ),
  252. 'inbox' => array(
  253. 'label' => $txt['inbox'],
  254. 'custom_url' => $scripturl . '?action=pm',
  255. ),
  256. 'sent' => array(
  257. 'label' => $txt['sent_items'],
  258. 'custom_url' => $scripturl . '?action=pm;f=sent',
  259. ),
  260. ),
  261. ),
  262. 'labels' => array(
  263. 'title' => $txt['pm_labels'],
  264. 'areas' => array(),
  265. ),
  266. 'actions' => array(
  267. 'title' => $txt['pm_actions'],
  268. 'areas' => array(
  269. 'search' => array(
  270. 'label' => $txt['pm_search_bar_title'],
  271. 'custom_url' => $scripturl . '?action=pm;sa=search',
  272. ),
  273. 'prune' => array(
  274. 'label' => $txt['pm_prune'],
  275. 'custom_url' => $scripturl . '?action=pm;sa=prune'
  276. ),
  277. ),
  278. ),
  279. 'pref' => array(
  280. 'title' => $txt['pm_preferences'],
  281. 'areas' => array(
  282. 'manlabels' => array(
  283. 'label' => $txt['pm_manage_labels'],
  284. 'custom_url' => $scripturl . '?action=pm;sa=manlabels',
  285. ),
  286. 'manrules' => array(
  287. 'label' => $txt['pm_manage_rules'],
  288. 'custom_url' => $scripturl . '?action=pm;sa=manrules',
  289. ),
  290. 'settings' => array(
  291. 'label' => $txt['pm_settings'],
  292. 'custom_url' => $scripturl . '?action=pm;sa=settings',
  293. ),
  294. ),
  295. ),
  296. );
  297. // Handle labels.
  298. if (empty($context['currently_using_labels']))
  299. unset($pm_areas['labels']);
  300. else
  301. {
  302. // Note we send labels by id as it will have less problems in the querystring.
  303. $unread_in_labels = 0;
  304. foreach ($context['labels'] as $label)
  305. {
  306. if ($label['id'] == -1)
  307. continue;
  308. // Count the amount of unread items in labels.
  309. $unread_in_labels += $label['unread_messages'];
  310. // Add the label to the menu.
  311. $pm_areas['labels']['areas']['label' . $label['id']] = array(
  312. 'label' => $label['name'] . (!empty($label['unread_messages']) ? ' (<strong>' . $label['unread_messages'] . '</strong>)' : ''),
  313. 'custom_url' => $scripturl . '?action=pm;l=' . $label['id'],
  314. 'unread_messages' => $label['unread_messages'],
  315. 'messages' => $label['messages'],
  316. );
  317. }
  318. if (!empty($unread_in_labels))
  319. $pm_areas['labels']['title'] .= ' (' . $unread_in_labels . ')';
  320. }
  321. $pm_areas['folders']['areas']['inbox']['unread_messages'] = &$context['labels'][-1]['unread_messages'];
  322. $pm_areas['folders']['areas']['inbox']['messages'] = &$context['labels'][-1]['messages'];
  323. if (!empty($context['labels'][-1]['unread_messages']))
  324. {
  325. $pm_areas['folders']['areas']['inbox']['label'] .= ' (<strong>' . $context['labels'][-1]['unread_messages'] . '</strong>)';
  326. $pm_areas['folders']['title'] .= ' (' . $context['labels'][-1]['unread_messages'] . ')';
  327. }
  328. // Do we have a limit on the amount of messages we can keep?
  329. if (!empty($context['message_limit']))
  330. {
  331. $bar = round(($user_info['messages'] * 100) / $context['message_limit'], 1);
  332. $context['limit_bar'] = array(
  333. 'messages' => $user_info['messages'],
  334. 'allowed' => $context['message_limit'],
  335. 'percent' => $bar,
  336. 'bar' => $bar > 100 ? 100 : (int) $bar,
  337. 'text' => sprintf($txt['pm_currently_using'], $user_info['messages'], $bar)
  338. );
  339. }
  340. require_once($sourcedir . '/Subs-Menu.php');
  341. // What page is this, again?
  342. $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'] : '');
  343. // Set a few options for the menu.
  344. $menuOptions = array(
  345. 'current_area' => $area,
  346. 'disable_url_session_check' => true,
  347. 'toggle_url' => $current_page . ';togglebar',
  348. 'toggle_redirect_url' => $current_page,
  349. );
  350. // Actually create the menu!
  351. $pm_include_data = createMenu($pm_areas, $menuOptions);
  352. unset($pm_areas);
  353. // Make a note of the Unique ID for this menu.
  354. $context['pm_menu_id'] = $context['max_menu_id'];
  355. $context['pm_menu_name'] = 'menu_data_' . $context['pm_menu_id'];
  356. // Set the selected item.
  357. $context['menu_item_selected'] = $pm_include_data['current_area'];
  358. // obExit will know what to do!
  359. if (!WIRELESS)
  360. $context['template_layers'][] = 'pm';
  361. }
  362. // A folder, ie. inbox/sent etc.
  363. function MessageFolder()
  364. {
  365. global $txt, $scripturl, $modSettings, $context, $subjects_request;
  366. global $messages_request, $user_info, $recipients, $options, $smcFunc, $memberContext, $user_settings;
  367. // Changing view?
  368. if (isset($_GET['view']))
  369. {
  370. $context['display_mode'] = $context['display_mode'] > 1 ? 0 : $context['display_mode'] + 1;
  371. updateMemberData($user_info['id'], array('pm_prefs' => ($user_settings['pm_prefs'] & 252) | $context['display_mode']));
  372. }
  373. // Make sure the starting location is valid.
  374. if (isset($_GET['start']) && $_GET['start'] != 'new')
  375. $_GET['start'] = (int) $_GET['start'];
  376. elseif (!isset($_GET['start']) && !empty($options['view_newest_pm_first']))
  377. $_GET['start'] = 0;
  378. else
  379. $_GET['start'] = 'new';
  380. // Set up some basic theme stuff.
  381. $context['from_or_to'] = $context['folder'] != 'sent' ? 'from' : 'to';
  382. $context['get_pmessage'] = 'prepareMessageContext';
  383. $context['signature_enabled'] = substr($modSettings['signature_settings'], 0, 1) == 1;
  384. $labelQuery = $context['folder'] != 'sent' ? '
  385. AND FIND_IN_SET(' . $context['current_label_id'] . ', pmr.labels) != 0' : '';
  386. // Set the index bar correct!
  387. messageIndexBar($context['current_label_id'] == -1 ? $context['folder'] : 'label' . $context['current_label_id']);
  388. // Sorting the folder.
  389. $sort_methods = array(
  390. 'date' => 'pm.id_pm',
  391. 'name' => 'IFNULL(mem.real_name, \'\')',
  392. 'subject' => 'pm.subject',
  393. );
  394. // They didn't pick one, use the forum default.
  395. if (!isset($_GET['sort']) || !isset($sort_methods[$_GET['sort']]))
  396. {
  397. $context['sort_by'] = 'date';
  398. $_GET['sort'] = 'pm.id_pm';
  399. // An overriding setting?
  400. $descending = !empty($options['view_newest_pm_first']);
  401. }
  402. // Otherwise use the defaults: ascending, by date.
  403. else
  404. {
  405. $context['sort_by'] = $_GET['sort'];
  406. $_GET['sort'] = $sort_methods[$_GET['sort']];
  407. $descending = isset($_GET['desc']);
  408. }
  409. $context['sort_direction'] = $descending ? 'down' : 'up';
  410. // Why would you want access to your sent items if you're not allowed to send anything?
  411. if ($context['folder'] == 'sent')
  412. isAllowedTo('pm_send');
  413. // Set the text to resemble the current folder.
  414. $pmbox = $context['folder'] != 'sent' ? $txt['inbox'] : $txt['sent_items'];
  415. $txt['delete_all'] = str_replace('PMBOX', $pmbox, $txt['delete_all']);
  416. // Now, build the link tree!
  417. if ($context['current_label_id'] == -1)
  418. $context['linktree'][] = array(
  419. 'url' => $scripturl . '?action=pm;f=' . $context['folder'],
  420. 'name' => $pmbox
  421. );
  422. // Build it further for a label.
  423. if ($context['current_label_id'] != -1)
  424. $context['linktree'][] = array(
  425. 'url' => $scripturl . '?action=pm;f=' . $context['folder'] . ';l=' . $context['current_label_id'],
  426. 'name' => $txt['pm_current_label'] . ': ' . $context['current_label']
  427. );
  428. // Figure out how many messages there are.
  429. if ($context['folder'] == 'sent')
  430. $request = $smcFunc['db_query']('', '
  431. SELECT COUNT(' . ($context['display_mode'] == 2 ? 'DISTINCT pm.id_pm_head' : '*') . ')
  432. FROM {db_prefix}personal_messages AS pm
  433. WHERE pm.id_member_from = {int:current_member}
  434. AND pm.deleted_by_sender = {int:not_deleted}',
  435. array(
  436. 'current_member' => $user_info['id'],
  437. 'not_deleted' => 0,
  438. )
  439. );
  440. else
  441. $request = $smcFunc['db_query']('', '
  442. SELECT COUNT(' . ($context['display_mode'] == 2 ? 'DISTINCT pm.id_pm_head' : '*') . ')
  443. FROM {db_prefix}pm_recipients AS pmr' . ($context['display_mode'] == 2 ? '
  444. INNER JOIN {db_prefix}personal_messages AS pm ON (pm.id_pm = pmr.id_pm)' : '') . '
  445. WHERE pmr.id_member = {int:current_member}
  446. AND pmr.deleted = {int:not_deleted}' . $labelQuery,
  447. array(
  448. 'current_member' => $user_info['id'],
  449. 'not_deleted' => 0,
  450. )
  451. );
  452. list ($max_messages) = $smcFunc['db_fetch_row']($request);
  453. $smcFunc['db_free_result']($request);
  454. // Only show the button if there are messages to delete.
  455. $context['show_delete'] = $max_messages > 0;
  456. // Start on the last page.
  457. if (!is_numeric($_GET['start']) || $_GET['start'] >= $max_messages)
  458. $_GET['start'] = ($max_messages - 1) - (($max_messages - 1) % $modSettings['defaultMaxMessages']);
  459. elseif ($_GET['start'] < 0)
  460. $_GET['start'] = 0;
  461. // ... but wait - what if we want to start from a specific message?
  462. if (isset($_GET['pmid']))
  463. {
  464. $pmID = (int) $_GET['pmid'];
  465. // Make sure you have access to this PM.
  466. if (!isAccessiblePM($pmID, $context['folder'] == 'sent' ? 'outbox' : 'inbox'))
  467. fatal_lang_error('no_access', false);
  468. $context['current_pm'] = $pmID;
  469. // With only one page of PM's we're gonna want page 1.
  470. if ($max_messages <= $modSettings['defaultMaxMessages'])
  471. $_GET['start'] = 0;
  472. // If we pass kstart we assume we're in the right place.
  473. elseif (!isset($_GET['kstart']))
  474. {
  475. if ($context['folder'] == 'sent')
  476. $request = $smcFunc['db_query']('', '
  477. SELECT COUNT(' . ($context['display_mode'] == 2 ? 'DISTINCT pm.id_pm_head' : '*') . ')
  478. FROM {db_prefix}personal_messages
  479. WHERE id_member_from = {int:current_member}
  480. AND deleted_by_sender = {int:not_deleted}
  481. AND id_pm ' . ($descending ? '>' : '<') . ' {int:id_pm}',
  482. array(
  483. 'current_member' => $user_info['id'],
  484. 'not_deleted' => 0,
  485. 'id_pm' => $pmID,
  486. )
  487. );
  488. else
  489. $request = $smcFunc['db_query']('', '
  490. SELECT COUNT(' . ($context['display_mode'] == 2 ? 'DISTINCT pm.id_pm_head' : '*') . ')
  491. FROM {db_prefix}pm_recipients AS pmr' . ($context['display_mode'] == 2 ? '
  492. INNER JOIN {db_prefix}personal_messages AS pm ON (pm.id_pm = pmr.id_pm)' : '') . '
  493. WHERE pmr.id_member = {int:current_member}
  494. AND pmr.deleted = {int:not_deleted}' . $labelQuery . '
  495. AND pmr.id_pm ' . ($descending ? '>' : '<') . ' {int:id_pm}',
  496. array(
  497. 'current_member' => $user_info['id'],
  498. 'not_deleted' => 0,
  499. 'id_pm' => $pmID,
  500. )
  501. );
  502. list ($_GET['start']) = $smcFunc['db_fetch_row']($request);
  503. $smcFunc['db_free_result']($request);
  504. // To stop the page index's being abnormal, start the page on the page the message would normally be located on...
  505. $_GET['start'] = $modSettings['defaultMaxMessages'] * (int) ($_GET['start'] / $modSettings['defaultMaxMessages']);
  506. }
  507. }
  508. // Sanitize and validate pmsg variable if set.
  509. if (isset($_GET['pmsg']))
  510. {
  511. $pmsg = (int) $_GET['pmsg'];
  512. if (!isAccessiblePM($pmsg, $context['folder'] == 'sent' ? 'outbox' : 'inbox'))
  513. fatal_lang_error('no_access', false);
  514. }
  515. // Set up the page index.
  516. $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']);
  517. $context['start'] = $_GET['start'];
  518. // Determine the navigation context (especially useful for the wireless template).
  519. $context['links'] = array(
  520. 'first' => $_GET['start'] >= $modSettings['defaultMaxMessages'] ? $scripturl . '?action=pm;start=0' : '',
  521. 'prev' => $_GET['start'] >= $modSettings['defaultMaxMessages'] ? $scripturl . '?action=pm;start=' . ($_GET['start'] - $modSettings['defaultMaxMessages']) : '',
  522. 'next' => $_GET['start'] + $modSettings['defaultMaxMessages'] < $max_messages ? $scripturl . '?action=pm;start=' . ($_GET['start'] + $modSettings['defaultMaxMessages']) : '',
  523. 'last' => $_GET['start'] + $modSettings['defaultMaxMessages'] < $max_messages ? $scripturl . '?action=pm;start=' . (floor(($max_messages - 1) / $modSettings['defaultMaxMessages']) * $modSettings['defaultMaxMessages']) : '',
  524. 'up' => $scripturl,
  525. );
  526. $context['page_info'] = array(
  527. 'current_page' => $_GET['start'] / $modSettings['defaultMaxMessages'] + 1,
  528. 'num_pages' => floor(($max_messages - 1) / $modSettings['defaultMaxMessages']) + 1
  529. );
  530. // First work out what messages we need to see - if grouped is a little trickier...
  531. if ($context['display_mode'] == 2)
  532. {
  533. // On a non-default sort due to PostgreSQL we have to do a harder sort.
  534. if ($smcFunc['db_title'] == 'PostgreSQL' && $_GET['sort'] != 'pm.id_pm')
  535. {
  536. $sub_request = $smcFunc['db_query']('', '
  537. SELECT MAX({raw:sort}) AS sort_param, pm.id_pm_head
  538. FROM {db_prefix}personal_messages AS pm' . ($context['folder'] == 'sent' ? ($context['sort_by'] == 'name' ? '
  539. LEFT JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm)' : '') : '
  540. INNER JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm
  541. AND pmr.id_member = {int:current_member}
  542. AND pmr.deleted = {int:not_deleted}
  543. ' . $labelQuery . ')') . ($context['sort_by'] == 'name' ? ( '
  544. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = {raw:id_member})') : '') . '
  545. WHERE ' . ($context['folder'] == 'sent' ? 'pm.id_member_from = {int:current_member}
  546. AND pm.deleted_by_sender = {int:not_deleted}' : '1=1') . (empty($pmsg) ? '' : '
  547. AND pm.id_pm = {int:id_pm}') . '
  548. GROUP BY pm.id_pm_head
  549. ORDER BY sort_param' . ($descending ? ' DESC' : ' ASC') . (empty($pmsg) ? '
  550. LIMIT ' . $_GET['start'] . ', ' . $modSettings['defaultMaxMessages'] : ''),
  551. array(
  552. 'current_member' => $user_info['id'],
  553. 'not_deleted' => 0,
  554. 'id_member' => $context['folder'] == 'sent' ? 'pmr.id_member' : 'pm.id_member_from',
  555. 'id_pm' => isset($pmsg) ? $pmsg : '0',
  556. 'sort' => $_GET['sort'],
  557. )
  558. );
  559. $sub_pms = array();
  560. while ($row = $smcFunc['db_fetch_assoc']($sub_request))
  561. $sub_pms[$row['id_pm_head']] = $row['sort_param'];
  562. $smcFunc['db_free_result']($sub_request);
  563. $request = $smcFunc['db_query']('', '
  564. SELECT pm.id_pm AS id_pm, pm.id_pm_head
  565. FROM {db_prefix}personal_messages AS pm' . ($context['folder'] == 'sent' ? ($context['sort_by'] == 'name' ? '
  566. LEFT JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm)' : '') : '
  567. INNER JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm
  568. AND pmr.id_member = {int:current_member}
  569. AND pmr.deleted = {int:not_deleted}
  570. ' . $labelQuery . ')') . ($context['sort_by'] == 'name' ? ( '
  571. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = {raw:id_member})') : '') . '
  572. WHERE ' . (empty($sub_pms) ? '0=1' : 'pm.id_pm IN ({array_int:pm_list})') . '
  573. ORDER BY ' . ($_GET['sort'] == 'pm.id_pm' && $context['folder'] != 'sent' ? 'id_pm' : '{raw:sort}') . ($descending ? ' DESC' : ' ASC') . (empty($pmsg) ? '
  574. LIMIT ' . $_GET['start'] . ', ' . $modSettings['defaultMaxMessages'] : ''),
  575. array(
  576. 'current_member' => $user_info['id'],
  577. 'pm_list' => array_keys($sub_pms),
  578. 'not_deleted' => 0,
  579. 'sort' => $_GET['sort'],
  580. 'id_member' => $context['folder'] == 'sent' ? 'pmr.id_member' : 'pm.id_member_from',
  581. )
  582. );
  583. }
  584. else
  585. {
  586. $request = $smcFunc['db_query']('pm_conversation_list', '
  587. SELECT MAX(pm.id_pm) AS id_pm, pm.id_pm_head
  588. FROM {db_prefix}personal_messages AS pm' . ($context['folder'] == 'sent' ? ($context['sort_by'] == 'name' ? '
  589. LEFT JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm)' : '') : '
  590. INNER JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm
  591. AND pmr.id_member = {int:current_member}
  592. AND pmr.deleted = {int:deleted_by}
  593. ' . $labelQuery . ')') . ($context['sort_by'] == 'name' ? ( '
  594. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = {raw:pm_member})') : '') . '
  595. WHERE ' . ($context['folder'] == 'sent' ? 'pm.id_member_from = {int:current_member}
  596. AND pm.deleted_by_sender = {int:deleted_by}' : '1=1') . (empty($pmsg) ? '' : '
  597. AND pm.id_pm = {int:pmsg}') . '
  598. GROUP BY pm.id_pm_head
  599. ORDER BY ' . ($_GET['sort'] == 'pm.id_pm' && $context['folder'] != 'sent' ? 'id_pm' : '{raw:sort}') . ($descending ? ' DESC' : ' ASC') . (empty($_GET['pmsg']) ? '
  600. LIMIT ' . $_GET['start'] . ', ' . $modSettings['defaultMaxMessages'] : ''),
  601. array(
  602. 'current_member' => $user_info['id'],
  603. 'deleted_by' => 0,
  604. 'sort' => $_GET['sort'],
  605. 'pm_member' => $context['folder'] == 'sent' ? 'pmr.id_member' : 'pm.id_member_from',
  606. 'pmsg' => isset($pmsg) ? (int) $pmsg : 0,
  607. )
  608. );
  609. }
  610. }
  611. // This is kinda simple!
  612. else
  613. {
  614. // !!!SLOW This query uses a filesort. (inbox only.)
  615. $request = $smcFunc['db_query']('', '
  616. SELECT pm.id_pm, pm.id_pm_head, pm.id_member_from
  617. FROM {db_prefix}personal_messages AS pm' . ($context['folder'] == 'sent' ? '' . ($context['sort_by'] == 'name' ? '
  618. LEFT JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm)' : '') : '
  619. INNER JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm
  620. AND pmr.id_member = {int:current_member}
  621. AND pmr.deleted = {int:is_deleted}
  622. ' . $labelQuery . ')') . ($context['sort_by'] == 'name' ? ( '
  623. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = {raw:pm_member})') : '') . '
  624. WHERE ' . ($context['folder'] == 'sent' ? 'pm.id_member_from = {raw:current_member}
  625. AND pm.deleted_by_sender = {int:is_deleted}' : '1=1') . (empty($pmsg) ? '' : '
  626. AND pm.id_pm = {int:pmsg}') . '
  627. ORDER BY ' . ($_GET['sort'] == 'pm.id_pm' && $context['folder'] != 'sent' ? 'pmr.id_pm' : '{raw:sort}') . ($descending ? ' DESC' : ' ASC') . (empty($pmsg) ? '
  628. LIMIT ' . $_GET['start'] . ', ' . $modSettings['defaultMaxMessages'] : ''),
  629. array(
  630. 'current_member' => $user_info['id'],
  631. 'is_deleted' => 0,
  632. 'sort' => $_GET['sort'],
  633. 'pm_member' => $context['folder'] == 'sent' ? 'pmr.id_member' : 'pm.id_member_from',
  634. 'pmsg' => isset($pmsg) ? (int) $pmsg : 0,
  635. )
  636. );
  637. }
  638. // Load the id_pms and initialize recipients.
  639. $pms = array();
  640. $lastData = array();
  641. $posters = $context['folder'] == 'sent' ? array($user_info['id']) : array();
  642. $recipients = array();
  643. while ($row = $smcFunc['db_fetch_assoc']($request))
  644. {
  645. if (!isset($recipients[$row['id_pm']]))
  646. {
  647. if (isset($row['id_member_from']))
  648. $posters[$row['id_pm']] = $row['id_member_from'];
  649. $pms[$row['id_pm']] = $row['id_pm'];
  650. $recipients[$row['id_pm']] = array(
  651. 'to' => array(),
  652. 'bcc' => array()
  653. );
  654. }
  655. // Keep track of the last message so we know what the head is without another query!
  656. if ((empty($pmID) && (empty($options['view_newest_pm_first']) || !isset($lastData))) || empty($lastData) || (!empty($pmID) && $pmID == $row['id_pm']))
  657. $lastData = array(
  658. 'id' => $row['id_pm'],
  659. 'head' => $row['id_pm_head'],
  660. );
  661. }
  662. $smcFunc['db_free_result']($request);
  663. // Make sure that we have been given a correct head pm id!
  664. if ($context['display_mode'] == 2 && !empty($pmID) && $pmID != $lastData['id'])
  665. fatal_lang_error('no_access', false);
  666. if (!empty($pms))
  667. {
  668. // Select the correct current message.
  669. if (empty($pmID))
  670. $context['current_pm'] = $lastData['id'];
  671. // This is a list of the pm's that are used for "full" display.
  672. if ($context['display_mode'] == 0)
  673. $display_pms = $pms;
  674. else
  675. $display_pms = array($context['current_pm']);
  676. // At this point we know the main id_pm's. But - if we are looking at conversations we need the others!
  677. if ($context['display_mode'] == 2)
  678. {
  679. $request = $smcFunc['db_query']('', '
  680. SELECT pm.id_pm, pm.id_member_from, pm.deleted_by_sender, pmr.id_member, pmr.deleted
  681. FROM {db_prefix}personal_messages AS pm
  682. INNER JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm)
  683. WHERE pm.id_pm_head = {int:id_pm_head}
  684. AND ((pm.id_member_from = {int:current_member} AND pm.deleted_by_sender = {int:not_deleted})
  685. OR (pmr.id_member = {int:current_member} AND pmr.deleted = {int:not_deleted}))
  686. ORDER BY pm.id_pm',
  687. array(
  688. 'current_member' => $user_info['id'],
  689. 'id_pm_head' => $lastData['head'],
  690. 'not_deleted' => 0,
  691. )
  692. );
  693. while ($row = $smcFunc['db_fetch_assoc']($request))
  694. {
  695. // This is, frankly, a joke. We will put in a workaround for people sending to themselves - yawn!
  696. if ($context['folder'] == 'sent' && $row['id_member_from'] == $user_info['id'] && $row['deleted_by_sender'] == 1)
  697. continue;
  698. elseif ($row['id_member'] == $user_info['id'] & $row['deleted'] == 1)
  699. continue;
  700. if (!isset($recipients[$row['id_pm']]))
  701. $recipients[$row['id_pm']] = array(
  702. 'to' => array(),
  703. 'bcc' => array()
  704. );
  705. $display_pms[] = $row['id_pm'];
  706. $posters[$row['id_pm']] = $row['id_member_from'];
  707. }
  708. $smcFunc['db_free_result']($request);
  709. }
  710. // This is pretty much EVERY pm!
  711. $all_pms = array_merge($pms, $display_pms);
  712. $all_pms = array_unique($all_pms);
  713. // Get recipients (don't include bcc-recipients for your inbox, you're not supposed to know :P).
  714. $request = $smcFunc['db_query']('', '
  715. 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
  716. FROM {db_prefix}pm_recipients AS pmr
  717. LEFT JOIN {db_prefix}members AS mem_to ON (mem_to.id_member = pmr.id_member)
  718. WHERE pmr.id_pm IN ({array_int:pm_list})',
  719. array(
  720. 'pm_list' => $all_pms,
  721. )
  722. );
  723. $context['message_labels'] = array();
  724. $context['message_replied'] = array();
  725. $context['message_unread'] = array();
  726. while ($row = $smcFunc['db_fetch_assoc']($request))
  727. {
  728. if ($context['folder'] == 'sent' || empty($row['bcc']))
  729. $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>';
  730. if ($row['id_member_to'] == $user_info['id'] && $context['folder'] != 'sent')
  731. {
  732. $context['message_replied'][$row['id_pm']] = $row['is_read'] & 2;
  733. $context['message_unread'][$row['id_pm']] = $row['is_read'] == 0;
  734. $row['labels'] = $row['labels'] == '' ? array() : explode(',', $row['labels']);
  735. foreach ($row['labels'] as $v)
  736. {
  737. if (isset($context['labels'][(int) $v]))
  738. $context['message_labels'][$row['id_pm']][(int) $v] = array('id' => $v, 'name' => $context['labels'][(int) $v]['name']);
  739. }
  740. }
  741. }
  742. $smcFunc['db_free_result']($request);
  743. // Make sure we don't load unnecessary data.
  744. if ($context['display_mode'] == 1)
  745. {
  746. foreach ($posters as $k => $v)
  747. if (!in_array($k, $display_pms))
  748. unset($posters[$k]);
  749. }
  750. // Load any users....
  751. $posters = array_unique($posters);
  752. if (!empty($posters))
  753. loadMemberData($posters);
  754. // If we're on grouped/restricted view get a restricted list of messages.
  755. if ($context['display_mode'] != 0)
  756. {
  757. // Get the order right.
  758. $orderBy = array();
  759. foreach (array_reverse($pms) as $pm)
  760. $orderBy[] = 'pm.id_pm = ' . $pm;
  761. // Seperate query for these bits!
  762. $subjects_request = $smcFunc['db_query']('', '
  763. SELECT pm.id_pm, pm.subject, pm.id_member_from, pm.msgtime, IFNULL(mem.real_name, pm.from_name) AS from_name,
  764. IFNULL(mem.id_member, 0) AS not_guest
  765. FROM {db_prefix}personal_messages AS pm
  766. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = pm.id_member_from)
  767. WHERE pm.id_pm IN ({array_int:pm_list})
  768. ORDER BY ' . implode(', ', $orderBy) . '
  769. LIMIT ' . count($pms),
  770. array(
  771. 'pm_list' => $pms,
  772. )
  773. );
  774. }
  775. // Execute the query!
  776. $messages_request = $smcFunc['db_query']('', '
  777. SELECT pm.id_pm, pm.subject, pm.id_member_from, pm.body, pm.msgtime, pm.from_name
  778. FROM {db_prefix}personal_messages AS pm' . ($context['folder'] == 'sent' ? '
  779. LEFT JOIN {db_prefix}pm_recipients AS pmr ON (pmr.id_pm = pm.id_pm)' : '') . ($context['sort_by'] == 'name' ? '
  780. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = {raw:id_member})' : '') . '
  781. WHERE pm.id_pm IN ({array_int:display_pms})' . ($context['folder'] == 'sent' ? '
  782. GROUP BY pm.id_pm, pm.subject, pm.id_member_from, pm.body, pm.msgtime, pm.from_name' : '') . '
  783. ORDER BY ' . ($context['display_mode'] == 2 ? 'pm.id_pm' : $_GET['sort']) . ($descending ? ' DESC' : ' ASC') . '
  784. LIMIT ' . count($display_pms),
  785. array(
  786. 'display_pms' => $display_pms,
  787. 'id_member' => $context['folder'] == 'sent' ? 'pmr.id_member' : 'pm.id_member_from',
  788. )
  789. );
  790. }
  791. else
  792. $messages_request = false;
  793. $context['can_send_pm'] = allowedTo('pm_send');
  794. if (!WIRELESS)
  795. $context['sub_template'] = 'folder';
  796. $context['page_title'] = $txt['pm_inbox'];
  797. // Finally mark the relevant messages as read.
  798. if ($context['folder'] != 'sent' && !empty($context['labels'][(int) $context['current_label_id']]['unread_messages']))
  799. {
  800. // If the display mode is "old sk00l" do them all...
  801. if ($context['display_mode'] == 0)
  802. markMessages(null, $context['current_label_id']);
  803. // Otherwise do just the current one!
  804. elseif (!empty($context['current_pm']))
  805. markMessages($display_pms, $context['current_label_id']);
  806. }
  807. }
  808. // Get a personal message for the theme. (used to save memory.)
  809. function prepareMessageContext($type = 'subject', $reset = false)
  810. {
  811. global $txt, $scripturl, $modSettings, $context, $messages_request, $memberContext, $recipients, $smcFunc;
  812. global $user_info, $subjects_request;
  813. // Count the current message number....
  814. static $counter = null;
  815. if ($counter === null || $reset)
  816. $counter = $context['start'];
  817. static $temp_pm_selected = null;
  818. if ($temp_pm_selected === null)
  819. {
  820. $temp_pm_selected = isset($_SESSION['pm_selected']) ? $_SESSION['pm_selected'] : array();
  821. $_SESSION['pm_selected'] = array();
  822. }
  823. // If we're in non-boring view do something exciting!
  824. if ($context['display_mode'] != 0 && $subjects_request && $type == 'subject')
  825. {
  826. $subject = $smcFunc['db_fetch_assoc']($subjects_request);
  827. if (!$subject)
  828. {
  829. $smcFunc['db_free_result']($subjects_request);
  830. return false;
  831. }
  832. $subject['subject'] = $subject['subject'] == '' ? $txt['no_subject'] : $subject['subject'];
  833. censorText($subject['subject']);
  834. $output = array(
  835. 'id' => $subject['id_pm'],
  836. 'member' => array(
  837. 'id' => $subject['id_member_from'],
  838. 'name' => $subject['from_name'],
  839. 'link' => $subject['not_guest'] ? '<a href="' . $scripturl . '?action=profile;u=' . $subject['id_member_from'] . '">' . $subject['from_name'] . '</a>' : $subject['from_name'],
  840. ),
  841. 'recipients' => &$recipients[$subject['id_pm']],
  842. 'subject' => $subject['subject'],
  843. 'time' => timeformat($subject['msgtime']),
  844. 'timestamp' => forum_time(true, $subject['msgtime']),
  845. 'number_recipients' => count($recipients[$subject['id_pm']]['to']),
  846. 'labels' => &$context['message_labels'][$subject['id_pm']],
  847. 'fully_labeled' => count($context['message_labels'][$subject['id_pm']]) == count($context['labels']),
  848. 'is_replied_to' => &$context['message_replied'][$subject['id_pm']],
  849. 'is_unread' => &$context['message_unread'][$subject['id_pm']],
  850. 'is_selected' => !empty($temp_pm_selected) && in_array($subject['id_pm'], $temp_pm_selected),
  851. );
  852. return $output;
  853. }
  854. // Bail if it's false, ie. no messages.
  855. if ($messages_request == false)
  856. return false;
  857. // Reset the data?
  858. if ($reset == true)
  859. return @$smcFunc['db_data_seek']($messages_request, 0);
  860. // Get the next one... bail if anything goes wrong.
  861. $message = $smcFunc['db_fetch_assoc']($messages_request);
  862. if (!$message)
  863. {
  864. if ($type != 'subject')
  865. $smcFunc['db_free_result']($messages_request);
  866. return false;
  867. }
  868. // Use '(no subject)' if none was specified.
  869. $message['subject'] = $message['subject'] == '' ? $txt['no_subject'] : $message['subject'];
  870. // Load the message's information - if it's not there, load the guest information.
  871. if (!loadMemberContext($message['id_member_from'], true))
  872. {
  873. $memberContext[$message['id_member_from']]['name'] = $message['from_name'];
  874. $memberContext[$message['id_member_from']]['id'] = 0;
  875. // Sometimes the forum sends messages itself (Warnings are an example) - in this case don't label it from a guest.
  876. $memberContext[$message['id_member_from']]['group'] = $message['from_name'] == $context['forum_name'] ? '' : $txt['guest_title'];
  877. $memberContext[$message['id_member_from']]['link'] = $message['from_name'];
  878. $memberContext[$message['id_member_from']]['email'] = '';
  879. $memberContext[$message['id_member_from']]['show_email'] = showEmailAddress(true, 0);
  880. $memberContext[$message['id_member_from']]['is_guest'] = true;
  881. }
  882. else
  883. {
  884. $memberContext[$message['id_member_from']]['can_view_profile'] = allowedTo('profile_view_any') || ($message['id_member_from'] == $user_info['id'] && allowedTo('profile_view_own'));
  885. $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'])));
  886. }
  887. // Censor all the important text...
  888. censorText($message['body']);
  889. censorText($message['subject']);
  890. // Run UBBC interpreter on the message.
  891. $message['body'] = parse_bbc($message['body'], true, 'pm' . $message['id_pm']);
  892. // Send the array.
  893. $output = array(
  894. 'alternate' => $counter % 2,
  895. 'id' => $message['id_pm'],
  896. 'member' => &$memberContext[$message['id_member_from']],
  897. 'subject' => $message['subject'],
  898. 'time' => timeformat($message['msgtime']),
  899. 'timestamp' => forum_time(true, $message['msgtime']),
  900. 'counter' => $counter,
  901. 'body' => $message['body'],
  902. 'recipients' => &$recipients[$message['id_pm']],
  903. 'number_recipients' => count($recipients[$message['id_pm']]['to']),
  904. 'labels' => &$context['message_labels'][$message['id_pm']],
  905. 'fully_labeled' => count($context['message_labels'][$message['id_pm']]) == count($context['labels']),
  906. 'is_replied_to' => &$context['message_replied'][$message['id_pm']],
  907. 'is_unread' => &$context['message_unread'][$message['id_pm']],
  908. 'is_selected' => !empty($temp_pm_selected) && in_array($message['id_pm'], $temp_pm_selected),
  909. );
  910. $counter++;
  911. return $output;
  912. }
  913. function MessageSearch()
  914. {
  915. global $context, $txt, $scripturl, $modSettings, $smcFunc;
  916. if (isset($_REQUEST['params']))
  917. {
  918. $temp_params = explode('|"|', base64_decode(strtr($_REQUEST['params'], array(' ' => '+'))));
  919. $context['search_params'] = array();
  920. foreach ($temp_params as $i => $data)
  921. {
  922. @list ($k, $v) = explode('|\'|', $data);
  923. $context['search_params'][$k] = $v;
  924. }
  925. }
  926. if (isset($_REQUEST['search']))
  927. $context['search_params']['search'] = un_htmlspecialchars($_REQUEST['search']);
  928. if (isset($context['search_params']['search']))
  929. $context['search_params']['search'] = htmlspecialchars($context['search_params']['search']);
  930. if (isset($context['search_params']['userspec']))
  931. $context['search_params']['userspec'] = htmlspecialchars($context['search_params']['userspec']);
  932. if (!empty($context['search_params']['searchtype']))
  933. $context['search_params']['searchtype'] = 2;
  934. if (!empty($context['search_params']['minage']))
  935. $context['search_params']['minage'] = (int) $context['search_params']['minage'];
  936. if (!empty($context['search_params']['maxage']))
  937. $context['search_params']['maxage'] = (int) $context['search_params']['maxage'];
  938. $context['search_params']['subject_only'] = !empty($context['search_params']['subject_only']);
  939. $context['search_params']['show_complete'] = !empty($context['search_params']['show_complete']);
  940. // Create the array of labels to be searched.
  941. $context['search_labels'] = array();
  942. $searchedLabels = isset($context['search_params']['labels']) && $context['search_params']['labels'] != '' ? explode(',', $context['search_params']['labels']) : array();
  943. foreach ($context['labels'] as $label)
  944. {
  945. $context['search_labels'][] = array(
  946. 'id' => $label['id'],
  947. 'name' => $label['name'],
  948. 'checked' => !empty($searchedLabels) ? in_array($label['id'], $searchedLabels) : true,
  949. );
  950. }
  951. // Are all the labels checked?
  952. $context['check_all'] = empty($searchedLabels) || count($context['search_labels']) == count($searchedLabels);
  953. // Load the error text strings if there were errors in the search.
  954. if (!empty($context['search_errors']))
  955. {
  956. loadLanguage('Errors');
  957. $context['search_errors']['messages'] = array();
  958. foreach ($context['search_errors'] as $search_error => $dummy)
  959. {
  960. if ($search_error == 'messages')
  961. continue;
  962. $context['search_errors']['messages'][] = $txt['error_' . $search_error];
  963. }
  964. }
  965. $context['simple_search'] = isset($context['search_params']['advanced']) ? empty($context['search_params']['advanced']) : !empty($modSettings['simpleSearch']) && !isset($_REQUEST['advanced']);
  966. $context['page_title'] = $txt['pm_search_title'];
  967. $context['sub_template'] = 'search';
  968. $context['linktree'][] = array(
  969. 'url' => $scripturl . '?action=pm;sa=search',
  970. 'name' => $txt['pm_search_bar_title'],
  971. );
  972. }
  973. function MessageSearch2()
  974. {
  975. global $scripturl, $modSettings, $user_info, $context, $txt;
  976. global $memberContext, $smcFunc;
  977. if (!empty($context['load_average']) && !empty($modSettings['loadavg_search']) && $context['load_average'] >= $modSettings['loadavg_search'])
  978. fatal_lang_error('loadavg_search_disabled', false);
  979. // !!! For the moment force the folder to the inbox.
  980. $context['folder'] = 'inbox';
  981. // Some useful general permissions.
  982. $context['can_send_pm'] = allowedTo('pm_send');
  983. // Some hardcoded veriables that can be tweaked if required.
  984. $maxMembersToSearch = 500;
  985. // Extract all the search parameters.
  986. $search_params = array();
  987. if (isset($_REQUEST['params']))
  988. {
  989. $temp_params = explode('|"|', base64_decode(strtr($_REQUEST['params'], array(' ' => '+'))));
  990. foreach ($temp_params as $i => $data)
  991. {
  992. @list ($k, $v) = explode('|\'|', $data);
  993. $search_params[$k] = $v;
  994. }
  995. }
  996. $context['start'] = isset($_GET['start']) ? (int) $_GET['start'] : 0;
  997. // Store whether simple search was used (needed if the user wants to do another query).
  998. if (!isset($search_params['advanced']))
  999. $search_params['advanced'] = empty($_REQUEST['advanced']) ? 0 : 1;
  1000. // 1 => 'allwords' (default, don't set as param) / 2 => 'anywords'.
  1001. if (!empty($search_params['searchtype']) || (!empty($_REQUEST['searchtype']) && $_REQUEST['searchtype'] == 2))
  1002. $search_params['searchtype'] = 2;
  1003. // Minimum age of messages. Default to zero (don't set param in that case).
  1004. if (!empty($search_params['minage']) || (!empty($_REQUEST['minage']) && $_REQUEST['minage'] > 0))
  1005. $search_params['minage'] = !empty($search_params['minage']) ? (int) $search_params['minage'] : (int) $_REQUEST['minage'];
  1006. // Maximum age of messages. Default to infinite (9999 days: param not set).
  1007. if (!empty($search_params['maxage']) || (!empty($_REQUEST['maxage']) && $_REQUEST['maxage'] != 9999))
  1008. $search_params['maxage'] = !empty($search_params['maxage']) ? (int) $search_params['maxage'] : (int) $_REQUEST['maxage'];
  1009. $search_params['subject_only'] = !empty($search_params['subject_only']) || !empty($_REQUEST['subject_only']);
  1010. $search_params['show_complete'] = !empty($search_params['show_complete']) || !empty($_REQUEST['show_complete']);
  1011. // Default the user name to a wildcard matching every user (*).
  1012. if (!empty($search_params['user_spec']) || (!empty($_REQUEST['userspec']) && $_REQUEST['userspec'] != '*'))
  1013. $search_params['userspec'] = isset($search_params['userspec']) ? $search_params['userspec'] : $_REQUEST['userspec'];
  1014. // This will be full of all kinds of parameters!
  1015. $searchq_parameters = array();
  1016. // If there's no specific user, then don't mention it in the main query.
  1017. if (empty($search_params['userspec']))
  1018. $userQuery = '';
  1019. else
  1020. {
  1021. $userString = strtr($smcFunc['htmlspecialchars']($search_params['userspec'], ENT_QUOTES), array('&quot;' => '"'));
  1022. $userString = strtr($userString, array('%' => '\%', '_' => '\_', '*' => '%', '?' => '_'));
  1023. preg_match_all('~"([^"]+)"~', $userString, $matches);
  1024. $possible_users = array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $userString)));
  1025. for ($k = 0, $n = count($possible_users); $k < $n; $k++)
  1026. {
  1027. $possible_users[$k] = trim($possible_users[$k]);
  1028. if (strlen($possible_users[$k]) == 0)
  1029. unset($possible_users[$k]);
  1030. }
  1031. // Who matches those criteria?
  1032. // !!! This doesn't support sent item searching.
  1033. $request = $smcFunc['db_query']('', '
  1034. SELECT id_member
  1035. FROM {db_prefix}members
  1036. WHERE real_name LIKE {raw:real_name_implode}',
  1037. array(
  1038. 'real_name_implode' => '\'' . implode('\' OR real_name LIKE \'', $possible_users) . '\'',
  1039. )
  1040. );
  1041. // Simply do nothing if there're too many members matching the criteria.
  1042. if ($smcFunc['db_num_rows']($request) > $maxMembersToSearch)
  1043. $userQuery = '';
  1044. elseif ($smcFunc['db_num_rows']($request) == 0)
  1045. {
  1046. $userQuery = 'AND pm.id_member_from = 0 AND (pm.from_name LIKE {raw:guest_user_name_implode})';
  1047. $searchq_parameters['guest_user_name_implode'] = '\'' . implode('\' OR pm.from_name LIKE \'', $possible_users) . '\'';
  1048. }
  1049. else
  1050. {
  1051. $memberlist = array();
  1052. while ($row = $smcFunc['db_fetch_assoc']($request))
  1053. $memberlist[] = $row['id_member'];
  1054. $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})))';
  1055. $searchq_parameters['guest_user_name_implode'] = '\'' . implode('\' OR pm.from_name LIKE \'', $possible_users) . '\'';
  1056. $searchq_parameters['member_list'] = $memberlist;
  1057. }
  1058. $smcFunc['db_free_result']($request);
  1059. }
  1060. // Setup the sorting variables...
  1061. // !!! Add more in here!
  1062. $sort_columns = array(
  1063. 'pm.id_pm',
  1064. );
  1065. if (empty($search_params['sort']) && !empty($_REQUEST['sort']))
  1066. list ($search_params['sort'], $search_params['sort_dir']) = array_pad(explode('|', $_REQUEST['sort']), 2, '');
  1067. $search_params['sort'] = !empty($search_params['sort']) && in_array($search_params['sort'], $sort_columns) ? $search_params['sort'] : 'pm.id_pm';
  1068. $search_params['sort_dir'] = !empty($search_params['sort_dir']) && $search_params['sort_dir'] == 'asc' ? 'asc' : 'desc';
  1069. // Sort out any labels we may be searching by.
  1070. $labelQuery = '';
  1071. if ($context['folder'] == 'inbox' && !empty($search_params['advanced']) && $context['currently_using_labels'])
  1072. {
  1073. // Came here from pagination? Put them back into $_REQUEST for sanitization.
  1074. if (isset($search_params['labels']))
  1075. $_REQUEST['searchlabel'] = explode(',', $search_params['labels']);
  1076. // Assuming we have some labels - make them all integers.
  1077. if (!empty($_REQUEST['searchlabel']) && is_array($_REQUEST['searchlabel']))
  1078. {
  1079. foreach ($_REQUEST['searchlabel'] as $key => $id)
  1080. $_REQUEST['searchlabel'][$key] = (int) $id;
  1081. }
  1082. else
  1083. $_REQUEST['searchlabel'] = array();
  1084. // Now that everything is cleaned up a bit, make the labels a param.
  1085. $search_params['labels'] = implode(',', $_REQUEST['searchlabel']);
  1086. // No labels selected? That must be an error!
  1087. if (empty($_REQUEST['searchlabel']))
  1088. $context['search_errors']['no_labels_selected'] = true;
  1089. // Otherwise prepare the query!
  1090. elseif (count($_REQUEST['searchlabel']) != count($context['labels']))
  1091. {
  1092. $labelQuery = '
  1093. AND {raw:label_implode}';
  1094. $labelStatements = array();
  1095. foreach ($_REQUEST['searchlabel'] as $label)
  1096. $labelStatements[] = $smcFunc['db_quote']('FIND_IN_SET({string:label}, pmr.labels) != 0', array(
  1097. 'label' => $label,
  1098. ));
  1099. $searchq_parameters['label_implode'] = '(' . implode(' OR ', $labelStatements) . ')';
  1100. }
  1101. }
  1102. // What are we actually searching for?
  1103. $search_params['search'] = !empty($search_params['search']) ? $search_params['search'] : (isset($_REQUEST['search']) ? $_REQUEST['search'] : '');
  1104. // If we ain't got nothing - we should error!
  1105. if (!isset($search_params['search']) || $search_params['search'] == '')
  1106. $context['search_errors']['invalid_search_string'] = true;
  1107. // Extract phrase parts first (e.g. some words "this is a phrase" some more words.)
  1108. preg_match_all('~(?:^|\s)([-]?)"([^"]+)"(?:$|\s)~' . ($context['utf8'] ? 'u' : ''), $search_params['search'], $matches, PREG_PATTERN_ORDER);
  1109. $searchArray = $matches[2];
  1110. // Remove the phrase parts and extract the words.
  1111. $tempSearch = explode(' ', preg_replace('~(?:^|\s)(?:[-]?)"(?:[^"]+)"(?:$|\s)~' . ($context['utf8'] ? 'u' : ''), ' ', $search_params['search']));
  1112. // A minus sign in front of a word excludes the word.... so...
  1113. $excludedWords = array();
  1114. // .. first, we check for things like -"some words", but not "-some words".
  1115. foreach ($matches[1] as $index => $word)
  1116. if ($word == '-')
  1117. {
  1118. $word = $smcFunc['strtolower'](trim($searchArray[$index]));
  1119. if (strlen($word) > 0)
  1120. $excludedWords[] = $word;
  1121. unset($searchArray[$index]);
  1122. }
  1123. // Now we look for -test, etc.... normaller.
  1124. foreach ($tempSearch as $index => $word)
  1125. if (strpos(trim($word), '-') === 0)
  1126. {
  1127. $word = substr($smcFunc['strtolower'](trim($word)), 1);
  1128. if (strlen($word) > 0)
  1129. $excludedWords[] = $word;
  1130. unset($tempSearch[$index]);
  1131. }
  1132. $searchArray = array_merge($searchArray, $tempSearch);
  1133. // Trim everything and make sure there are no words that are the same.
  1134. foreach ($searchArray as $index => $value)
  1135. {
  1136. $searchArray[$index] = $smcFunc['strtolower'](trim($value));
  1137. if ($searchArray[$index] == '')
  1138. unset($searchArray[$index]);
  1139. else
  1140. {
  1141. // Sort out entities first.
  1142. $searchArray[$index] = $smcFunc['htmlspecialchars']($searchArray[$index]);
  1143. }

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