(a little test for later merges)
[phpbb.git] / phpBB / includes / functions_privmsgs.php
blobc93b6a6bba96abf7f885258df5bd46f839970c74
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 global $db, $user, $template;
119 global $phpbb_root_path, $phpEx;
121 $folder = array();
123 // Get folder information
124 $sql = 'SELECT folder_id, COUNT(msg_id) as num_messages, SUM(pm_unread) as num_unread
125 FROM ' . PRIVMSGS_TO_TABLE . "
126 WHERE user_id = $user_id
127 AND folder_id <> " . PRIVMSGS_NO_BOX . '
128 GROUP BY folder_id';
129 $result = $db->sql_query($sql);
131 $num_messages = $num_unread = array();
132 while ($row = $db->sql_fetchrow($result))
134 $num_messages[(int) $row['folder_id']] = $row['num_messages'];
135 $num_unread[(int) $row['folder_id']] = $row['num_unread'];
137 $db->sql_freeresult($result);
139 // Make sure the default boxes are defined
140 $available_folder = array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX);
142 foreach ($available_folder as $default_folder)
144 if (!isset($num_messages[$default_folder]))
146 $num_messages[$default_folder] = 0;
149 if (!isset($num_unread[$default_folder]))
151 $num_unread[$default_folder] = 0;
155 // Adjust unread status for outbox
156 $num_unread[PRIVMSGS_OUTBOX] = $num_messages[PRIVMSGS_OUTBOX];
158 $folder[PRIVMSGS_INBOX] = array(
159 'folder_name' => $user->lang['PM_INBOX'],
160 'num_messages' => $num_messages[PRIVMSGS_INBOX],
161 'unread_messages' => $num_unread[PRIVMSGS_INBOX]
164 // Custom Folder
165 $sql = 'SELECT folder_id, folder_name, pm_count
166 FROM ' . PRIVMSGS_FOLDER_TABLE . "
167 WHERE user_id = $user_id";
168 $result = $db->sql_query($sql);
170 while ($row = $db->sql_fetchrow($result))
172 $folder[$row['folder_id']] = array(
173 'folder_name' => $row['folder_name'],
174 'num_messages' => $row['pm_count'],
175 'unread_messages' => ((isset($num_unread[$row['folder_id']])) ? $num_unread[$row['folder_id']] : 0)
178 $db->sql_freeresult($result);
180 $folder[PRIVMSGS_OUTBOX] = array(
181 'folder_name' => $user->lang['PM_OUTBOX'],
182 'num_messages' => $num_messages[PRIVMSGS_OUTBOX],
183 'unread_messages' => $num_unread[PRIVMSGS_OUTBOX]
186 $folder[PRIVMSGS_SENTBOX] = array(
187 'folder_name' => $user->lang['PM_SENTBOX'],
188 'num_messages' => $num_messages[PRIVMSGS_SENTBOX],
189 'unread_messages' => $num_unread[PRIVMSGS_SENTBOX]
192 // Define Folder Array for template designers (and for making custom folders usable by the template too)
193 foreach ($folder as $f_id => $folder_ary)
195 $folder_id_name = ($f_id == PRIVMSGS_INBOX) ? 'inbox' : (($f_id == PRIVMSGS_OUTBOX) ? 'outbox' : 'sentbox');
197 $template->assign_block_vars('folder', array(
198 'FOLDER_ID' => $f_id,
199 'FOLDER_NAME' => $folder_ary['folder_name'],
200 'NUM_MESSAGES' => $folder_ary['num_messages'],
201 'UNREAD_MESSAGES' => $folder_ary['unread_messages'],
203 'U_FOLDER' => ($f_id > 0) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=' . $f_id) : append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=' . $folder_id_name),
205 'S_CUR_FOLDER' => ($f_id === $folder_id) ? true : false,
206 'S_UNREAD_MESSAGES' => ($folder_ary['unread_messages']) ? true : false,
207 'S_CUSTOM_FOLDER' => ($f_id > 0) ? true : false)
211 if ($folder_id !== false && !isset($folder[$folder_id]))
213 trigger_error('UNKNOWN_FOLDER');
216 return $folder;
220 * Delete Messages From Sentbox
221 * we are doing this here because this saves us a bunch of checks and queries
223 function clean_sentbox($num_sentbox_messages)
225 global $db, $user, $config;
227 // Check Message Limit
228 if ($user->data['message_limit'] && $num_sentbox_messages > $user->data['message_limit'])
230 // Delete old messages
231 $sql = 'SELECT t.msg_id
232 FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p
233 WHERE t.msg_id = p.msg_id
234 AND t.user_id = ' . $user->data['user_id'] . '
235 AND t.folder_id = ' . PRIVMSGS_SENTBOX . '
236 ORDER BY p.message_time ASC';
237 $result = $db->sql_query_limit($sql, ($num_sentbox_messages - $user->data['message_limit']));
239 $delete_ids = array();
240 while ($row = $db->sql_fetchrow($result))
242 $delete_ids[] = $row['msg_id'];
244 $db->sql_freeresult($result);
245 delete_pm($user->data['user_id'], $delete_ids, PRIVMSGS_SENTBOX);
250 * Check Rule against Message Information
252 function check_rule(&$rules, &$rule_row, &$message_row, $user_id)
254 global $user, $config;
256 if (!isset($rules[$rule_row['rule_check']][$rule_row['rule_connection']]))
258 return false;
261 $check_ary = $rules[$rule_row['rule_check']][$rule_row['rule_connection']];
263 // Replace Check Literals
264 $evaluate = $check_ary['function'];
265 $evaluate = preg_replace('/{(CHECK[0-9])}/', '$message_row[$check_ary[strtolower("\1")]]', $evaluate);
267 // Replace Rule Literals
268 $evaluate = preg_replace('/{(STRING|USER_ID|GROUP_ID)}/', '$rule_row["rule_" . strtolower("\1")]', $evaluate);
270 // Evil Statement
271 $result = false;
272 eval('$result = (' . $evaluate . ') ? true : false;');
274 if (!$result)
276 return false;
279 switch ($rule_row['rule_action'])
281 case ACTION_PLACE_INTO_FOLDER:
282 return array('action' => $rule_row['rule_action'], 'folder_id' => $rule_row['rule_folder_id']);
283 break;
285 case ACTION_MARK_AS_READ:
286 case ACTION_MARK_AS_IMPORTANT:
287 return array('action' => $rule_row['rule_action'], 'pm_unread' => $message_row['pm_unread'], 'pm_marked' => $message_row['pm_marked']);
288 break;
290 case ACTION_DELETE_MESSAGE:
291 global $db, $auth;
293 // Check for admins/mods - users are not allowed to remove those messages...
294 // We do the check here to make sure the data we use is consistent
295 $sql = 'SELECT user_id, user_type, user_permissions
296 FROM ' . USERS_TABLE . '
297 WHERE user_id = ' . (int) $message_row['author_id'];
298 $result = $db->sql_query($sql);
299 $userdata = $db->sql_fetchrow($result);
300 $db->sql_freeresult($result);
302 $auth2 = new auth();
303 $auth2->acl($userdata);
305 if (!$auth2->acl_get('a_') && !$auth2->acl_get('m_') && !$auth2->acl_getf_global('m_'))
307 return array('action' => $rule_row['rule_action'], 'pm_unread' => $message_row['pm_unread'], 'pm_marked' => $message_row['pm_marked']);
310 return false;
311 break;
313 default:
314 return false;
317 return false;
321 * Update user PM count
323 function update_pm_counts()
325 global $user, $db;
327 // Update unread count
328 $sql = 'SELECT COUNT(msg_id) as num_messages
329 FROM ' . PRIVMSGS_TO_TABLE . '
330 WHERE pm_unread = 1
331 AND folder_id <> ' . PRIVMSGS_OUTBOX . '
332 AND user_id = ' . $user->data['user_id'];
333 $result = $db->sql_query($sql);
334 $user->data['user_unread_privmsg'] = (int) $db->sql_fetchfield('num_messages');
335 $db->sql_freeresult($result);
337 // Update new pm count
338 $sql = 'SELECT COUNT(msg_id) as num_messages
339 FROM ' . PRIVMSGS_TO_TABLE . '
340 WHERE pm_new = 1
341 AND folder_id IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
342 AND user_id = ' . $user->data['user_id'];
343 $result = $db->sql_query($sql);
344 $user->data['user_new_privmsg'] = (int) $db->sql_fetchfield('num_messages');
345 $db->sql_freeresult($result);
347 $db->sql_query('UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array(
348 'user_unread_privmsg' => (int) $user->data['user_unread_privmsg'],
349 'user_new_privmsg' => (int) $user->data['user_new_privmsg'],
350 )) . ' WHERE user_id = ' . $user->data['user_id']);
352 // Ok, here we need to repair something, other boxes than privmsgs_no_box and privmsgs_hold_box should not carry the pm_new flag.
353 if (!$user->data['user_new_privmsg'])
355 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
356 SET pm_new = 0
357 WHERE pm_new = 1
358 AND folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
359 AND user_id = ' . $user->data['user_id'];
360 $db->sql_query($sql);
365 * Place new messages into appropriate folder
367 function place_pm_into_folder(&$global_privmsgs_rules, $release = false)
369 global $db, $user, $config;
371 if (!$user->data['user_new_privmsg'])
373 return array('not_moved' => 0, 'removed' => 0);
376 $user_message_rules = (int) $user->data['user_message_rules'];
377 $user_id = (int) $user->data['user_id'];
379 $action_ary = $move_into_folder = array();
380 $num_removed = 0;
382 // Newly processing on-hold messages
383 if ($release)
385 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
386 SET folder_id = ' . PRIVMSGS_NO_BOX . '
387 WHERE folder_id = ' . PRIVMSGS_HOLD_BOX . "
388 AND user_id = $user_id";
389 $db->sql_query($sql);
392 // Get those messages not yet placed into any box
393 $retrieve_sql = 'SELECT t.*, p.*, u.username, u.user_id, u.group_id
394 FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p, ' . USERS_TABLE . " u
395 WHERE t.user_id = $user_id
396 AND p.author_id = u.user_id
397 AND t.folder_id = " . PRIVMSGS_NO_BOX . '
398 AND t.msg_id = p.msg_id';
400 // Just place into the appropriate arrays if no rules need to be checked
401 if (!$user_message_rules)
403 $result = $db->sql_query($retrieve_sql);
405 while ($row = $db->sql_fetchrow($result))
407 $action_ary[$row['msg_id']][] = array('action' => false);
409 $db->sql_freeresult($result);
411 else
413 $user_rules = $zebra = $check_rows = array();
414 $user_ids = $memberships = array();
416 // First of all, grab all rules and retrieve friends/foes
417 $sql = 'SELECT *
418 FROM ' . PRIVMSGS_RULES_TABLE . "
419 WHERE user_id = $user_id";
420 $result = $db->sql_query($sql);
421 $user_rules = $db->sql_fetchrowset($result);
422 $db->sql_freeresult($result);
424 if (sizeof($user_rules))
426 $sql = 'SELECT zebra_id, friend, foe
427 FROM ' . ZEBRA_TABLE . "
428 WHERE user_id = $user_id";
429 $result = $db->sql_query($sql);
431 while ($row = $db->sql_fetchrow($result))
433 $zebra[$row['zebra_id']] = $row;
435 $db->sql_freeresult($result);
438 // Now build a bare-bone check_row array
439 $result = $db->sql_query($retrieve_sql);
441 while ($row = $db->sql_fetchrow($result))
443 $check_rows[] = array_merge($row, array(
444 'to' => explode(':', $row['to_address']),
445 'bcc' => explode(':', $row['bcc_address']),
446 'friend' => (isset($zebra[$row['author_id']])) ? $zebra[$row['author_id']]['friend'] : 0,
447 'foe' => (isset($zebra[$row['author_id']])) ? $zebra[$row['author_id']]['foe'] : 0,
448 'user_in_group' => array($user->data['group_id']),
449 'author_in_group' => array())
452 $user_ids[] = $row['user_id'];
454 $db->sql_freeresult($result);
456 // Retrieve user memberships
457 if (sizeof($user_ids))
459 $sql = 'SELECT *
460 FROM ' . USER_GROUP_TABLE . '
461 WHERE ' . $db->sql_in_set('user_id', $user_ids) . '
462 AND user_pending = 0';
463 $result = $db->sql_query($sql);
465 while ($row = $db->sql_fetchrow($result))
467 $memberships[$row['user_id']][] = $row['group_id'];
469 $db->sql_freeresult($result);
472 // Now place into the appropriate folder
473 foreach ($check_rows as $row)
475 // Add membership if set
476 if (isset($memberships[$row['author_id']]))
478 $row['author_in_group'] = $memberships[$row['user_id']];
481 // Check Rule - this should be very quick since we have all information we need
482 $is_match = false;
483 foreach ($user_rules as $rule_row)
485 if (($action = check_rule($global_privmsgs_rules, $rule_row, $row, $user_id)) !== false)
487 $is_match = true;
488 $action_ary[$row['msg_id']][] = $action;
492 if (!$is_match)
494 $action_ary[$row['msg_id']][] = array('action' => false);
498 unset($user_rules, $zebra, $check_rows, $user_ids, $memberships);
501 // We place actions into arrays, to save queries.
502 $sql = $unread_ids = $delete_ids = $important_ids = array();
504 foreach ($action_ary as $msg_id => $msg_ary)
506 // It is allowed to execute actions more than once, except placing messages into folder
507 $folder_action = $message_removed = false;
509 foreach ($msg_ary as $pos => $rule_ary)
511 if ($folder_action && $rule_ary['action'] == ACTION_PLACE_INTO_FOLDER)
513 continue;
516 switch ($rule_ary['action'])
518 case ACTION_PLACE_INTO_FOLDER:
519 // Folder actions have precedence, so we will remove any other ones
520 $folder_action = true;
521 $move_into_folder[(int) $rule_ary['folder_id']][] = $msg_id;
522 break;
524 case ACTION_MARK_AS_READ:
525 if ($rule_ary['pm_unread'])
527 $unread_ids[] = $msg_id;
529 break;
531 case ACTION_DELETE_MESSAGE:
532 $delete_ids[] = $msg_id;
533 $message_removed = true;
534 break;
536 case ACTION_MARK_AS_IMPORTANT:
537 if (!$rule_ary['pm_marked'])
539 $important_ids[] = $msg_id;
541 break;
545 // 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
546 // folder. Here we simply move the message into the INBOX if it gets not removed and also not put into a custom folder.
547 if (!$folder_action && !$message_removed)
549 $move_into_folder[PRIVMSGS_INBOX][] = $msg_id;
553 // Do not change the order of processing
554 // The number of queries needed to be executed here highly depends on the defined rules and are
555 // only gone through if new messages arrive.
557 // Delete messages
558 if (sizeof($delete_ids))
560 $num_removed += sizeof($delete_ids);
561 delete_pm($user_id, $delete_ids, PRIVMSGS_NO_BOX);
564 // Set messages to Unread
565 if (sizeof($unread_ids))
567 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
568 SET pm_unread = 0
569 WHERE ' . $db->sql_in_set('msg_id', $unread_ids) . "
570 AND user_id = $user_id
571 AND folder_id = " . PRIVMSGS_NO_BOX;
572 $db->sql_query($sql);
575 // mark messages as important
576 if (sizeof($important_ids))
578 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
579 SET pm_marked = 1 - pm_marked
580 WHERE folder_id = ' . PRIVMSGS_NO_BOX . "
581 AND user_id = $user_id
582 AND " . $db->sql_in_set('msg_id', $important_ids);
583 $db->sql_query($sql);
586 // Move into folder
587 $folder = array();
589 if (sizeof($move_into_folder))
591 // Determine Full Folder Action - we need the move to folder id later eventually
592 $full_folder_action = ($user->data['user_full_folder'] == FULL_FOLDER_NONE) ? ($config['full_folder_action'] - (FULL_FOLDER_NONE*(-1))) : $user->data['user_full_folder'];
594 $sql_folder = array_keys($move_into_folder);
595 if ($full_folder_action >= 0)
597 $sql_folder[] = $full_folder_action;
600 $sql = 'SELECT folder_id, pm_count
601 FROM ' . PRIVMSGS_FOLDER_TABLE . '
602 WHERE ' . $db->sql_in_set('folder_id', $sql_folder) . "
603 AND user_id = $user_id";
604 $result = $db->sql_query($sql);
606 while ($row = $db->sql_fetchrow($result))
608 $folder[(int) $row['folder_id']] = (int) $row['pm_count'];
610 $db->sql_freeresult($result);
612 unset($sql_folder);
614 if (isset($move_into_folder[PRIVMSGS_INBOX]))
616 $sql = 'SELECT COUNT(msg_id) as num_messages
617 FROM ' . PRIVMSGS_TO_TABLE . "
618 WHERE user_id = $user_id
619 AND folder_id = " . PRIVMSGS_INBOX;
620 $result = $db->sql_query($sql);
621 $folder[PRIVMSGS_INBOX] = (int) $db->sql_fetchfield('num_messages');
622 $db->sql_freeresult($result);
626 // Here we have ideally only one folder to move into
627 foreach ($move_into_folder as $folder_id => $msg_ary)
629 $dest_folder = $folder_id;
630 $full_folder_action = FULL_FOLDER_NONE;
632 // Check Message Limit - we calculate with the complete array, most of the time it is one message
633 // But we are making sure that the other way around works too (more messages in queue than allowed to be stored)
634 if ($user->data['message_limit'] && $folder[$folder_id] && ($folder[$folder_id] + sizeof($msg_ary)) > $user->data['message_limit'])
636 $full_folder_action = ($user->data['user_full_folder'] == FULL_FOLDER_NONE) ? ($config['full_folder_action'] - (FULL_FOLDER_NONE*(-1))) : $user->data['user_full_folder'];
638 // If destination folder itself is full...
639 if ($full_folder_action >= 0 && ($folder[$full_folder_action] + sizeof($msg_ary)) > $user->data['message_limit'])
641 $full_folder_action = $config['full_folder_action'] - (FULL_FOLDER_NONE*(-1));
644 // If Full Folder Action is to move to another folder, we simply adjust the destination folder
645 if ($full_folder_action >= 0)
647 $dest_folder = $full_folder_action;
649 else if ($full_folder_action == FULL_FOLDER_DELETE)
651 // Delete some messages. NOTE: Ordered by msg_id here instead of message_time!
652 $sql = 'SELECT msg_id
653 FROM ' . PRIVMSGS_TO_TABLE . "
654 WHERE user_id = $user_id
655 AND folder_id = $dest_folder
656 ORDER BY msg_id ASC";
657 $result = $db->sql_query_limit($sql, (($folder[$dest_folder] + sizeof($msg_ary)) - $user->data['message_limit']));
659 $delete_ids = array();
660 while ($row = $db->sql_fetchrow($result))
662 $delete_ids[] = $row['msg_id'];
664 $db->sql_freeresult($result);
666 $num_removed += sizeof($delete_ids);
667 delete_pm($user_id, $delete_ids, $dest_folder);
672 if ($full_folder_action == FULL_FOLDER_HOLD)
674 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
675 SET folder_id = ' . PRIVMSGS_HOLD_BOX . '
676 WHERE folder_id = ' . PRIVMSGS_NO_BOX . "
677 AND user_id = $user_id
678 AND " . $db->sql_in_set('msg_id', $msg_ary);
679 $db->sql_query($sql);
681 else
683 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
684 SET folder_id = $dest_folder, pm_new = 0
685 WHERE folder_id = " . PRIVMSGS_NO_BOX . "
686 AND user_id = $user_id
687 AND pm_new = 1
688 AND " . $db->sql_in_set('msg_id', $msg_ary);
689 $db->sql_query($sql);
691 if ($dest_folder != PRIVMSGS_INBOX)
693 $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . '
694 SET pm_count = pm_count + ' . (int) $db->sql_affectedrows() . "
695 WHERE folder_id = $dest_folder
696 AND user_id = $user_id";
697 $db->sql_query($sql);
702 if (sizeof($action_ary))
704 // Move from OUTBOX to SENTBOX
705 // We are not checking any full folder status here... SENTBOX is a special treatment (old messages get deleted)
706 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
707 SET folder_id = ' . PRIVMSGS_SENTBOX . '
708 WHERE folder_id = ' . PRIVMSGS_OUTBOX . '
709 AND ' . $db->sql_in_set('msg_id', array_keys($action_ary));
710 $db->sql_query($sql);
713 // Update new/unread count
714 update_pm_counts();
716 // Now check how many messages got not moved...
717 $sql = 'SELECT COUNT(msg_id) as num_messages
718 FROM ' . PRIVMSGS_TO_TABLE . "
719 WHERE user_id = $user_id
720 AND folder_id = " . PRIVMSGS_HOLD_BOX;
721 $result = $db->sql_query($sql);
722 $num_not_moved = (int) $db->sql_fetchfield('num_messages');
723 $db->sql_freeresult($result);
725 return array('not_moved' => $num_not_moved, 'removed' => $num_removed);
729 * Move PM from one to another folder
731 function move_pm($user_id, $message_limit, $move_msg_ids, $dest_folder, $cur_folder_id)
733 global $db, $user;
734 global $phpbb_root_path, $phpEx;
736 $num_moved = 0;
738 if (!is_array($move_msg_ids))
740 $move_msg_ids = array($move_msg_ids);
743 if (sizeof($move_msg_ids) && !in_array($dest_folder, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX)) &&
744 !in_array($cur_folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)) && $cur_folder_id != $dest_folder)
746 // We have to check the destination folder ;)
747 if ($dest_folder != PRIVMSGS_INBOX)
749 $sql = 'SELECT folder_id, folder_name, pm_count
750 FROM ' . PRIVMSGS_FOLDER_TABLE . "
751 WHERE folder_id = $dest_folder
752 AND user_id = $user_id";
753 $result = $db->sql_query($sql);
754 $row = $db->sql_fetchrow($result);
755 $db->sql_freeresult($result);
757 if (!$row)
759 trigger_error('NOT_AUTHORISED');
762 if ($message_limit && $row['pm_count'] + sizeof($move_msg_ids) > $message_limit)
764 $message = sprintf($user->lang['NOT_ENOUGH_SPACE_FOLDER'], $row['folder_name']) . '<br /><br />';
765 $message .= sprintf($user->lang['CLICK_RETURN_FOLDER'], '<a href="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=' . $row['folder_id']) . '">', '</a>', $row['folder_name']);
766 trigger_error($message);
769 else
771 $sql = 'SELECT COUNT(msg_id) as num_messages
772 FROM ' . PRIVMSGS_TO_TABLE . '
773 WHERE folder_id = ' . PRIVMSGS_INBOX . "
774 AND user_id = $user_id";
775 $result = $db->sql_query($sql);
776 $num_messages = (int) $db->sql_fetchfield('num_messages');
777 $db->sql_freeresult($result);
779 if ($message_limit && $num_messages + sizeof($move_msg_ids) > $message_limit)
781 $message = sprintf($user->lang['NOT_ENOUGH_SPACE_FOLDER'], $user->lang['PM_INBOX']) . '<br /><br />';
782 $message .= sprintf($user->lang['CLICK_RETURN_FOLDER'], '<a href="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=inbox') . '">', '</a>', $user->lang['PM_INBOX']);
783 trigger_error($message);
787 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
788 SET folder_id = $dest_folder
789 WHERE folder_id = $cur_folder_id
790 AND user_id = $user_id
791 AND " . $db->sql_in_set('msg_id', $move_msg_ids);
792 $db->sql_query($sql);
793 $num_moved = $db->sql_affectedrows();
795 // Update pm counts
796 if ($num_moved)
798 if (!in_array($cur_folder_id, array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX)))
800 $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . "
801 SET pm_count = pm_count - $num_moved
802 WHERE folder_id = $cur_folder_id
803 AND user_id = $user_id";
804 $db->sql_query($sql);
807 if ($dest_folder != PRIVMSGS_INBOX)
809 $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . "
810 SET pm_count = pm_count + $num_moved
811 WHERE folder_id = $dest_folder
812 AND user_id = $user_id";
813 $db->sql_query($sql);
817 else if (in_array($cur_folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)))
819 trigger_error('CANNOT_MOVE_SPECIAL');
822 return $num_moved;
826 * Update unread message status
828 function update_unread_status($unread, $msg_id, $user_id, $folder_id)
830 if (!$unread)
832 return;
835 global $db, $user;
837 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
838 SET pm_unread = 0
839 WHERE msg_id = $msg_id
840 AND user_id = $user_id
841 AND folder_id = $folder_id";
842 $db->sql_query($sql);
844 $sql = 'UPDATE ' . USERS_TABLE . "
845 SET user_unread_privmsg = user_unread_privmsg - 1
846 WHERE user_id = $user_id";
847 $db->sql_query($sql);
849 if ($user->data['user_id'] == $user_id)
851 $user->data['user_unread_privmsg']--;
853 // Try to cope with previous wrong conversions...
854 if ($user->data['user_unread_privmsg'] < 0)
856 $sql = 'UPDATE ' . USERS_TABLE . "
857 SET user_unread_privmsg = 0
858 WHERE user_id = $user_id";
859 $db->sql_query($sql);
861 $user->data['user_unread_privmsg'] = 0;
867 * Handle all actions possible with marked messages
869 function handle_mark_actions($user_id, $mark_action)
871 global $db, $user, $phpbb_root_path, $phpEx;
873 $msg_ids = request_var('marked_msg_id', array(0));
874 $cur_folder_id = request_var('cur_folder_id', PRIVMSGS_NO_BOX);
875 $confirm = (isset($_POST['confirm'])) ? true : false;
877 if (!sizeof($msg_ids))
879 return false;
882 switch ($mark_action)
884 case 'mark_important':
886 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
887 SET pm_marked = 1 - pm_marked
888 WHERE folder_id = $cur_folder_id
889 AND user_id = $user_id
890 AND " . $db->sql_in_set('msg_id', $msg_ids);
891 $db->sql_query($sql);
893 break;
895 case 'delete_marked':
897 if (confirm_box(true))
899 delete_pm($user_id, $msg_ids, $cur_folder_id);
901 $success_msg = (sizeof($msg_ids) == 1) ? 'MESSAGE_DELETED' : 'MESSAGES_DELETED';
902 $redirect = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=' . $cur_folder_id);
904 meta_refresh(3, $redirect);
905 trigger_error($user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_FOLDER'], '<a href="' . $redirect . '">', '</a>'));
907 else
909 $s_hidden_fields = array(
910 'cur_folder_id' => $cur_folder_id,
911 'mark_option' => 'delete_marked',
912 'submit_mark' => true,
913 'marked_msg_id' => $msg_ids
916 confirm_box(false, 'DELETE_MARKED_PM', build_hidden_fields($s_hidden_fields));
919 break;
921 default:
922 return false;
925 return true;
929 * Delete PM(s)
931 function delete_pm($user_id, $msg_ids, $folder_id)
933 global $db, $user, $phpbb_root_path, $phpEx;
935 $user_id = (int) $user_id;
936 $folder_id = (int) $folder_id;
938 if (!$user_id)
940 return false;
943 if (!is_array($msg_ids))
945 if (!$msg_ids)
947 return false;
949 $msg_ids = array($msg_ids);
952 if (!sizeof($msg_ids))
954 return false;
957 // Get PM Information for later deleting
958 $sql = 'SELECT msg_id, pm_unread, pm_new
959 FROM ' . PRIVMSGS_TO_TABLE . '
960 WHERE ' . $db->sql_in_set('msg_id', array_map('intval', $msg_ids)) . "
961 AND folder_id = $folder_id
962 AND user_id = $user_id";
963 $result = $db->sql_query($sql);
965 $delete_rows = array();
966 $num_unread = $num_new = $num_deleted = 0;
967 while ($row = $db->sql_fetchrow($result))
969 $num_unread += (int) $row['pm_unread'];
970 $num_new += (int) $row['pm_new'];
972 $delete_rows[$row['msg_id']] = 1;
974 $db->sql_freeresult($result);
975 unset($msg_ids);
977 if (!sizeof($delete_rows))
979 return false;
982 $db->sql_transaction('begin');
984 // if no one has read the message yet (meaning it is in users outbox)
985 // then mark the message as deleted...
986 if ($folder_id == PRIVMSGS_OUTBOX)
988 // Remove PM from Outbox
989 $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . "
990 WHERE user_id = $user_id AND folder_id = " . PRIVMSGS_OUTBOX . '
991 AND ' . $db->sql_in_set('msg_id', array_keys($delete_rows));
992 $db->sql_query($sql);
994 // Update PM Information for safety
995 $sql = 'UPDATE ' . PRIVMSGS_TABLE . " SET message_text = ''
996 WHERE " . $db->sql_in_set('msg_id', array_keys($delete_rows));
997 $db->sql_query($sql);
999 // Set delete flag for those intended to receive the PM
1000 // We do not remove the message actually, to retain some basic information (sent time for example)
1001 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
1002 SET pm_deleted = 1
1003 WHERE ' . $db->sql_in_set('msg_id', array_keys($delete_rows));
1004 $db->sql_query($sql);
1006 $num_deleted = $db->sql_affectedrows();
1008 else
1010 // Delete private message data
1011 $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . "
1012 WHERE user_id = $user_id
1013 AND folder_id = $folder_id
1014 AND " . $db->sql_in_set('msg_id', array_keys($delete_rows));
1015 $db->sql_query($sql);
1016 $num_deleted = $db->sql_affectedrows();
1019 // if folder id is user defined folder then decrease pm_count
1020 if (!in_array($folder_id, array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX, PRIVMSGS_NO_BOX)))
1022 $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . "
1023 SET pm_count = pm_count - $num_deleted
1024 WHERE folder_id = $folder_id";
1025 $db->sql_query($sql);
1028 // Update unread and new status field
1029 if ($num_unread || $num_new)
1031 $set_sql = ($num_unread) ? 'user_unread_privmsg = user_unread_privmsg - ' . $num_unread : '';
1033 if ($num_new)
1035 $set_sql .= ($set_sql != '') ? ', ' : '';
1036 $set_sql .= 'user_new_privmsg = user_new_privmsg - ' . $num_new;
1039 $db->sql_query('UPDATE ' . USERS_TABLE . " SET $set_sql WHERE user_id = $user_id");
1041 $user->data['user_new_privmsg'] -= $num_new;
1042 $user->data['user_unread_privmsg'] -= $num_unread;
1045 // Now we have to check which messages we can delete completely
1046 $sql = 'SELECT msg_id
1047 FROM ' . PRIVMSGS_TO_TABLE . '
1048 WHERE ' . $db->sql_in_set('msg_id', array_keys($delete_rows));
1049 $result = $db->sql_query($sql);
1051 while ($row = $db->sql_fetchrow($result))
1053 unset($delete_rows[$row['msg_id']]);
1055 $db->sql_freeresult($result);
1057 $delete_ids = array_keys($delete_rows);
1059 if (sizeof($delete_ids))
1061 // Check if there are any attachments we need to remove
1062 if (!function_exists('delete_attachments'))
1064 include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
1067 delete_attachments('message', $delete_ids, false);
1069 $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
1070 WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
1071 $db->sql_query($sql);
1074 $db->sql_transaction('commit');
1076 return true;
1080 * Rebuild message header
1082 function rebuild_header($check_ary)
1084 global $db;
1086 $address = array();
1088 foreach ($check_ary as $check_type => $address_field)
1090 // Split Addresses into users and groups
1091 preg_match_all('/:?(u|g)_([0-9]+):?/', $address_field, $match);
1093 $u = $g = array();
1094 foreach ($match[1] as $id => $type)
1096 ${$type}[] = (int) $match[2][$id];
1099 $_types = array('u', 'g');
1100 foreach ($_types as $type)
1102 if (sizeof($$type))
1104 foreach ($$type as $id)
1106 $address[$type][$id] = $check_type;
1112 return $address;
1116 * Print out/assign recipient information
1118 function write_pm_addresses($check_ary, $author_id, $plaintext = false)
1120 global $db, $user, $template, $phpbb_root_path, $phpEx;
1122 $addresses = array();
1124 foreach ($check_ary as $check_type => $address_field)
1126 if (!is_array($address_field))
1128 // Split Addresses into users and groups
1129 preg_match_all('/:?(u|g)_([0-9]+):?/', $address_field, $match);
1131 $u = $g = array();
1132 foreach ($match[1] as $id => $type)
1134 ${$type}[] = (int) $match[2][$id];
1137 else
1139 $u = $address_field['u'];
1140 $g = $address_field['g'];
1143 $address = array();
1144 if (sizeof($u))
1146 $sql = 'SELECT user_id, username, user_colour
1147 FROM ' . USERS_TABLE . '
1148 WHERE ' . $db->sql_in_set('user_id', $u);
1149 $result = $db->sql_query($sql);
1151 while ($row = $db->sql_fetchrow($result))
1153 if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
1155 if ($plaintext)
1157 $address[] = $row['username'];
1159 else
1161 $address['user'][$row['user_id']] = array('name' => $row['username'], 'colour' => $row['user_colour']);
1165 $db->sql_freeresult($result);
1168 if (sizeof($g))
1170 if ($plaintext)
1172 $sql = 'SELECT group_name, group_type
1173 FROM ' . GROUPS_TABLE . '
1174 WHERE ' . $db->sql_in_set('group_id', $g);
1175 $result = $db->sql_query($sql);
1177 while ($row = $db->sql_fetchrow($result))
1179 if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
1181 $address[] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
1184 $db->sql_freeresult($result);
1186 else
1188 $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_type, ug.user_id
1189 FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug
1190 WHERE ' . $db->sql_in_set('g.group_id', $g) . '
1191 AND g.group_id = ug.group_id
1192 AND ug.user_pending = 0';
1193 $result = $db->sql_query($sql);
1195 while ($row = $db->sql_fetchrow($result))
1197 if (!isset($address['group'][$row['group_id']]))
1199 if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
1201 $row['group_name'] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
1202 $address['group'][$row['group_id']] = array('name' => $row['group_name'], 'colour' => $row['group_colour']);
1206 if (isset($address['user'][$row['user_id']]))
1208 $address['user'][$row['user_id']]['in_group'] = $row['group_id'];
1211 $db->sql_freeresult($result);
1215 if (sizeof($address) && !$plaintext)
1217 $template->assign_var('S_' . strtoupper($check_type) . '_RECIPIENT', true);
1219 foreach ($address as $type => $adr_ary)
1221 foreach ($adr_ary as $id => $row)
1223 $tpl_ary = array(
1224 'IS_GROUP' => ($type == 'group') ? true : false,
1225 'IS_USER' => ($type == 'user') ? true : false,
1226 'UG_ID' => $id,
1227 'NAME' => $row['name'],
1228 'COLOUR' => ($row['colour']) ? '#' . $row['colour'] : '',
1229 'TYPE' => $type,
1232 if ($type == 'user')
1234 $tpl_ary = array_merge($tpl_ary, array(
1235 'U_VIEW' => get_username_string('profile', $id, $row['name'], $row['colour']),
1236 'NAME_FULL' => get_username_string('full', $id, $row['name'], $row['colour']),
1239 else
1241 $tpl_ary = array_merge($tpl_ary, array(
1242 'U_VIEW' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&amp;g=' . $id),
1246 $template->assign_block_vars($check_type . '_recipient', $tpl_ary);
1251 $addresses[$check_type] = $address;
1254 return $addresses;
1258 * Get folder status
1260 function get_folder_status($folder_id, $folder)
1262 global $db, $user, $config;
1264 if (isset($folder[$folder_id]))
1266 $folder = $folder[$folder_id];
1268 else
1270 return false;
1273 $return = array(
1274 'folder_name' => $folder['folder_name'],
1275 'cur' => $folder['num_messages'],
1276 'remaining' => ($user->data['message_limit']) ? $user->data['message_limit'] - $folder['num_messages'] : 0,
1277 'max' => $user->data['message_limit'],
1278 'percent' => ($user->data['message_limit']) ? (($user->data['message_limit'] > 0) ? round(($folder['num_messages'] / $user->data['message_limit']) * 100) : 100) : 0,
1281 $return['message'] = sprintf($user->lang['FOLDER_STATUS_MSG'], $return['percent'], $return['cur'], $return['max']);
1283 return $return;
1287 // COMPOSE MESSAGES
1291 * Submit PM
1293 function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
1295 global $db, $auth, $config, $phpEx, $template, $user, $phpbb_root_path;
1297 // We do not handle erasing pms here
1298 if ($mode == 'delete')
1300 return false;
1303 $current_time = time();
1305 // Collect some basic information about which tables and which rows to update/insert
1306 $sql_data = array();
1307 $root_level = 0;
1309 // Recipient Information
1310 $recipients = $to = $bcc = array();
1312 if ($mode != 'edit')
1314 // Build Recipient List
1315 // u|g => array($user_id => 'to'|'bcc')
1316 $_types = array('u', 'g');
1317 foreach ($_types as $ug_type)
1319 if (isset($data['address_list'][$ug_type]) && sizeof($data['address_list'][$ug_type]))
1321 foreach ($data['address_list'][$ug_type] as $id => $field)
1323 $id = (int) $id;
1325 // Do not rely on the address list being "valid"
1326 if (!$id || ($ug_type == 'u' && $id == ANONYMOUS))
1328 continue;
1331 $field = ($field == 'to') ? 'to' : 'bcc';
1332 if ($ug_type == 'u')
1334 $recipients[$id] = $field;
1336 ${$field}[] = $ug_type . '_' . $id;
1341 if (isset($data['address_list']['g']) && sizeof($data['address_list']['g']))
1343 // We need to check the PM status of group members (do they want to receive PM's?)
1344 // Only check if not a moderator or admin, since they are allowed to override this user setting
1345 $sql_allow_pm = (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) ? ' AND u.user_allow_pm = 1' : '';
1347 $sql = 'SELECT u.user_type, ug.group_id, ug.user_id
1348 FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . ' ug
1349 WHERE ' . $db->sql_in_set('ug.group_id', array_keys($data['address_list']['g'])) . '
1350 AND ug.user_pending = 0
1351 AND u.user_id = ug.user_id
1352 AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')' .
1353 $sql_allow_pm;
1354 $result = $db->sql_query($sql);
1356 while ($row = $db->sql_fetchrow($result))
1358 // Additionally, do not include the sender if he is in the group he wants to send to. ;)
1359 if ($row['user_id'] === $user->data['user_id'])
1361 continue;
1364 $field = ($data['address_list']['g'][$row['group_id']] == 'to') ? 'to' : 'bcc';
1365 $recipients[$row['user_id']] = $field;
1367 $db->sql_freeresult($result);
1370 if (!sizeof($recipients))
1372 trigger_error('NO_RECIPIENT');
1376 $db->sql_transaction('begin');
1378 $sql = '';
1380 switch ($mode)
1382 case 'reply':
1383 case 'quote':
1384 $root_level = ($data['reply_from_root_level']) ? $data['reply_from_root_level'] : $data['reply_from_msg_id'];
1386 // Set message_replied switch for this user
1387 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
1388 SET pm_replied = 1
1389 WHERE user_id = ' . $data['from_user_id'] . '
1390 AND msg_id = ' . $data['reply_from_msg_id'];
1392 // no break
1394 case 'forward':
1395 case 'post':
1396 case 'quotepost':
1397 $sql_data = array(
1398 'root_level' => $root_level,
1399 'author_id' => $data['from_user_id'],
1400 'icon_id' => $data['icon_id'],
1401 'author_ip' => $data['from_user_ip'],
1402 'message_time' => $current_time,
1403 'enable_bbcode' => $data['enable_bbcode'],
1404 'enable_smilies' => $data['enable_smilies'],
1405 'enable_magic_url' => $data['enable_urls'],
1406 'enable_sig' => $data['enable_sig'],
1407 'message_subject' => $subject,
1408 'message_text' => $data['message'],
1409 'message_attachment'=> (!empty($data['attachment_data'])) ? 1 : 0,
1410 'bbcode_bitfield' => $data['bbcode_bitfield'],
1411 'bbcode_uid' => $data['bbcode_uid'],
1412 'to_address' => implode(':', $to),
1413 'bcc_address' => implode(':', $bcc),
1414 'message_reported' => 0,
1416 break;
1418 case 'edit':
1419 $sql_data = array(
1420 'icon_id' => $data['icon_id'],
1421 'message_edit_time' => $current_time,
1422 'enable_bbcode' => $data['enable_bbcode'],
1423 'enable_smilies' => $data['enable_smilies'],
1424 'enable_magic_url' => $data['enable_urls'],
1425 'enable_sig' => $data['enable_sig'],
1426 'message_subject' => $subject,
1427 'message_text' => $data['message'],
1428 'message_attachment'=> (!empty($data['attachment_data'])) ? 1 : 0,
1429 'bbcode_bitfield' => $data['bbcode_bitfield'],
1430 'bbcode_uid' => $data['bbcode_uid']
1432 break;
1435 if (sizeof($sql_data))
1437 $query = '';
1439 if ($mode == 'post' || $mode == 'reply' || $mode == 'quote' || $mode == 'quotepost' || $mode == 'forward')
1441 $db->sql_query('INSERT INTO ' . PRIVMSGS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_data));
1442 $data['msg_id'] = $db->sql_nextid();
1444 else if ($mode == 'edit')
1446 $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
1447 SET message_edit_count = message_edit_count + 1, ' . $db->sql_build_array('UPDATE', $sql_data) . '
1448 WHERE msg_id = ' . $data['msg_id'];
1449 $db->sql_query($sql);
1453 if ($mode != 'edit')
1455 if ($sql)
1457 $db->sql_query($sql);
1459 unset($sql);
1461 $sql_ary = array();
1462 foreach ($recipients as $user_id => $type)
1464 $sql_ary[] = array(
1465 'msg_id' => (int) $data['msg_id'],
1466 'user_id' => (int) $user_id,
1467 'author_id' => (int) $data['from_user_id'],
1468 'folder_id' => PRIVMSGS_NO_BOX,
1469 'pm_new' => 1,
1470 'pm_unread' => 1,
1471 'pm_forwarded' => ($mode == 'forward') ? 1 : 0
1475 $db->sql_multi_insert(PRIVMSGS_TO_TABLE, $sql_ary);
1477 $sql = 'UPDATE ' . USERS_TABLE . '
1478 SET user_new_privmsg = user_new_privmsg + 1, user_unread_privmsg = user_unread_privmsg + 1, user_last_privmsg = ' . time() . '
1479 WHERE ' . $db->sql_in_set('user_id', array_keys($recipients));
1480 $db->sql_query($sql);
1482 // Put PM into outbox
1483 if ($put_in_outbox)
1485 $db->sql_query('INSERT INTO ' . PRIVMSGS_TO_TABLE . ' ' . $db->sql_build_array('INSERT', array(
1486 'msg_id' => (int) $data['msg_id'],
1487 'user_id' => (int) $data['from_user_id'],
1488 'author_id' => (int) $data['from_user_id'],
1489 'folder_id' => PRIVMSGS_OUTBOX,
1490 'pm_new' => 0,
1491 'pm_unread' => 0,
1492 'pm_forwarded' => ($mode == 'forward') ? 1 : 0))
1497 // Set user last post time
1498 if ($mode == 'reply' || $mode == 'quote' || $mode == 'quotepost' || $mode == 'forward' || $mode == 'post')
1500 $sql = 'UPDATE ' . USERS_TABLE . "
1501 SET user_lastpost_time = $current_time
1502 WHERE user_id = " . $data['from_user_id'];
1503 $db->sql_query($sql);
1506 // Submit Attachments
1507 if (!empty($data['attachment_data']) && $data['msg_id'] && in_array($mode, array('post', 'reply', 'quote', 'quotepost', 'edit', 'forward')))
1509 $space_taken = $files_added = 0;
1510 $orphan_rows = array();
1512 foreach ($data['attachment_data'] as $pos => $attach_row)
1514 $orphan_rows[(int) $attach_row['attach_id']] = array();
1517 if (sizeof($orphan_rows))
1519 $sql = 'SELECT attach_id, filesize, physical_filename
1520 FROM ' . ATTACHMENTS_TABLE . '
1521 WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan_rows)) . '
1522 AND in_message = 1
1523 AND is_orphan = 1
1524 AND poster_id = ' . $user->data['user_id'];
1525 $result = $db->sql_query($sql);
1527 $orphan_rows = array();
1528 while ($row = $db->sql_fetchrow($result))
1530 $orphan_rows[$row['attach_id']] = $row;
1532 $db->sql_freeresult($result);
1535 foreach ($data['attachment_data'] as $pos => $attach_row)
1537 if ($attach_row['is_orphan'] && !isset($orphan_rows[$attach_row['attach_id']]))
1539 continue;
1542 if (!$attach_row['is_orphan'])
1544 // update entry in db if attachment already stored in db and filespace
1545 $sql = 'UPDATE ' . ATTACHMENTS_TABLE . "
1546 SET attach_comment = '" . $db->sql_escape($attach_row['attach_comment']) . "'
1547 WHERE attach_id = " . (int) $attach_row['attach_id'] . '
1548 AND is_orphan = 0';
1549 $db->sql_query($sql);
1551 else
1553 // insert attachment into db
1554 if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . utf8_basename($orphan_rows[$attach_row['attach_id']]['physical_filename'])))
1556 continue;
1559 $space_taken += $orphan_rows[$attach_row['attach_id']]['filesize'];
1560 $files_added++;
1562 $attach_sql = array(
1563 'post_msg_id' => $data['msg_id'],
1564 'topic_id' => 0,
1565 'is_orphan' => 0,
1566 'poster_id' => $data['from_user_id'],
1567 'attach_comment' => $attach_row['attach_comment'],
1570 $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $attach_sql) . '
1571 WHERE attach_id = ' . $attach_row['attach_id'] . '
1572 AND is_orphan = 1
1573 AND poster_id = ' . $user->data['user_id'];
1574 $db->sql_query($sql);
1578 if ($space_taken && $files_added)
1580 set_config_count('upload_dir_size', $space_taken, true);
1581 set_config_count('num_files', $files_added, true);
1585 // Delete draft if post was loaded...
1586 $draft_id = request_var('draft_loaded', 0);
1587 if ($draft_id)
1589 $sql = 'DELETE FROM ' . DRAFTS_TABLE . "
1590 WHERE draft_id = $draft_id
1591 AND user_id = " . $data['from_user_id'];
1592 $db->sql_query($sql);
1595 $db->sql_transaction('commit');
1597 // Send Notifications
1598 if ($mode != 'edit')
1600 pm_notification($mode, $data['from_username'], $recipients, $subject, $data['message']);
1603 return $data['msg_id'];
1607 * PM Notification
1609 function pm_notification($mode, $author, $recipients, $subject, $message)
1611 global $db, $user, $config, $phpbb_root_path, $phpEx, $auth;
1613 $subject = censor_text($subject);
1615 unset($recipients[ANONYMOUS], $recipients[$user->data['user_id']]);
1617 if (!sizeof($recipients))
1619 return;
1622 // Get banned User ID's
1623 $sql = 'SELECT ban_userid
1624 FROM ' . BANLIST_TABLE . '
1625 WHERE ' . $db->sql_in_set('ban_userid', array_map('intval', array_keys($recipients))) . '
1626 AND ban_exclude = 0';
1627 $result = $db->sql_query($sql);
1629 while ($row = $db->sql_fetchrow($result))
1631 unset($recipients[$row['ban_userid']]);
1633 $db->sql_freeresult($result);
1635 if (!sizeof($recipients))
1637 return;
1640 $sql = 'SELECT user_id, username, user_email, user_lang, user_notify_pm, user_notify_type, user_jabber
1641 FROM ' . USERS_TABLE . '
1642 WHERE ' . $db->sql_in_set('user_id', array_map('intval', array_keys($recipients)));
1643 $result = $db->sql_query($sql);
1645 $msg_list_ary = array();
1646 while ($row = $db->sql_fetchrow($result))
1648 if ($row['user_notify_pm'] == 1 && trim($row['user_email']))
1650 $msg_list_ary[] = array(
1651 'method' => $row['user_notify_type'],
1652 'email' => $row['user_email'],
1653 'jabber' => $row['user_jabber'],
1654 'name' => $row['username'],
1655 'lang' => $row['user_lang']
1659 $db->sql_freeresult($result);
1661 if (!sizeof($msg_list_ary))
1663 return;
1666 include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
1667 $messenger = new messenger();
1669 foreach ($msg_list_ary as $pos => $addr)
1671 $messenger->template('privmsg_notify', $addr['lang']);
1673 $messenger->to($addr['email'], $addr['name']);
1674 $messenger->im($addr['jabber'], $addr['name']);
1676 $messenger->assign_vars(array(
1677 'SUBJECT' => htmlspecialchars_decode($subject),
1678 'AUTHOR_NAME' => htmlspecialchars_decode($author),
1679 'USERNAME' => htmlspecialchars_decode($addr['name']),
1681 'U_INBOX' => generate_board_url() . "/ucp.$phpEx?i=pm&folder=inbox")
1684 $messenger->send($addr['method']);
1686 unset($msg_list_ary);
1688 $messenger->save_queue();
1690 unset($messenger);
1694 * Display Message History
1696 function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode = false)
1698 global $db, $user, $config, $template, $phpbb_root_path, $phpEx, $auth, $bbcode;
1700 // Select all receipts and the author from the pm we currently view, to only display their pm-history
1701 $sql = 'SELECT author_id, user_id
1702 FROM ' . PRIVMSGS_TO_TABLE . "
1703 WHERE msg_id = $msg_id
1704 AND folder_id <> " . PRIVMSGS_HOLD_BOX;
1705 $result = $db->sql_query($sql);
1707 $recipients = array();
1708 while ($row = $db->sql_fetchrow($result))
1710 $recipients[] = (int) $row['user_id'];
1711 $recipients[] = (int) $row['author_id'];
1713 $db->sql_freeresult($result);
1714 $recipients = array_unique($recipients);
1716 // Get History Messages (could be newer)
1717 $sql = 'SELECT t.*, p.*, u.*
1718 FROM ' . PRIVMSGS_TABLE . ' p, ' . PRIVMSGS_TO_TABLE . ' t, ' . USERS_TABLE . ' u
1719 WHERE t.msg_id = p.msg_id
1720 AND p.author_id = u.user_id
1721 AND t.folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
1722 AND ' . $db->sql_in_set('t.author_id', $recipients, false, true) . "
1723 AND t.user_id = $user_id";
1725 // We no longer need those.
1726 unset($recipients);
1728 if (!$message_row['root_level'])
1730 $sql .= " AND (p.root_level = $msg_id OR (p.root_level = 0 AND p.msg_id = $msg_id))";
1732 else
1734 $sql .= " AND (p.root_level = " . $message_row['root_level'] . ' OR p.msg_id = ' . $message_row['root_level'] . ')';
1736 $sql .= ' ORDER BY p.message_time DESC';
1738 $result = $db->sql_query($sql);
1739 $row = $db->sql_fetchrow($result);
1741 if (!$row)
1743 $db->sql_freeresult($result);
1744 return false;
1747 $rowset = array();
1748 $bbcode_bitfield = '';
1749 $folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm') . '&amp;folder=';
1753 $folder_id = (int) $row['folder_id'];
1755 $row['folder'][] = (isset($folder[$folder_id])) ? '<a href="' . $folder_url . $folder_id . '">' . $folder[$folder_id]['folder_name'] . '</a>' : $user->lang['UNKNOWN_FOLDER'];
1757 if (isset($rowset[$row['msg_id']]))
1759 $rowset[$row['msg_id']]['folder'][] = (isset($folder[$folder_id])) ? '<a href="' . $folder_url . $folder_id . '">' . $folder[$folder_id]['folder_name'] . '</a>' : $user->lang['UNKNOWN_FOLDER'];
1761 else
1763 $rowset[$row['msg_id']] = $row;
1764 $bbcode_bitfield = $bbcode_bitfield | base64_decode($row['bbcode_bitfield']);
1767 while ($row = $db->sql_fetchrow($result));
1768 $db->sql_freeresult($result);
1770 $title = $row['message_subject'];
1772 if (sizeof($rowset) == 1 && !$in_post_mode)
1774 return false;
1777 // Instantiate BBCode class
1778 if ((empty($bbcode) || $bbcode === false) && $bbcode_bitfield !== '')
1780 if (!class_exists('bbcode'))
1782 include($phpbb_root_path . 'includes/bbcode.' . $phpEx);
1784 $bbcode = new bbcode(base64_encode($bbcode_bitfield));
1787 $title = censor_text($title);
1789 $url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm');
1790 $next_history_pm = $previous_history_pm = $prev_id = 0;
1792 // Re-order rowset to be able to get the next/prev message rows...
1793 $rowset = array_values($rowset);
1795 for ($i = 0, $size = sizeof($rowset); $i < $size; $i++)
1797 $row = &$rowset[$i];
1798 $id = (int) $row['msg_id'];
1800 $author_id = $row['author_id'];
1801 $folder_id = (int) $row['folder_id'];
1803 $subject = $row['message_subject'];
1804 $message = $row['message_text'];
1806 $message = censor_text($message);
1808 $decoded_message = false;
1810 if ($in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS)
1812 $decoded_message = $message;
1813 decode_message($decoded_message, $row['bbcode_uid']);
1815 $decoded_message = bbcode_nl2br($decoded_message);
1818 if ($row['bbcode_bitfield'])
1820 $bbcode->bbcode_second_pass($message, $row['bbcode_uid'], $row['bbcode_bitfield']);
1823 $message = bbcode_nl2br($message);
1824 $message = smiley_text($message, !$row['enable_smilies']);
1826 $subject = censor_text($subject);
1828 if ($id == $msg_id)
1830 $next_history_pm = (isset($rowset[$i + 1])) ? (int) $rowset[$i + 1]['msg_id'] : 0;
1831 $previous_history_pm = $prev_id;
1834 $template->assign_block_vars('history_row', array(
1835 'MESSAGE_AUTHOR_QUOTE' => (($decoded_message) ? addslashes(get_username_string('username', $author_id, $row['username'], $row['user_colour'], $row['username'])) : ''),
1836 'MESSAGE_AUTHOR_FULL' => get_username_string('full', $author_id, $row['username'], $row['user_colour'], $row['username']),
1837 'MESSAGE_AUTHOR_COLOUR' => get_username_string('colour', $author_id, $row['username'], $row['user_colour'], $row['username']),
1838 'MESSAGE_AUTHOR' => get_username_string('username', $author_id, $row['username'], $row['user_colour'], $row['username']),
1839 'U_MESSAGE_AUTHOR' => get_username_string('profile', $author_id, $row['username'], $row['user_colour'], $row['username']),
1841 'SUBJECT' => $subject,
1842 'SENT_DATE' => $user->format_date($row['message_time']),
1843 'MESSAGE' => $message,
1844 'FOLDER' => implode(', ', $row['folder']),
1845 'DECODED_MESSAGE' => $decoded_message,
1847 'S_CURRENT_MSG' => ($row['msg_id'] == $msg_id),
1848 'S_AUTHOR_DELETED' => ($author_id == ANONYMOUS) ? true : false,
1849 'S_IN_POST_MODE' => $in_post_mode,
1851 'MSG_ID' => $row['msg_id'],
1852 'U_VIEW_MESSAGE' => "$url&amp;f=$folder_id&amp;p=" . $row['msg_id'],
1853 'U_QUOTE' => (!$in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS) ? "$url&amp;mode=compose&amp;action=quote&amp;f=" . $folder_id . "&amp;p=" . $row['msg_id'] : '',
1854 'U_POST_REPLY_PM' => ($author_id != $user->data['user_id'] && $author_id != ANONYMOUS && $auth->acl_get('u_sendpm')) ? "$url&amp;mode=compose&amp;action=reply&amp;f=$folder_id&amp;p=" . $row['msg_id'] : '')
1856 unset($rowset[$i]);
1857 $prev_id = $id;
1860 $template->assign_vars(array(
1861 'QUOTE_IMG' => $user->img('icon_post_quote', $user->lang['REPLY_WITH_QUOTE']),
1862 'HISTORY_TITLE' => $title,
1864 'U_VIEW_NEXT_HISTORY' => ($next_history_pm) ? "$url&amp;p=" . $next_history_pm : '',
1865 'U_VIEW_PREVIOUS_HISTORY' => ($previous_history_pm) ? "$url&amp;p=" . $previous_history_pm : '',
1868 return true;
1872 * Set correct users max messages in PM folder.
1873 * If several group memberships define different amount of messages, the highest will be chosen.
1875 function set_user_message_limit()
1877 global $user, $db, $config;
1879 // Get maximum about from user memberships - if it is 0, there is no limit set and we use the maximum value within the config.
1880 $sql = 'SELECT MAX(g.group_message_limit) as max_message_limit
1881 FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug
1882 WHERE ug.user_id = ' . $user->data['user_id'] . '
1883 AND ug.user_pending = 0
1884 AND ug.group_id = g.group_id';
1885 $result = $db->sql_query($sql);
1886 $message_limit = (int) $db->sql_fetchfield('max_message_limit');
1887 $db->sql_freeresult($result);
1889 $user->data['message_limit'] = (!$message_limit) ? $config['pm_max_msgs'] : $message_limit;
1893 * Generates an array of coloured recipient names from a list of PMs - (groups & users)
1895 * @param array $pm_by_id An array of rows from PRIVMSGS_TABLE, keys are the msg_ids.
1897 * @return array 2D Array: array(msg_id => array('username or group string', ...), ...)
1898 * Usernames are generated with {@link get_username_string get_username_string}
1899 * Groups are coloured and have a link to the membership page
1901 function get_recipient_strings($pm_by_id)
1903 global $db, $phpbb_root_path, $phpEx, $user;
1905 $address_list = $recipient_list = $address = array();
1907 $_types = array('u', 'g');
1909 foreach ($pm_by_id as $message_id => $row)
1911 $address[$message_id] = rebuild_header(array('to' => $row['to_address'], 'bcc' => $row['bcc_address']));
1913 foreach ($_types as $ug_type)
1915 if (isset($address[$message_id][$ug_type]) && sizeof($address[$message_id][$ug_type]))
1917 foreach ($address[$message_id][$ug_type] as $ug_id => $in_to)
1919 $recipient_list[$ug_type][$ug_id] = array('name' => $user->lang['NA'], 'colour' => '');
1925 foreach ($_types as $ug_type)
1927 if (!empty($recipient_list[$ug_type]))
1929 if ($ug_type == 'u')
1931 $sql = 'SELECT user_id as id, username as name, user_colour as colour
1932 FROM ' . USERS_TABLE . '
1933 WHERE ';
1935 else
1937 $sql = 'SELECT group_id as id, group_name as name, group_colour as colour, group_type
1938 FROM ' . GROUPS_TABLE . '
1939 WHERE ';
1941 $sql .= $db->sql_in_set(($ug_type == 'u') ? 'user_id' : 'group_id', array_map('intval', array_keys($recipient_list[$ug_type])));
1943 $result = $db->sql_query($sql);
1945 while ($row = $db->sql_fetchrow($result))
1947 if ($ug_type == 'g')
1949 $row['name'] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['name']] : $row['name'];
1952 $recipient_list[$ug_type][$row['id']] = array('name' => $row['name'], 'colour' => $row['colour']);
1954 $db->sql_freeresult($result);
1958 foreach ($address as $message_id => $adr_ary)
1960 foreach ($adr_ary as $type => $id_ary)
1962 foreach ($id_ary as $ug_id => $_id)
1964 if ($type == 'u')
1966 $address_list[$message_id][] = get_username_string('full', $ug_id, $recipient_list[$type][$ug_id]['name'], $recipient_list[$type][$ug_id]['colour']);
1968 else
1970 $user_colour = ($recipient_list[$type][$ug_id]['colour']) ? ' style="font-weight: bold; color:#' . $recipient_list[$type][$ug_id]['colour'] . '"' : '';
1971 $link = '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&amp;g=' . $ug_id) . '"' . $user_colour . '>';
1972 $address_list[$message_id][] = $link . $recipient_list[$type][$ug_id]['name'] . (($link) ? '</a>' : '');
1978 return $address_list;