Update code_sniffer build.xml file to be executable on our system
[phpbb.git] / phpBB / includes / functions_privmsgs.php
blob90060519db068fc5928202dc61c896bcb75ffffc
1 <?php
2 /**
4 * @package phpBB3
5 * @version $Id$
6 * @copyright (c) 2005 phpBB Group
7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
9 */
11 /**
13 if (!defined('IN_PHPBB'))
15 exit;
19 Ability to simply add own rules by doing three things:
20 1) Add an appropriate constant
21 2) Add a new check array to the global_privmsgs_rules variable and the condition array (if one is required)
22 3) Add a new language variable to ucp.php
24 The user is then able to select the new rule. It will be checked against and handled as specified.
25 To add new actions (yes, checks can be added here too) to the rule management, the core code has to be modified.
28 define('RULE_IS_LIKE', 1); // Is Like
29 define('RULE_IS_NOT_LIKE', 2); // Is Not Like
30 define('RULE_IS', 3); // Is
31 define('RULE_IS_NOT', 4); // Is Not
32 define('RULE_BEGINS_WITH', 5); // Begins with
33 define('RULE_ENDS_WITH', 6); // Ends with
34 define('RULE_IS_FRIEND', 7); // Is Friend
35 define('RULE_IS_FOE', 8); // Is Foe
36 define('RULE_IS_USER', 9); // Is User
37 define('RULE_IS_GROUP', 10); // Is In Usergroup
38 define('RULE_ANSWERED', 11); // Answered
39 define('RULE_FORWARDED', 12); // Forwarded
40 define('RULE_TO_GROUP', 14); // Usergroup
41 define('RULE_TO_ME', 15); // Me
43 define('ACTION_PLACE_INTO_FOLDER', 1);
44 define('ACTION_MARK_AS_READ', 2);
45 define('ACTION_MARK_AS_IMPORTANT', 3);
46 define('ACTION_DELETE_MESSAGE', 4);
48 define('CHECK_SUBJECT', 1);
49 define('CHECK_SENDER', 2);
50 define('CHECK_MESSAGE', 3);
51 define('CHECK_STATUS', 4);
52 define('CHECK_TO', 5);
54 /**
55 * Global private message rules
56 * These rules define what to do if a rule is hit
58 $global_privmsgs_rules = array(
59 CHECK_SUBJECT => array(
60 RULE_IS_LIKE => array('check0' => 'message_subject', 'function' => 'preg_match("/" . preg_quote({STRING}, "/") . "/i", {CHECK0})'),
61 RULE_IS_NOT_LIKE => array('check0' => 'message_subject', 'function' => '!(preg_match("/" . preg_quote({STRING}, "/") . "/i", {CHECK0}))'),
62 RULE_IS => array('check0' => 'message_subject', 'function' => '{CHECK0} == {STRING}'),
63 RULE_IS_NOT => array('check0' => 'message_subject', 'function' => '{CHECK0} != {STRING}'),
64 RULE_BEGINS_WITH => array('check0' => 'message_subject', 'function' => 'preg_match("/^" . preg_quote({STRING}, "/") . "/i", {CHECK0})'),
65 RULE_ENDS_WITH => array('check0' => 'message_subject', 'function' => 'preg_match("/" . preg_quote({STRING}, "/") . "$/i", {CHECK0})'),
68 CHECK_SENDER => array(
69 RULE_IS_LIKE => array('check0' => 'username', 'function' => 'preg_match("/" . preg_quote({STRING}, "/") . "/i", {CHECK0})'),
70 RULE_IS_NOT_LIKE => array('check0' => 'username', 'function' => '!(preg_match("/" . preg_quote({STRING}, "/") . "/i", {CHECK0}))'),
71 RULE_IS => array('check0' => 'username', 'function' => '{CHECK0} == {STRING}'),
72 RULE_IS_NOT => array('check0' => 'username', 'function' => '{CHECK0} != {STRING}'),
73 RULE_BEGINS_WITH => array('check0' => 'username', 'function' => 'preg_match("/^" . preg_quote({STRING}, "/") . "/i", {CHECK0})'),
74 RULE_ENDS_WITH => array('check0' => 'username', 'function' => 'preg_match("/" . preg_quote({STRING}, "/") . "$/i", {CHECK0})'),
75 RULE_IS_FRIEND => array('check0' => 'friend', 'function' => '{CHECK0} == 1'),
76 RULE_IS_FOE => array('check0' => 'foe', 'function' => '{CHECK0} == 1'),
77 RULE_IS_USER => array('check0' => 'author_id', 'function' => '{CHECK0} == {USER_ID}'),
78 RULE_IS_GROUP => array('check0' => 'author_in_group', 'function' => 'in_array({GROUP_ID}, {CHECK0})'),
81 CHECK_MESSAGE => array(
82 RULE_IS_LIKE => array('check0' => 'message_text', 'function' => 'preg_match("/" . preg_quote({STRING}, "/") . "/i", {CHECK0})'),
83 RULE_IS_NOT_LIKE => array('check0' => 'message_text', 'function' => '!(preg_match("/" . preg_quote({STRING}, "/") . "/i", {CHECK0}))'),
84 RULE_IS => array('check0' => 'message_text', 'function' => '{CHECK0} == {STRING}'),
85 RULE_IS_NOT => array('check0' => 'message_text', 'function' => '{CHECK0} != {STRING}'),
88 CHECK_STATUS => array(
89 RULE_ANSWERED => array('check0' => 'pm_replied', 'function' => '{CHECK0} == 1'),
90 RULE_FORWARDED => array('check0' => 'pm_forwarded', 'function' => '{CHECK0} == 1'),
93 CHECK_TO => array(
94 RULE_TO_GROUP => array('check0' => 'to', 'check1' => 'bcc', 'check2' => 'user_in_group', 'function' => 'in_array("g_" . {CHECK2}, {CHECK0}) || in_array("g_" . {CHECK2}, {CHECK1})'),
95 RULE_TO_ME => array('check0' => 'to', 'check1' => 'bcc', 'function' => 'in_array("u_" . $user_id, {CHECK0}) || in_array("u_" . $user_id, {CHECK1})'),
99 /**
100 * This is for defining which condition fields to show for which Rule
102 $global_rule_conditions = array(
103 RULE_IS_LIKE => 'text',
104 RULE_IS_NOT_LIKE => 'text',
105 RULE_IS => 'text',
106 RULE_IS_NOT => 'text',
107 RULE_BEGINS_WITH => 'text',
108 RULE_ENDS_WITH => 'text',
109 RULE_IS_USER => 'user',
110 RULE_IS_GROUP => 'group'
114 * Get all folder
116 function get_folder($user_id, $folder_id = false)
118 $folder = array();
120 // Get folder information
121 $sql = 'SELECT folder_id, COUNT(msg_id) as num_messages, SUM(pm_unread) as num_unread
122 FROM ' . PRIVMSGS_TO_TABLE . "
123 WHERE user_id = $user_id
124 AND folder_id <> " . PRIVMSGS_NO_BOX . '
125 GROUP BY folder_id';
126 $result = phpbb::$db->sql_query($sql);
128 $num_messages = $num_unread = array();
129 while ($row = phpbb::$db->sql_fetchrow($result))
131 $num_messages[(int) $row['folder_id']] = $row['num_messages'];
132 $num_unread[(int) $row['folder_id']] = $row['num_unread'];
134 phpbb::$db->sql_freeresult($result);
136 // Make sure the default boxes are defined
137 $available_folder = array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX);
139 foreach ($available_folder as $default_folder)
141 if (!isset($num_messages[$default_folder]))
143 $num_messages[$default_folder] = 0;
146 if (!isset($num_unread[$default_folder]))
148 $num_unread[$default_folder] = 0;
152 // Adjust unread status for outbox
153 $num_unread[PRIVMSGS_OUTBOX] = $num_messages[PRIVMSGS_OUTBOX];
155 $folder[PRIVMSGS_INBOX] = array(
156 'folder_name' => phpbb::$user->lang['PM_INBOX'],
157 'num_messages' => $num_messages[PRIVMSGS_INBOX],
158 'unread_messages' => $num_unread[PRIVMSGS_INBOX]
161 // Custom Folder
162 $sql = 'SELECT folder_id, folder_name, pm_count
163 FROM ' . PRIVMSGS_FOLDER_TABLE . "
164 WHERE user_id = $user_id";
165 $result = phpbb::$db->sql_query($sql);
167 while ($row = phpbb::$db->sql_fetchrow($result))
169 $folder[$row['folder_id']] = array(
170 'folder_name' => $row['folder_name'],
171 'num_messages' => $row['pm_count'],
172 'unread_messages' => ((isset($num_unread[$row['folder_id']])) ? $num_unread[$row['folder_id']] : 0)
175 phpbb::$db->sql_freeresult($result);
177 $folder[PRIVMSGS_OUTBOX] = array(
178 'folder_name' => phpbb::$user->lang['PM_OUTBOX'],
179 'num_messages' => $num_messages[PRIVMSGS_OUTBOX],
180 'unread_messages' => $num_unread[PRIVMSGS_OUTBOX]
183 $folder[PRIVMSGS_SENTBOX] = array(
184 'folder_name' => phpbb::$user->lang['PM_SENTBOX'],
185 'num_messages' => $num_messages[PRIVMSGS_SENTBOX],
186 'unread_messages' => $num_unread[PRIVMSGS_SENTBOX]
189 // Define Folder Array for template designers (and for making custom folders usable by the template too)
190 foreach ($folder as $f_id => $folder_ary)
192 $folder_id_name = ($f_id == PRIVMSGS_INBOX) ? 'inbox' : (($f_id == PRIVMSGS_OUTBOX) ? 'outbox' : 'sentbox');
194 phpbb::$template->assign_block_vars('folder', array(
195 'FOLDER_ID' => $f_id,
196 'FOLDER_NAME' => $folder_ary['folder_name'],
197 'NUM_MESSAGES' => $folder_ary['num_messages'],
198 'UNREAD_MESSAGES' => $folder_ary['unread_messages'],
200 'U_FOLDER' => ($f_id > 0) ? append_sid('ucp', 'i=pm&amp;folder=' . $f_id) : append_sid('ucp', 'i=pm&amp;folder=' . $folder_id_name),
202 'S_CUR_FOLDER' => ($f_id === $folder_id) ? true : false,
203 'S_UNREAD_MESSAGES' => ($folder_ary['unread_messages']) ? true : false,
204 'S_CUSTOM_FOLDER' => ($f_id > 0) ? true : false,
208 if ($folder_id !== false && !isset($folder[$folder_id]))
210 trigger_error('UNKNOWN_FOLDER');
213 return $folder;
217 * Delete Messages From Sentbox
218 * we are doing this here because this saves us a bunch of checks and queries
220 function clean_sentbox($num_sentbox_messages)
222 // Check Message Limit
223 if (phpbb::$user->data['message_limit'] && $num_sentbox_messages > phpbb::$user->data['message_limit'])
225 // Delete old messages
226 $sql = 'SELECT t.msg_id
227 FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p
228 WHERE t.msg_id = p.msg_id
229 AND t.user_id = ' . phpbb::$user->data['user_id'] . '
230 AND t.folder_id = ' . PRIVMSGS_SENTBOX . '
231 ORDER BY p.message_time ASC';
232 $result = phpbb::$db->sql_query_limit($sql, ($num_sentbox_messages - phpbb::$user->data['message_limit']));
234 $delete_ids = array();
235 while ($row = phpbb::$db->sql_fetchrow($result))
237 $delete_ids[] = $row['msg_id'];
239 phpbb::$db->sql_freeresult($result);
240 delete_pm(phpbb::$user->data['user_id'], $delete_ids, PRIVMSGS_SENTBOX);
245 * Check Rule against Message Information
247 function check_rule(&$rules, &$rule_row, &$message_row, $user_id)
249 if (!isset($rules[$rule_row['rule_check']][$rule_row['rule_connection']]))
251 return false;
254 $check_ary = $rules[$rule_row['rule_check']][$rule_row['rule_connection']];
256 // Replace Check Literals
257 $evaluate = $check_ary['function'];
258 $evaluate = preg_replace('/{(CHECK[0-9])}/', '$message_row[$check_ary[strtolower("\1")]]', $evaluate);
260 // Replace Rule Literals
261 $evaluate = preg_replace('/{(STRING|USER_ID|GROUP_ID)}/', '$rule_row["rule_" . strtolower("\1")]', $evaluate);
263 // Evil Statement
264 $result = false;
265 eval('$result = (' . $evaluate . ') ? true : false;');
267 if (!$result)
269 return false;
272 switch ($rule_row['rule_action'])
274 case ACTION_PLACE_INTO_FOLDER:
275 return array('action' => $rule_row['rule_action'], 'folder_id' => $rule_row['rule_folder_id']);
276 break;
278 case ACTION_MARK_AS_READ:
279 case ACTION_MARK_AS_IMPORTANT:
280 return array('action' => $rule_row['rule_action'], 'pm_unread' => $message_row['pm_unread'], 'pm_marked' => $message_row['pm_marked']);
281 break;
283 case ACTION_DELETE_MESSAGE:
284 // Check for admins/mods - users are not allowed to remove those messages...
285 // We do the check here to make sure the data we use is consistent
286 $sql = 'SELECT user_id, user_type, user_permissions
287 FROM ' . USERS_TABLE . '
288 WHERE user_id = ' . (int) $message_row['author_id'];
289 $result = phpbb::$db->sql_query($sql);
290 $userdata = phpbb::$db->sql_fetchrow($result);
291 phpbb::$db->sql_freeresult($result);
293 $auth2 = new auth();
294 $auth2->acl($userdata);
296 if (!$auth2->acl_get('a_') && !$auth2->acl_get('m_') && !$auth2->acl_getf_global('m_'))
298 return array('action' => $rule_row['rule_action'], 'pm_unread' => $message_row['pm_unread'], 'pm_marked' => $message_row['pm_marked']);
301 return false;
302 break;
304 default:
305 return false;
308 return false;
312 * Update user PM count
314 function update_pm_counts()
316 // Update unread count
317 $sql = 'SELECT COUNT(msg_id) as num_messages
318 FROM ' . PRIVMSGS_TO_TABLE . '
319 WHERE pm_unread = 1
320 AND folder_id <> ' . PRIVMSGS_OUTBOX . '
321 AND user_id = ' . phpbb::$user->data['user_id'];
322 $result = phpbb::$db->sql_query($sql);
323 phpbb::$user->data['user_unread_privmsg'] = (int) phpbb::$db->sql_fetchfield('num_messages');
324 phpbb::$db->sql_freeresult($result);
326 // Update new pm count
327 $sql = 'SELECT COUNT(msg_id) as num_messages
328 FROM ' . PRIVMSGS_TO_TABLE . '
329 WHERE pm_new = 1
330 AND folder_id IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
331 AND user_id = ' . phpbb::$user->data['user_id'];
332 $result = phpbb::$db->sql_query($sql);
333 phpbb::$user->data['user_new_privmsg'] = (int) phpbb::$db->sql_fetchfield('num_messages');
334 phpbb::$db->sql_freeresult($result);
336 phpbb::$db->sql_query('UPDATE ' . USERS_TABLE . ' SET ' . phpbb::$db->sql_build_array('UPDATE', array(
337 'user_unread_privmsg' => (int) phpbb::$user->data['user_unread_privmsg'],
338 'user_new_privmsg' => (int) phpbb::$user->data['user_new_privmsg'],
339 )) . ' WHERE user_id = ' . phpbb::$user->data['user_id']);
341 // Ok, here we need to repair something, other boxes than privmsgs_no_box and privmsgs_hold_box should not carry the pm_new flag.
342 if (!phpbb::$user->data['user_new_privmsg'])
344 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
345 SET pm_new = 0
346 WHERE pm_new = 1
347 AND folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
348 AND user_id = ' . phpbb::$user->data['user_id'];
349 phpbb::$db->sql_query($sql);
354 * Place new messages into appropriate folder
356 function place_pm_into_folder(&$global_privmsgs_rules, $release = false)
358 if (!phpbb::$user->data['user_new_privmsg'])
360 return array('not_moved' => 0, 'removed' => 0);
363 $user_message_rules = (int) phpbb::$user->data['user_message_rules'];
364 $user_id = (int) phpbb::$user->data['user_id'];
366 $action_ary = $move_into_folder = array();
367 $num_removed = 0;
369 // Newly processing on-hold messages
370 if ($release)
372 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
373 SET folder_id = ' . PRIVMSGS_NO_BOX . '
374 WHERE folder_id = ' . PRIVMSGS_HOLD_BOX . "
375 AND user_id = $user_id";
376 phpbb::$db->sql_query($sql);
379 // Get those messages not yet placed into any box
380 $retrieve_sql = 'SELECT t.*, p.*, u.username, u.user_id, u.group_id
381 FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p, ' . USERS_TABLE . " u
382 WHERE t.user_id = $user_id
383 AND p.author_id = u.user_id
384 AND t.folder_id = " . PRIVMSGS_NO_BOX . '
385 AND t.msg_id = p.msg_id';
387 // Just place into the appropriate arrays if no rules need to be checked
388 if (!$user_message_rules)
390 $result = phpbb::$db->sql_query($retrieve_sql);
392 while ($row = phpbb::$db->sql_fetchrow($result))
394 $action_ary[$row['msg_id']][] = array('action' => false);
396 phpbb::$db->sql_freeresult($result);
398 else
400 $user_rules = $zebra = $check_rows = array();
401 $user_ids = $memberships = array();
403 // First of all, grab all rules and retrieve friends/foes
404 $sql = 'SELECT *
405 FROM ' . PRIVMSGS_RULES_TABLE . "
406 WHERE user_id = $user_id";
407 $result = phpbb::$db->sql_query($sql);
408 $user_rules = phpbb::$db->sql_fetchrowset($result);
409 phpbb::$db->sql_freeresult($result);
411 if (sizeof($user_rules))
413 $sql = 'SELECT zebra_id, friend, foe
414 FROM ' . ZEBRA_TABLE . "
415 WHERE user_id = $user_id";
416 $result = phpbb::$db->sql_query($sql);
418 while ($row = phpbb::$db->sql_fetchrow($result))
420 $zebra[$row['zebra_id']] = $row;
422 phpbb::$db->sql_freeresult($result);
425 // Now build a bare-bone check_row array
426 $result = phpbb::$db->sql_query($retrieve_sql);
428 while ($row = phpbb::$db->sql_fetchrow($result))
430 $check_rows[] = array_merge($row, array(
431 'to' => explode(':', $row['to_address']),
432 'bcc' => explode(':', $row['bcc_address']),
433 'friend' => (isset($zebra[$row['author_id']])) ? $zebra[$row['author_id']]['friend'] : 0,
434 'foe' => (isset($zebra[$row['author_id']])) ? $zebra[$row['author_id']]['foe'] : 0,
435 'user_in_group' => array(phpbb::$user->data['group_id']),
436 'author_in_group' => array())
439 $user_ids[] = $row['user_id'];
441 phpbb::$db->sql_freeresult($result);
443 // Retrieve user memberships
444 if (sizeof($user_ids))
446 $sql = 'SELECT *
447 FROM ' . USER_GROUP_TABLE . '
448 WHERE ' . phpbb::$db->sql_in_set('user_id', $user_ids) . '
449 AND user_pending = 0';
450 $result = phpbb::$db->sql_query($sql);
452 while ($row = phpbb::$db->sql_fetchrow($result))
454 $memberships[$row['user_id']][] = $row['group_id'];
456 phpbb::$db->sql_freeresult($result);
459 // Now place into the appropriate folder
460 foreach ($check_rows as $row)
462 // Add membership if set
463 if (isset($memberships[$row['author_id']]))
465 $row['author_in_group'] = $memberships[$row['user_id']];
468 // Check Rule - this should be very quick since we have all information we need
469 $is_match = false;
470 foreach ($user_rules as $rule_row)
472 if (($action = check_rule($global_privmsgs_rules, $rule_row, $row, $user_id)) !== false)
474 $is_match = true;
475 $action_ary[$row['msg_id']][] = $action;
479 if (!$is_match)
481 $action_ary[$row['msg_id']][] = array('action' => false);
485 unset($user_rules, $zebra, $check_rows, $user_ids, $memberships);
488 // We place actions into arrays, to save queries.
489 $sql = $unread_ids = $delete_ids = $important_ids = array();
491 foreach ($action_ary as $msg_id => $msg_ary)
493 // It is allowed to execute actions more than once, except placing messages into folder
494 $folder_action = $message_removed = false;
496 foreach ($msg_ary as $pos => $rule_ary)
498 if ($folder_action && $rule_ary['action'] == ACTION_PLACE_INTO_FOLDER)
500 continue;
503 switch ($rule_ary['action'])
505 case ACTION_PLACE_INTO_FOLDER:
506 // Folder actions have precedence, so we will remove any other ones
507 $folder_action = true;
508 $move_into_folder[(int) $rule_ary['folder_id']][] = $msg_id;
509 break;
511 case ACTION_MARK_AS_READ:
512 if ($rule_ary['pm_unread'])
514 $unread_ids[] = $msg_id;
516 break;
518 case ACTION_DELETE_MESSAGE:
519 $delete_ids[] = $msg_id;
520 $message_removed = true;
521 break;
523 case ACTION_MARK_AS_IMPORTANT:
524 if (!$rule_ary['pm_marked'])
526 $important_ids[] = $msg_id;
528 break;
532 // We place this here because it could happen that the messages are doubled if a rule marks a message and then moves it into a specific
533 // folder. Here we simply move the message into the INBOX if it gets not removed and also not put into a custom folder.
534 if (!$folder_action && !$message_removed)
536 $move_into_folder[PRIVMSGS_INBOX][] = $msg_id;
540 // Do not change the order of processing
541 // The number of queries needed to be executed here highly depends on the defined rules and are
542 // only gone through if new messages arrive.
544 // Delete messages
545 if (sizeof($delete_ids))
547 $num_removed += sizeof($delete_ids);
548 delete_pm($user_id, $delete_ids, PRIVMSGS_NO_BOX);
551 // Set messages to Unread
552 if (sizeof($unread_ids))
554 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
555 SET pm_unread = 0
556 WHERE ' . phpbb::$db->sql_in_set('msg_id', $unread_ids) . "
557 AND user_id = $user_id
558 AND folder_id = " . PRIVMSGS_NO_BOX;
559 phpbb::$db->sql_query($sql);
562 // mark messages as important
563 if (sizeof($important_ids))
565 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
566 SET pm_marked = 1 - pm_marked
567 WHERE folder_id = ' . PRIVMSGS_NO_BOX . "
568 AND user_id = $user_id
569 AND " . phpbb::$db->sql_in_set('msg_id', $important_ids);
570 phpbb::$db->sql_query($sql);
573 // Move into folder
574 $folder = array();
576 if (sizeof($move_into_folder))
578 // Determine Full Folder Action - we need the move to folder id later eventually
579 $full_folder_action = (phpbb::$user->data['user_full_folder'] == FULL_FOLDER_NONE) ? (phpbb::$config['full_folder_action'] - (FULL_FOLDER_NONE*(-1))) : phpbb::$user->data['user_full_folder'];
581 $sql_folder = array_keys($move_into_folder);
582 if ($full_folder_action >= 0)
584 $sql_folder[] = $full_folder_action;
587 $sql = 'SELECT folder_id, pm_count
588 FROM ' . PRIVMSGS_FOLDER_TABLE . '
589 WHERE ' . phpbb::$db->sql_in_set('folder_id', $sql_folder) . "
590 AND user_id = $user_id";
591 $result = phpbb::$db->sql_query($sql);
593 while ($row = phpbb::$db->sql_fetchrow($result))
595 $folder[(int) $row['folder_id']] = (int) $row['pm_count'];
597 phpbb::$db->sql_freeresult($result);
599 unset($sql_folder);
601 if (isset($move_into_folder[PRIVMSGS_INBOX]))
603 $sql = 'SELECT COUNT(msg_id) as num_messages
604 FROM ' . PRIVMSGS_TO_TABLE . "
605 WHERE user_id = $user_id
606 AND folder_id = " . PRIVMSGS_INBOX;
607 $result = phpbb::$db->sql_query($sql);
608 $folder[PRIVMSGS_INBOX] = (int) phpbb::$db->sql_fetchfield('num_messages');
609 phpbb::$db->sql_freeresult($result);
613 // Here we have ideally only one folder to move into
614 foreach ($move_into_folder as $folder_id => $msg_ary)
616 $dest_folder = $folder_id;
617 $full_folder_action = FULL_FOLDER_NONE;
619 // Check Message Limit - we calculate with the complete array, most of the time it is one message
620 // But we are making sure that the other way around works too (more messages in queue than allowed to be stored)
621 if (phpbb::$user->data['message_limit'] && $folder[$folder_id] && ($folder[$folder_id] + sizeof($msg_ary)) > phpbb::$user->data['message_limit'])
623 $full_folder_action = (phpbb::$user->data['user_full_folder'] == FULL_FOLDER_NONE) ? (phpbb::$config['full_folder_action'] - (FULL_FOLDER_NONE*(-1))) : phpbb::$user->data['user_full_folder'];
625 // If destination folder itself is full...
626 if ($full_folder_action >= 0 && ($folder[$full_folder_action] + sizeof($msg_ary)) > phpbb::$user->data['message_limit'])
628 $full_folder_action = phpbb::$config['full_folder_action'] - (FULL_FOLDER_NONE*(-1));
631 // If Full Folder Action is to move to another folder, we simply adjust the destination folder
632 if ($full_folder_action >= 0)
634 $dest_folder = $full_folder_action;
636 else if ($full_folder_action == FULL_FOLDER_DELETE)
638 // Delete some messages. NOTE: Ordered by msg_id here instead of message_time!
639 $sql = 'SELECT msg_id
640 FROM ' . PRIVMSGS_TO_TABLE . "
641 WHERE user_id = $user_id
642 AND folder_id = $dest_folder
643 ORDER BY msg_id ASC";
644 $result = phpbb::$db->sql_query_limit($sql, (($folder[$dest_folder] + sizeof($msg_ary)) - phpbb::$user->data['message_limit']));
646 $delete_ids = array();
647 while ($row = phpbb::$db->sql_fetchrow($result))
649 $delete_ids[] = $row['msg_id'];
651 phpbb::$db->sql_freeresult($result);
653 $num_removed += sizeof($delete_ids);
654 delete_pm($user_id, $delete_ids, $dest_folder);
659 if ($full_folder_action == FULL_FOLDER_HOLD)
661 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
662 SET folder_id = ' . PRIVMSGS_HOLD_BOX . '
663 WHERE folder_id = ' . PRIVMSGS_NO_BOX . "
664 AND user_id = $user_id
665 AND " . phpbb::$db->sql_in_set('msg_id', $msg_ary);
666 phpbb::$db->sql_query($sql);
668 else
670 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
671 SET folder_id = $dest_folder, pm_new = 0
672 WHERE folder_id = " . PRIVMSGS_NO_BOX . "
673 AND user_id = $user_id
674 AND pm_new = 1
675 AND " . phpbb::$db->sql_in_set('msg_id', $msg_ary);
676 phpbb::$db->sql_query($sql);
678 if ($dest_folder != PRIVMSGS_INBOX)
680 $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . '
681 SET pm_count = pm_count + ' . (int) phpbb::$db->sql_affectedrows() . "
682 WHERE folder_id = $dest_folder
683 AND user_id = $user_id";
684 phpbb::$db->sql_query($sql);
689 if (sizeof($action_ary))
691 // Move from OUTBOX to SENTBOX
692 // We are not checking any full folder status here... SENTBOX is a special treatment (old messages get deleted)
693 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
694 SET folder_id = ' . PRIVMSGS_SENTBOX . '
695 WHERE folder_id = ' . PRIVMSGS_OUTBOX . '
696 AND ' . phpbb::$db->sql_in_set('msg_id', array_keys($action_ary));
697 phpbb::$db->sql_query($sql);
700 // Update new/unread count
701 update_pm_counts();
703 // Now check how many messages got not moved...
704 $sql = 'SELECT COUNT(msg_id) as num_messages
705 FROM ' . PRIVMSGS_TO_TABLE . "
706 WHERE user_id = $user_id
707 AND folder_id = " . PRIVMSGS_HOLD_BOX;
708 $result = phpbb::$db->sql_query($sql);
709 $num_not_moved = (int) phpbb::$db->sql_fetchfield('num_messages');
710 phpbb::$db->sql_freeresult($result);
712 return array('not_moved' => $num_not_moved, 'removed' => $num_removed);
716 * Move PM from one to another folder
718 function move_pm($user_id, $message_limit, $move_msg_ids, $dest_folder, $cur_folder_id)
720 $num_moved = 0;
722 if (!is_array($move_msg_ids))
724 $move_msg_ids = array($move_msg_ids);
727 if (sizeof($move_msg_ids) && !in_array($dest_folder, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX)) &&
728 !in_array($cur_folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)) && $cur_folder_id != $dest_folder)
730 // We have to check the destination folder ;)
731 if ($dest_folder != PRIVMSGS_INBOX)
733 $sql = 'SELECT folder_id, folder_name, pm_count
734 FROM ' . PRIVMSGS_FOLDER_TABLE . "
735 WHERE folder_id = $dest_folder
736 AND user_id = $user_id";
737 $result = phpbb::$db->sql_query($sql);
738 $row = phpbb::$db->sql_fetchrow($result);
739 phpbb::$db->sql_freeresult($result);
741 if (!$row)
743 trigger_error('NOT_AUTHORISED');
746 if ($message_limit && $row['pm_count'] + sizeof($move_msg_ids) > $message_limit)
748 $message = sprintf(phpbb::$user->lang['NOT_ENOUGH_SPACE_FOLDER'], $row['folder_name']) . '<br /><br />';
749 $message .= sprintf(phpbb::$user->lang['CLICK_RETURN_FOLDER'], '<a href="' . append_sid('ucp', 'i=pm&amp;folder=' . $row['folder_id']) . '">', '</a>', $row['folder_name']);
750 trigger_error($message);
753 else
755 $sql = 'SELECT COUNT(msg_id) as num_messages
756 FROM ' . PRIVMSGS_TO_TABLE . '
757 WHERE folder_id = ' . PRIVMSGS_INBOX . "
758 AND user_id = $user_id";
759 $result = phpbb::$db->sql_query($sql);
760 $num_messages = (int) phpbb::$db->sql_fetchfield('num_messages');
761 phpbb::$db->sql_freeresult($result);
763 if ($message_limit && $num_messages + sizeof($move_msg_ids) > $message_limit)
765 $message = sprintf(phpbb::$user->lang['NOT_ENOUGH_SPACE_FOLDER'], phpbb::$user->lang['PM_INBOX']) . '<br /><br />';
766 $message .= sprintf(phpbb::$user->lang['CLICK_RETURN_FOLDER'], '<a href="' . append_sid('ucp', 'i=pm&amp;folder=inbox') . '">', '</a>', phpbb::$user->lang['PM_INBOX']);
767 trigger_error($message);
771 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
772 SET folder_id = $dest_folder
773 WHERE folder_id = $cur_folder_id
774 AND user_id = $user_id
775 AND " . phpbb::$db->sql_in_set('msg_id', $move_msg_ids);
776 phpbb::$db->sql_query($sql);
777 $num_moved = phpbb::$db->sql_affectedrows();
779 // Update pm counts
780 if ($num_moved)
782 if (!in_array($cur_folder_id, array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX)))
784 $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . "
785 SET pm_count = pm_count - $num_moved
786 WHERE folder_id = $cur_folder_id
787 AND user_id = $user_id";
788 phpbb::$db->sql_query($sql);
791 if ($dest_folder != PRIVMSGS_INBOX)
793 $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . "
794 SET pm_count = pm_count + $num_moved
795 WHERE folder_id = $dest_folder
796 AND user_id = $user_id";
797 phpbb::$db->sql_query($sql);
801 else if (in_array($cur_folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)))
803 trigger_error('CANNOT_MOVE_SPECIAL');
806 return $num_moved;
810 * Update unread message status
812 function update_unread_status($unread, $msg_id, $user_id, $folder_id)
814 if (!$unread)
816 return;
819 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
820 SET pm_unread = 0
821 WHERE msg_id = $msg_id
822 AND user_id = $user_id
823 AND folder_id = $folder_id";
824 phpbb::$db->sql_query($sql);
826 $sql = 'UPDATE ' . USERS_TABLE . "
827 SET user_unread_privmsg = user_unread_privmsg - 1
828 WHERE user_id = $user_id";
829 phpbb::$db->sql_query($sql);
831 if (phpbb::$user->data['user_id'] == $user_id)
833 phpbb::$user->data['user_unread_privmsg']--;
835 // Try to cope with previous wrong conversions...
836 if (phpbb::$user->data['user_unread_privmsg'] < 0)
838 $sql = 'UPDATE ' . USERS_TABLE . "
839 SET user_unread_privmsg = 0
840 WHERE user_id = $user_id";
841 phpbb::$db->sql_query($sql);
843 phpbb::$user->data['user_unread_privmsg'] = 0;
849 * Handle all actions possible with marked messages
851 function handle_mark_actions($user_id, $mark_action)
853 $msg_ids = request_var('marked_msg_id', array(0));
854 $cur_folder_id = request_var('cur_folder_id', PRIVMSGS_NO_BOX);
855 $confirm = phpbb_request::is_set_post('confirm');
857 if (!sizeof($msg_ids))
859 return false;
862 switch ($mark_action)
864 case 'mark_important':
866 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
867 SET pm_marked = 1 - pm_marked
868 WHERE folder_id = $cur_folder_id
869 AND user_id = $user_id
870 AND " . phpbb::$db->sql_in_set('msg_id', $msg_ids);
871 phpbb::$db->sql_query($sql);
873 break;
875 case 'delete_marked':
877 if (confirm_box(true))
879 delete_pm($user_id, $msg_ids, $cur_folder_id);
881 $success_msg = (sizeof($msg_ids) == 1) ? 'MESSAGE_DELETED' : 'MESSAGES_DELETED';
882 $redirect = append_sid('ucp', 'i=pm&amp;folder=' . $cur_folder_id);
884 meta_refresh(3, $redirect);
885 trigger_error(phpbb::$user->lang[$success_msg] . '<br /><br />' . sprintf(phpbb::$user->lang['RETURN_FOLDER'], '<a href="' . $redirect . '">', '</a>'));
887 else
889 $s_hidden_fields = array(
890 'cur_folder_id' => $cur_folder_id,
891 'mark_option' => 'delete_marked',
892 'submit_mark' => true,
893 'marked_msg_id' => $msg_ids
896 confirm_box(false, 'DELETE_MARKED_PM', build_hidden_fields($s_hidden_fields));
899 break;
901 default:
902 return false;
905 return true;
909 * Delete PM(s)
911 function delete_pm($user_id, $msg_ids, $folder_id)
913 $user_id = (int) $user_id;
914 $folder_id = (int) $folder_id;
916 if (!$user_id)
918 return false;
921 if (!is_array($msg_ids))
923 if (!$msg_ids)
925 return false;
927 $msg_ids = array($msg_ids);
930 if (!sizeof($msg_ids))
932 return false;
935 // Get PM Information for later deleting
936 $sql = 'SELECT msg_id, pm_unread, pm_new
937 FROM ' . PRIVMSGS_TO_TABLE . '
938 WHERE ' . phpbb::$db->sql_in_set('msg_id', array_map('intval', $msg_ids)) . "
939 AND folder_id = $folder_id
940 AND user_id = $user_id";
941 $result = phpbb::$db->sql_query($sql);
943 $delete_rows = array();
944 $num_unread = $num_new = $num_deleted = 0;
945 while ($row = phpbb::$db->sql_fetchrow($result))
947 $num_unread += (int) $row['pm_unread'];
948 $num_new += (int) $row['pm_new'];
950 $delete_rows[$row['msg_id']] = 1;
952 phpbb::$db->sql_freeresult($result);
953 unset($msg_ids);
955 if (!sizeof($delete_rows))
957 return false;
960 phpbb::$db->sql_transaction('begin');
962 // if no one has read the message yet (meaning it is in users outbox)
963 // then mark the message as deleted...
964 if ($folder_id == PRIVMSGS_OUTBOX)
966 // Remove PM from Outbox
967 $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . "
968 WHERE user_id = $user_id AND folder_id = " . PRIVMSGS_OUTBOX . '
969 AND ' . phpbb::$db->sql_in_set('msg_id', array_keys($delete_rows));
970 phpbb::$db->sql_query($sql);
972 // Update PM Information for safety
973 $sql = 'UPDATE ' . PRIVMSGS_TABLE . " SET message_text = ''
974 WHERE " . phpbb::$db->sql_in_set('msg_id', array_keys($delete_rows));
975 phpbb::$db->sql_query($sql);
977 // Set delete flag for those intended to receive the PM
978 // We do not remove the message actually, to retain some basic information (sent time for example)
979 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
980 SET pm_deleted = 1
981 WHERE ' . phpbb::$db->sql_in_set('msg_id', array_keys($delete_rows));
982 phpbb::$db->sql_query($sql);
984 $num_deleted = phpbb::$db->sql_affectedrows();
986 else
988 // Delete private message data
989 $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . "
990 WHERE user_id = $user_id
991 AND folder_id = $folder_id
992 AND " . phpbb::$db->sql_in_set('msg_id', array_keys($delete_rows));
993 phpbb::$db->sql_query($sql);
994 $num_deleted = phpbb::$db->sql_affectedrows();
997 // if folder id is user defined folder then decrease pm_count
998 if (!in_array($folder_id, array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX, PRIVMSGS_NO_BOX)))
1000 $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . "
1001 SET pm_count = pm_count - $num_deleted
1002 WHERE folder_id = $folder_id";
1003 phpbb::$db->sql_query($sql);
1006 // Update unread and new status field
1007 if ($num_unread || $num_new)
1009 $set_sql = ($num_unread) ? 'user_unread_privmsg = user_unread_privmsg - ' . $num_unread : '';
1011 if ($num_new)
1013 $set_sql .= ($set_sql != '') ? ', ' : '';
1014 $set_sql .= 'user_new_privmsg = user_new_privmsg - ' . $num_new;
1017 phpbb::$db->sql_query('UPDATE ' . USERS_TABLE . " SET $set_sql WHERE user_id = $user_id");
1019 phpbb::$user->data['user_new_privmsg'] -= $num_new;
1020 phpbb::$user->data['user_unread_privmsg'] -= $num_unread;
1023 // Now we have to check which messages we can delete completely
1024 $sql = 'SELECT msg_id
1025 FROM ' . PRIVMSGS_TO_TABLE . '
1026 WHERE ' . phpbb::$db->sql_in_set('msg_id', array_keys($delete_rows));
1027 $result = phpbb::$db->sql_query($sql);
1029 while ($row = phpbb::$db->sql_fetchrow($result))
1031 unset($delete_rows[$row['msg_id']]);
1033 phpbb::$db->sql_freeresult($result);
1035 $delete_ids = array_keys($delete_rows);
1037 if (sizeof($delete_ids))
1039 // Check if there are any attachments we need to remove
1040 if (!function_exists('delete_attachments'))
1042 include(PHPBB_ROOT_PATH . 'includes/functions_admin.' . PHP_EXT);
1045 delete_attachments('message', $delete_ids, false);
1047 $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
1048 WHERE ' . phpbb::$db->sql_in_set('msg_id', $delete_ids);
1049 phpbb::$db->sql_query($sql);
1052 phpbb::$db->sql_transaction('commit');
1054 return true;
1058 * Rebuild message header
1060 function rebuild_header($check_ary)
1062 $address = array();
1064 foreach ($check_ary as $check_type => $address_field)
1066 // Split Addresses into users and groups
1067 preg_match_all('/:?(u|g)_([0-9]+):?/', $address_field, $match);
1069 $u = $g = array();
1070 foreach ($match[1] as $id => $type)
1072 ${$type}[] = (int) $match[2][$id];
1075 $_types = array('u', 'g');
1076 foreach ($_types as $type)
1078 if (sizeof($$type))
1080 foreach ($$type as $id)
1082 $address[$type][$id] = $check_type;
1088 return $address;
1092 * Print out/assign recipient information
1094 function write_pm_addresses($check_ary, $author_id, $plaintext = false)
1096 $addresses = array();
1098 foreach ($check_ary as $check_type => $address_field)
1100 if (!is_array($address_field))
1102 // Split Addresses into users and groups
1103 preg_match_all('/:?(u|g)_([0-9]+):?/', $address_field, $match);
1105 $u = $g = array();
1106 foreach ($match[1] as $id => $type)
1108 ${$type}[] = (int) $match[2][$id];
1111 else
1113 $u = $address_field['u'];
1114 $g = $address_field['g'];
1117 $address = array();
1118 if (sizeof($u))
1120 $sql = 'SELECT user_id, username, user_colour
1121 FROM ' . USERS_TABLE . '
1122 WHERE ' . phpbb::$db->sql_in_set('user_id', $u) . '
1123 AND user_type IN (' . phpbb::USER_NORMAL . ', ' . phpbb::USER_FOUNDER . ')';
1124 $result = phpbb::$db->sql_query($sql);
1126 while ($row = phpbb::$db->sql_fetchrow($result))
1128 if ($check_type == 'to' || $author_id == phpbb::$user->data['user_id'] || $row['user_id'] == phpbb::$user->data['user_id'])
1130 if ($plaintext)
1132 $address[] = $row['username'];
1134 else
1136 $address['user'][$row['user_id']] = array('name' => $row['username'], 'colour' => $row['user_colour']);
1140 phpbb::$db->sql_freeresult($result);
1143 if (sizeof($g))
1145 if ($plaintext)
1147 $sql = 'SELECT group_name, group_type
1148 FROM ' . GROUPS_TABLE . '
1149 WHERE ' . phpbb::$db->sql_in_set('group_id', $g);
1150 $result = phpbb::$db->sql_query($sql);
1152 while ($row = phpbb::$db->sql_fetchrow($result))
1154 if ($check_type == 'to' || $author_id == phpbb::$user->data['user_id'] || $row['user_id'] == phpbb::$user->data['user_id'])
1156 $address[] = ($row['group_type'] == GROUP_SPECIAL) ? phpbb::$user->lang['G_' . $row['group_name']] : $row['group_name'];
1159 phpbb::$db->sql_freeresult($result);
1161 else
1163 $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_type, ug.user_id
1164 FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug
1165 WHERE ' . phpbb::$db->sql_in_set('g.group_id', $g) . '
1166 AND g.group_id = ug.group_id
1167 AND ug.user_pending = 0';
1168 $result = phpbb::$db->sql_query($sql);
1170 while ($row = phpbb::$db->sql_fetchrow($result))
1172 if (!isset($address['group'][$row['group_id']]))
1174 if ($check_type == 'to' || $author_id == phpbb::$user->data['user_id'] || $row['user_id'] == phpbb::$user->data['user_id'])
1176 $row['group_name'] = ($row['group_type'] == GROUP_SPECIAL) ? phpbb::$user->lang['G_' . $row['group_name']] : $row['group_name'];
1177 $address['group'][$row['group_id']] = array('name' => $row['group_name'], 'colour' => $row['group_colour']);
1181 if (isset($address['user'][$row['user_id']]))
1183 $address['user'][$row['user_id']]['in_group'] = $row['group_id'];
1186 phpbb::$db->sql_freeresult($result);
1190 if (sizeof($address) && !$plaintext)
1192 phpbb::$template->assign_var('S_' . strtoupper($check_type) . '_RECIPIENT', true);
1194 foreach ($address as $type => $adr_ary)
1196 foreach ($adr_ary as $id => $row)
1198 $tpl_ary = array(
1199 'IS_GROUP' => ($type == 'group') ? true : false,
1200 'IS_USER' => ($type == 'user') ? true : false,
1201 'UG_ID' => $id,
1202 'NAME' => $row['name'],
1203 'COLOUR' => ($row['colour']) ? '#' . $row['colour'] : '',
1204 'TYPE' => $type,
1207 if ($type == 'user')
1209 $tpl_ary = array_merge($tpl_ary, array(
1210 'U_VIEW' => get_username_string('profile', $id, $row['name'], $row['colour']),
1211 'NAME_FULL' => get_username_string('full', $id, $row['name'], $row['colour']),
1214 else
1216 $tpl_ary = array_merge($tpl_ary, array(
1217 'U_VIEW' => append_sid('memberlist', 'mode=group&amp;g=' . $id),
1221 phpbb::$template->assign_block_vars($check_type . '_recipient', $tpl_ary);
1226 $addresses[$check_type] = $address;
1229 return $addresses;
1233 * Get folder status
1235 function get_folder_status($folder_id, $folder)
1237 if (isset($folder[$folder_id]))
1239 $folder = $folder[$folder_id];
1241 else
1243 return false;
1246 $return = array(
1247 'folder_name' => $folder['folder_name'],
1248 'cur' => $folder['num_messages'],
1249 'remaining' => (phpbb::$user->data['message_limit']) ? phpbb::$user->data['message_limit'] - $folder['num_messages'] : 0,
1250 'max' => phpbb::$user->data['message_limit'],
1251 'percent' => (phpbb::$user->data['message_limit']) ? ((phpbb::$user->data['message_limit'] > 0) ? round(($folder['num_messages'] / phpbb::$user->data['message_limit']) * 100) : 100) : 0,
1254 $return['message'] = sprintf(phpbb::$user->lang['FOLDER_STATUS_MSG'], $return['percent'], $return['cur'], $return['max']);
1256 return $return;
1260 // COMPOSE MESSAGES
1264 * Submit PM
1266 function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
1268 // We do not handle erasing pms here
1269 if ($mode == 'delete')
1271 return false;
1274 $current_time = time();
1276 // Collect some basic information about which tables and which rows to update/insert
1277 $sql_data = array();
1278 $root_level = 0;
1280 // Recipient Information
1281 $recipients = $to = $bcc = array();
1283 if ($mode != 'edit')
1285 // Build Recipient List
1286 // u|g => array($user_id => 'to'|'bcc')
1287 $_types = array('u', 'g');
1288 foreach ($_types as $ug_type)
1290 if (isset($data['address_list'][$ug_type]) && sizeof($data['address_list'][$ug_type]))
1292 foreach ($data['address_list'][$ug_type] as $id => $field)
1294 $id = (int) $id;
1296 // Do not rely on the address list being "valid"
1297 if (!$id || ($ug_type == 'u' && $id == ANONYMOUS))
1299 continue;
1302 $field = ($field == 'to') ? 'to' : 'bcc';
1303 if ($ug_type == 'u')
1305 $recipients[$id] = $field;
1307 ${$field}[] = $ug_type . '_' . $id;
1312 if (isset($data['address_list']['g']) && sizeof($data['address_list']['g']))
1314 // We need to check the PM status of group members (do they want to receive PM's?)
1315 // Only check if not a moderator or admin, since they are allowed to override this user setting
1316 $sql_allow_pm = (!phpbb::$acl->acl_gets('a_', 'm_') && !phpbb::$acl->acl_getf_global('m_')) ? ' AND u.user_allow_pm = 1' : '';
1318 $sql = 'SELECT u.user_type, ug.group_id, ug.user_id
1319 FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . ' ug
1320 WHERE ' . phpbb::$db->sql_in_set('ug.group_id', array_keys($data['address_list']['g'])) . '
1321 AND ug.user_pending = 0
1322 AND u.user_id = ug.user_id
1323 AND u.user_type IN (' . phpbb::USER_NORMAL . ', ' . phpbb::USER_FOUNDER . ')' .
1324 $sql_allow_pm;
1325 $result = phpbb::$db->sql_query($sql);
1327 while ($row = phpbb::$db->sql_fetchrow($result))
1329 $field = ($data['address_list']['g'][$row['group_id']] == 'to') ? 'to' : 'bcc';
1330 $recipients[$row['user_id']] = $field;
1332 phpbb::$db->sql_freeresult($result);
1335 if (!sizeof($recipients))
1337 trigger_error('NO_RECIPIENT');
1341 phpbb::$db->sql_transaction('begin');
1343 $sql = '';
1345 switch ($mode)
1347 case 'reply':
1348 case 'quote':
1349 $root_level = ($data['reply_from_root_level']) ? $data['reply_from_root_level'] : $data['reply_from_msg_id'];
1351 // Set message_replied switch for this user
1352 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
1353 SET pm_replied = 1
1354 WHERE user_id = ' . $data['from_user_id'] . '
1355 AND msg_id = ' . $data['reply_from_msg_id'];
1357 // no break
1359 case 'forward':
1360 case 'post':
1361 case 'quotepost':
1362 $sql_data = array(
1363 'root_level' => $root_level,
1364 'author_id' => $data['from_user_id'],
1365 'icon_id' => $data['icon_id'],
1366 'author_ip' => $data['from_user_ip'],
1367 'message_time' => $current_time,
1368 'enable_bbcode' => $data['enable_bbcode'],
1369 'enable_smilies' => $data['enable_smilies'],
1370 'enable_magic_url' => $data['enable_urls'],
1371 'enable_sig' => $data['enable_sig'],
1372 'message_subject' => $subject,
1373 'message_text' => $data['message'],
1374 'message_attachment'=> (!empty($data['attachment_data'])) ? 1 : 0,
1375 'bbcode_bitfield' => $data['bbcode_bitfield'],
1376 'bbcode_uid' => $data['bbcode_uid'],
1377 'to_address' => implode(':', $to),
1378 'bcc_address' => implode(':', $bcc)
1380 break;
1382 case 'edit':
1383 $sql_data = array(
1384 'icon_id' => $data['icon_id'],
1385 'message_edit_time' => $current_time,
1386 'enable_bbcode' => $data['enable_bbcode'],
1387 'enable_smilies' => $data['enable_smilies'],
1388 'enable_magic_url' => $data['enable_urls'],
1389 'enable_sig' => $data['enable_sig'],
1390 'message_subject' => $subject,
1391 'message_text' => $data['message'],
1392 'message_attachment'=> (!empty($data['attachment_data'])) ? 1 : 0,
1393 'bbcode_bitfield' => $data['bbcode_bitfield'],
1394 'bbcode_uid' => $data['bbcode_uid']
1396 break;
1399 if (sizeof($sql_data))
1401 $query = '';
1403 if ($mode == 'post' || $mode == 'reply' || $mode == 'quote' || $mode == 'quotepost' || $mode == 'forward')
1405 phpbb::$db->sql_query('INSERT INTO ' . PRIVMSGS_TABLE . ' ' . phpbb::$db->sql_build_array('INSERT', $sql_data));
1406 $data['msg_id'] = phpbb::$db->sql_nextid();
1408 else if ($mode == 'edit')
1410 $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
1411 SET message_edit_count = message_edit_count + 1, ' . phpbb::$db->sql_build_array('UPDATE', $sql_data) . '
1412 WHERE msg_id = ' . $data['msg_id'];
1413 phpbb::$db->sql_query($sql);
1417 if ($mode != 'edit')
1419 if ($sql)
1421 phpbb::$db->sql_query($sql);
1423 unset($sql);
1425 $sql_ary = array();
1426 foreach ($recipients as $user_id => $type)
1428 $sql_ary[] = array(
1429 'msg_id' => (int) $data['msg_id'],
1430 'user_id' => (int) $user_id,
1431 'author_id' => (int) $data['from_user_id'],
1432 'folder_id' => PRIVMSGS_NO_BOX,
1433 'pm_new' => 1,
1434 'pm_unread' => 1,
1435 'pm_forwarded' => ($mode == 'forward') ? 1 : 0
1439 phpbb::$db->sql_multi_insert(PRIVMSGS_TO_TABLE, $sql_ary);
1441 $sql = 'UPDATE ' . USERS_TABLE . '
1442 SET user_new_privmsg = user_new_privmsg + 1, user_unread_privmsg = user_unread_privmsg + 1, user_last_privmsg = ' . time() . '
1443 WHERE ' . phpbb::$db->sql_in_set('user_id', array_keys($recipients));
1444 phpbb::$db->sql_query($sql);
1446 // Put PM into outbox
1447 if ($put_in_outbox)
1449 phpbb::$db->sql_query('INSERT INTO ' . PRIVMSGS_TO_TABLE . ' ' . phpbb::$db->sql_build_array('INSERT', array(
1450 'msg_id' => (int) $data['msg_id'],
1451 'user_id' => (int) $data['from_user_id'],
1452 'author_id' => (int) $data['from_user_id'],
1453 'folder_id' => PRIVMSGS_OUTBOX,
1454 'pm_new' => 0,
1455 'pm_unread' => 0,
1456 'pm_forwarded' => ($mode == 'forward') ? 1 : 0))
1461 // Set user last post time
1462 if ($mode == 'reply' || $mode == 'quote' || $mode == 'quotepost' || $mode == 'forward' || $mode == 'post')
1464 $sql = 'UPDATE ' . USERS_TABLE . "
1465 SET user_lastpost_time = $current_time
1466 WHERE user_id = " . $data['from_user_id'];
1467 phpbb::$db->sql_query($sql);
1470 // Submit Attachments
1471 if (!empty($data['attachment_data']) && $data['msg_id'] && in_array($mode, array('post', 'reply', 'quote', 'quotepost', 'edit', 'forward')))
1473 $space_taken = $files_added = 0;
1474 $orphan_rows = array();
1476 foreach ($data['attachment_data'] as $pos => $attach_row)
1478 $orphan_rows[(int) $attach_row['attach_id']] = array();
1481 if (sizeof($orphan_rows))
1483 $sql = 'SELECT attach_id, filesize, physical_filename
1484 FROM ' . ATTACHMENTS_TABLE . '
1485 WHERE ' . phpbb::$db->sql_in_set('attach_id', array_keys($orphan_rows)) . '
1486 AND in_message = 1
1487 AND is_orphan = 1
1488 AND poster_id = ' . phpbb::$user->data['user_id'];
1489 $result = phpbb::$db->sql_query($sql);
1491 $orphan_rows = array();
1492 while ($row = phpbb::$db->sql_fetchrow($result))
1494 $orphan_rows[$row['attach_id']] = $row;
1496 phpbb::$db->sql_freeresult($result);
1499 foreach ($data['attachment_data'] as $pos => $attach_row)
1501 if ($attach_row['is_orphan'] && !isset($orphan_rows[$attach_row['attach_id']]))
1503 continue;
1506 if (!$attach_row['is_orphan'])
1508 // update entry in db if attachment already stored in db and filespace
1509 $sql = 'UPDATE ' . ATTACHMENTS_TABLE . "
1510 SET attach_comment = '" . phpbb::$db->sql_escape($attach_row['attach_comment']) . "'
1511 WHERE attach_id = " . (int) $attach_row['attach_id'] . '
1512 AND is_orphan = 0';
1513 phpbb::$db->sql_query($sql);
1515 else
1517 // insert attachment into db
1518 if (!@file_exists(PHPBB_ROOT_PATH . phpbb::$config['upload_path'] . '/' . basename($orphan_rows[$attach_row['attach_id']]['physical_filename'])))
1520 continue;
1523 $space_taken += $orphan_rows[$attach_row['attach_id']]['filesize'];
1524 $files_added++;
1526 $attach_sql = array(
1527 'post_msg_id' => $data['msg_id'],
1528 'topic_id' => 0,
1529 'is_orphan' => 0,
1530 'poster_id' => $data['from_user_id'],
1531 'attach_comment' => $attach_row['attach_comment'],
1534 $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' SET ' . phpbb::$db->sql_build_array('UPDATE', $attach_sql) . '
1535 WHERE attach_id = ' . $attach_row['attach_id'] . '
1536 AND is_orphan = 1
1537 AND poster_id = ' . phpbb::$user->data['user_id'];
1538 phpbb::$db->sql_query($sql);
1542 if ($space_taken && $files_added)
1544 set_config_count('upload_dir_size', $space_taken, true);
1545 set_config_count('num_files', $files_added, true);
1549 // Delete draft if post was loaded...
1550 $draft_id = request_var('draft_loaded', 0);
1551 if ($draft_id)
1553 $sql = 'DELETE FROM ' . DRAFTS_TABLE . "
1554 WHERE draft_id = $draft_id
1555 AND user_id = " . $data['from_user_id'];
1556 phpbb::$db->sql_query($sql);
1559 phpbb::$db->sql_transaction('commit');
1561 // Send Notifications
1562 if ($mode != 'edit')
1564 pm_notification($mode, $data['from_username'], $recipients, $subject, $data['message']);
1567 return $data['msg_id'];
1571 * PM Notification
1573 function pm_notification($mode, $author, $recipients, $subject, $message)
1575 $subject = censor_text($subject);
1577 unset($recipients[ANONYMOUS], $recipients[phpbb::$user->data['user_id']]);
1579 if (!sizeof($recipients))
1581 return;
1584 // Get banned User ID's
1585 $sql = 'SELECT ban_userid
1586 FROM ' . BANLIST_TABLE . '
1587 WHERE ' . phpbb::$db->sql_in_set('ban_userid', array_map('intval', array_keys($recipients))) . '
1588 AND ban_exclude = 0';
1589 $result = phpbb::$db->sql_query($sql);
1591 while ($row = phpbb::$db->sql_fetchrow($result))
1593 unset($recipients[$row['ban_userid']]);
1595 phpbb::$db->sql_freeresult($result);
1597 if (!sizeof($recipients))
1599 return;
1602 $sql = 'SELECT user_id, username, user_email, user_lang, user_notify_pm, user_notify_type, user_jabber
1603 FROM ' . USERS_TABLE . '
1604 WHERE ' . phpbb::$db->sql_in_set('user_id', array_map('intval', array_keys($recipients)));
1605 $result = phpbb::$db->sql_query($sql);
1607 $msg_list_ary = array();
1608 while ($row = phpbb::$db->sql_fetchrow($result))
1610 if ($row['user_notify_pm'] == 1 && trim($row['user_email']))
1612 $msg_list_ary[] = array(
1613 'method' => $row['user_notify_type'],
1614 'email' => $row['user_email'],
1615 'jabber' => $row['user_jabber'],
1616 'name' => $row['username'],
1617 'lang' => $row['user_lang']
1621 phpbb::$db->sql_freeresult($result);
1623 if (!sizeof($msg_list_ary))
1625 return;
1628 include_once(PHPBB_ROOT_PATH . 'includes/functions_messenger.' . PHP_EXT);
1629 $messenger = new messenger();
1631 foreach ($msg_list_ary as $pos => $addr)
1633 $messenger->template('privmsg_notify', $addr['lang']);
1635 $messenger->to($addr['email'], $addr['name']);
1636 $messenger->im($addr['jabber'], $addr['name']);
1638 $messenger->assign_vars(array(
1639 'SUBJECT' => htmlspecialchars_decode($subject),
1640 'AUTHOR_NAME' => htmlspecialchars_decode($author),
1641 'USERNAME' => htmlspecialchars_decode($addr['name']),
1643 'U_INBOX' => generate_board_url() . '/ucp.' . PHP_EXT . '?i=pm&folder=inbox')
1646 $messenger->send($addr['method']);
1648 unset($msg_list_ary);
1650 $messenger->save_queue();
1652 unset($messenger);
1656 * Display Message History
1658 function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode = false)
1660 global $bbcode;
1662 // Get History Messages (could be newer)
1663 $sql = 'SELECT t.*, p.*, u.*
1664 FROM ' . PRIVMSGS_TABLE . ' p, ' . PRIVMSGS_TO_TABLE . ' t, ' . USERS_TABLE . ' u
1665 WHERE t.msg_id = p.msg_id
1666 AND p.author_id = u.user_id
1667 AND t.folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ")
1668 AND t.user_id = $user_id";
1670 if (!$message_row['root_level'])
1672 $sql .= " AND (p.root_level = $msg_id OR (p.root_level = 0 AND p.msg_id = $msg_id))";
1674 else
1676 $sql .= " AND (p.root_level = " . $message_row['root_level'] . ' OR p.msg_id = ' . $message_row['root_level'] . ')';
1678 $sql .= ' ORDER BY p.message_time DESC';
1680 $result = phpbb::$db->sql_query($sql);
1681 $row = phpbb::$db->sql_fetchrow($result);
1683 if (!$row)
1685 phpbb::$db->sql_freeresult($result);
1686 return false;
1689 $rowset = array();
1690 $bbcode_bitfield = '';
1691 $folder_url = append_sid('ucp', 'i=pm') . '&amp;folder=';
1695 $folder_id = (int) $row['folder_id'];
1697 $row['folder'][] = (isset($folder[$folder_id])) ? '<a href="' . $folder_url . $folder_id . '">' . $folder[$folder_id]['folder_name'] . '</a>' : phpbb::$user->lang['UNKNOWN_FOLDER'];
1699 if (isset($rowset[$row['msg_id']]))
1701 $rowset[$row['msg_id']]['folder'][] = (isset($folder[$folder_id])) ? '<a href="' . $folder_url . $folder_id . '">' . $folder[$folder_id]['folder_name'] . '</a>' : phpbb::$user->lang['UNKNOWN_FOLDER'];
1703 else
1705 $rowset[$row['msg_id']] = $row;
1706 $bbcode_bitfield = $bbcode_bitfield | base64_decode($row['bbcode_bitfield']);
1709 while ($row = phpbb::$db->sql_fetchrow($result));
1710 phpbb::$db->sql_freeresult($result);
1712 $title = $row['message_subject'];
1714 if (sizeof($rowset) == 1 && !$in_post_mode)
1716 return false;
1719 // Instantiate BBCode class
1720 if ((empty($bbcode) || $bbcode === false) && $bbcode_bitfield !== '')
1722 if (!class_exists('bbcode'))
1724 include(PHPBB_ROOT_PATH . 'includes/bbcode.' . PHP_EXT);
1726 $bbcode = new bbcode(base64_encode($bbcode_bitfield));
1729 $title = censor_text($title);
1731 $url = append_sid('ucp', 'i=pm');
1732 $next_history_pm = $previous_history_pm = $prev_id = 0;
1734 // Re-order rowset to be able to get the next/prev message rows...
1735 $rowset = array_values($rowset);
1737 for ($i = 0, $size = sizeof($rowset); $i < $size; $i++)
1739 $row = &$rowset[$i];
1740 $id = (int) $row['msg_id'];
1742 $author_id = $row['author_id'];
1743 $folder_id = (int) $row['folder_id'];
1745 $subject = $row['message_subject'];
1746 $message = $row['message_text'];
1748 $message = censor_text($message);
1750 $decoded_message = false;
1752 if ($in_post_mode && phpbb::$acl->acl_get('u_sendpm') && $author_id != ANONYMOUS && $author_id != phpbb::$user->data['user_id'])
1754 $decoded_message = $message;
1755 decode_message($decoded_message, $row['bbcode_uid']);
1757 $decoded_message = bbcode_nl2br($decoded_message);
1760 if ($row['bbcode_bitfield'])
1762 $bbcode->bbcode_second_pass($message, $row['bbcode_uid'], $row['bbcode_bitfield']);
1765 $message = bbcode_nl2br($message);
1766 $message = smiley_text($message, !$row['enable_smilies']);
1768 $subject = censor_text($subject);
1770 if ($id == $msg_id)
1772 $next_history_pm = (isset($rowset[$i + 1])) ? (int) $rowset[$i + 1]['msg_id'] : 0;
1773 $previous_history_pm = $prev_id;
1776 phpbb::$template->assign_block_vars('history_row', array(
1777 'MESSAGE_AUTHOR_QUOTE' => (($decoded_message) ? addslashes(get_username_string('username', $author_id, $row['username'], $row['user_colour'], $row['username'])) : ''),
1778 'MESSAGE_AUTHOR_FULL' => get_username_string('full', $author_id, $row['username'], $row['user_colour'], $row['username']),
1779 'MESSAGE_AUTHOR_COLOUR' => get_username_string('colour', $author_id, $row['username'], $row['user_colour'], $row['username']),
1780 'MESSAGE_AUTHOR' => get_username_string('username', $author_id, $row['username'], $row['user_colour'], $row['username']),
1781 'U_MESSAGE_AUTHOR' => get_username_string('profile', $author_id, $row['username'], $row['user_colour'], $row['username']),
1783 'SUBJECT' => $subject,
1784 'SENT_DATE' => phpbb::$user->format_date($row['message_time']),
1785 'MESSAGE' => $message,
1786 'FOLDER' => implode(', ', $row['folder']),
1787 'DECODED_MESSAGE' => $decoded_message,
1789 'S_CURRENT_MSG' => ($row['msg_id'] == $msg_id),
1790 'S_AUTHOR_DELETED' => ($author_id == ANONYMOUS) ? true : false,
1791 'S_IN_POST_MODE' => $in_post_mode,
1793 'MSG_ID' => $row['msg_id'],
1794 'U_VIEW_MESSAGE' => "$url&amp;f=$folder_id&amp;p=" . $row['msg_id'],
1795 'U_QUOTE' => (!$in_post_mode && phpbb::$acl->acl_get('u_sendpm') && $author_id != ANONYMOUS && $author_id != phpbb::$user->data['user_id']) ? "$url&amp;mode=compose&amp;action=quote&amp;f=" . $folder_id . "&amp;p=" . $row['msg_id'] : '',
1796 'U_POST_REPLY_PM' => ($author_id != phpbb::$user->data['user_id'] && $author_id != ANONYMOUS && phpbb::$acl->acl_get('u_sendpm')) ? "$url&amp;mode=compose&amp;action=reply&amp;f=$folder_id&amp;p=" . $row['msg_id'] : '',
1798 unset($rowset[$id]);
1799 $prev_id = $id;
1802 phpbb::$template->assign_vars(array(
1803 'QUOTE_IMG' => phpbb::$user->img('icon_post_quote', 'REPLY_WITH_QUOTE'),
1804 'HISTORY_TITLE' => $title,
1806 'U_VIEW_NEXT_HISTORY' => ($next_history_pm) ? "$url&amp;p=" . $next_history_pm : '',
1807 'U_VIEW_PREVIOUS_HISTORY' => ($previous_history_pm) ? "$url&amp;p=" . $previous_history_pm : '',
1810 return true;
1814 * Set correct users max messages in PM folder.
1815 * If several group memberships define different amount of messages, the highest will be chosen.
1817 function set_user_message_limit()
1819 // Get maximum about from user memberships - if it is 0, there is no limit set and we use the maximum value within the config.
1820 $sql = 'SELECT MAX(g.group_message_limit) as max_message_limit
1821 FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug
1822 WHERE ug.user_id = ' . phpbb::$user->data['user_id'] . '
1823 AND ug.user_pending = 0
1824 AND ug.group_id = g.group_id';
1825 $result = phpbb::$db->sql_query($sql);
1826 $message_limit = (int) phpbb::$db->sql_fetchfield('max_message_limit');
1827 phpbb::$db->sql_freeresult($result);
1829 phpbb::$user->data['message_limit'] = (!$message_limit) ? phpbb::$config['pm_max_msgs'] : $message_limit;