Verzeichnisstruktur phpBB-3.1.0
- Veröffentlicht
- 27.10.2014
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
functions_privmsgs.php
0001 <?php
0002 /**
0003 *
0004 * This file is part of the phpBB Forum Software package.
0005 *
0006 * @copyright (c) phpBB Limited <https://www.phpbb.com>
0007 * @license GNU General Public License, version 2 (GPL-2.0)
0008 *
0009 * For full copyright and license information, please see
0010 * the docs/CREDITS.txt file.
0011 *
0012 */
0013
0014 /**
0015 */
0016 if (!defined('IN_PHPBB'))
0017 {
0018 exit;
0019 }
0020
0021 /*
0022 Ability to simply add own rules by doing three things:
0023 1) Add an appropriate constant
0024 2) Add a new check array to the global_privmsgs_rules variable and the condition array (if one is required)
0025 3) Implement the rule logic in the check_rule() function
0026 4) Add a new language variable to ucp.php
0027
0028 The user is then able to select the new rule. It will be checked against and handled as specified.
0029 To add new actions (yes, checks can be added here too) to the rule management, the core code has to be modified.
0030 */
0031
0032 define('RULE_IS_LIKE', 1); // Is Like
0033 define('RULE_IS_NOT_LIKE', 2); // Is Not Like
0034 define('RULE_IS', 3); // Is
0035 define('RULE_IS_NOT', 4); // Is Not
0036 define('RULE_BEGINS_WITH', 5); // Begins with
0037 define('RULE_ENDS_WITH', 6); // Ends with
0038 define('RULE_IS_FRIEND', 7); // Is Friend
0039 define('RULE_IS_FOE', 8); // Is Foe
0040 define('RULE_IS_USER', 9); // Is User
0041 define('RULE_IS_GROUP', 10); // Is In Usergroup
0042 define('RULE_ANSWERED', 11); // Answered
0043 define('RULE_FORWARDED', 12); // Forwarded
0044 define('RULE_TO_GROUP', 14); // Usergroup
0045 define('RULE_TO_ME', 15); // Me
0046
0047 define('ACTION_PLACE_INTO_FOLDER', 1);
0048 define('ACTION_MARK_AS_READ', 2);
0049 define('ACTION_MARK_AS_IMPORTANT', 3);
0050 define('ACTION_DELETE_MESSAGE', 4);
0051
0052 define('CHECK_SUBJECT', 1);
0053 define('CHECK_SENDER', 2);
0054 define('CHECK_MESSAGE', 3);
0055 define('CHECK_STATUS', 4);
0056 define('CHECK_TO', 5);
0057
0058 /**
0059 * Global private message rules
0060 * These rules define what to do if a rule is hit
0061 */
0062 $global_privmsgs_rules = array(
0063 CHECK_SUBJECT => array(
0064 RULE_IS_LIKE => array('check0' => 'message_subject'),
0065 RULE_IS_NOT_LIKE => array('check0' => 'message_subject'),
0066 RULE_IS => array('check0' => 'message_subject'),
0067 RULE_IS_NOT => array('check0' => 'message_subject'),
0068 RULE_BEGINS_WITH => array('check0' => 'message_subject'),
0069 RULE_ENDS_WITH => array('check0' => 'message_subject'),
0070 ),
0071
0072 CHECK_SENDER => array(
0073 RULE_IS_LIKE => array('check0' => 'username'),
0074 RULE_IS_NOT_LIKE => array('check0' => 'username'),
0075 RULE_IS => array('check0' => 'username'),
0076 RULE_IS_NOT => array('check0' => 'username'),
0077 RULE_BEGINS_WITH => array('check0' => 'username'),
0078 RULE_ENDS_WITH => array('check0' => 'username'),
0079 RULE_IS_FRIEND => array('check0' => 'friend'),
0080 RULE_IS_FOE => array('check0' => 'foe'),
0081 RULE_IS_USER => array('check0' => 'author_id'),
0082 RULE_IS_GROUP => array('check0' => 'author_in_group'),
0083 ),
0084
0085 CHECK_MESSAGE => array(
0086 RULE_IS_LIKE => array('check0' => 'message_text'),
0087 RULE_IS_NOT_LIKE => array('check0' => 'message_text'),
0088 RULE_IS => array('check0' => 'message_text'),
0089 RULE_IS_NOT => array('check0' => 'message_text'),
0090 ),
0091
0092 CHECK_STATUS => array(
0093 RULE_ANSWERED => array('check0' => 'pm_replied'),
0094 RULE_FORWARDED => array('check0' => 'pm_forwarded'),
0095 ),
0096
0097 CHECK_TO => array(
0098 RULE_TO_GROUP => array('check0' => 'to', 'check1' => 'bcc', 'check2' => 'user_in_group'),
0099 RULE_TO_ME => array('check0' => 'to', 'check1' => 'bcc'),
0100 )
0101 );
0102
0103 /**
0104 * This is for defining which condition fields to show for which Rule
0105 */
0106 $global_rule_conditions = array(
0107 RULE_IS_LIKE => 'text',
0108 RULE_IS_NOT_LIKE => 'text',
0109 RULE_IS => 'text',
0110 RULE_IS_NOT => 'text',
0111 RULE_BEGINS_WITH => 'text',
0112 RULE_ENDS_WITH => 'text',
0113 RULE_IS_USER => 'user',
0114 RULE_IS_GROUP => 'group'
0115 );
0116
0117 /**
0118 * Get all folder
0119 */
0120 function get_folder($user_id, $folder_id = false)
0121 {
0122 global $db, $user, $template;
0123 global $phpbb_root_path, $phpEx;
0124
0125 $folder = array();
0126
0127 // Get folder information
0128 $sql = 'SELECT folder_id, COUNT(msg_id) as num_messages, SUM(pm_unread) as num_unread
0129 FROM ' . PRIVMSGS_TO_TABLE . "
0130 WHERE user_id = $user_id
0131 AND folder_id <> " . PRIVMSGS_NO_BOX . '
0132 GROUP BY folder_id';
0133 $result = $db->sql_query($sql);
0134
0135 $num_messages = $num_unread = array();
0136 while ($row = $db->sql_fetchrow($result))
0137 {
0138 $num_messages[(int) $row['folder_id']] = $row['num_messages'];
0139 $num_unread[(int) $row['folder_id']] = $row['num_unread'];
0140 }
0141 $db->sql_freeresult($result);
0142
0143 // Make sure the default boxes are defined
0144 $available_folder = array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX);
0145
0146 foreach ($available_folder as $default_folder)
0147 {
0148 if (!isset($num_messages[$default_folder]))
0149 {
0150 $num_messages[$default_folder] = 0;
0151 }
0152
0153 if (!isset($num_unread[$default_folder]))
0154 {
0155 $num_unread[$default_folder] = 0;
0156 }
0157 }
0158
0159 // Adjust unread status for outbox
0160 $num_unread[PRIVMSGS_OUTBOX] = $num_messages[PRIVMSGS_OUTBOX];
0161
0162 $folder[PRIVMSGS_INBOX] = array(
0163 'folder_name' => $user->lang['PM_INBOX'],
0164 'num_messages' => $num_messages[PRIVMSGS_INBOX],
0165 'unread_messages' => $num_unread[PRIVMSGS_INBOX]
0166 );
0167
0168 // Custom Folder
0169 $sql = 'SELECT folder_id, folder_name, pm_count
0170 FROM ' . PRIVMSGS_FOLDER_TABLE . "
0171 WHERE user_id = $user_id";
0172 $result = $db->sql_query($sql);
0173
0174 while ($row = $db->sql_fetchrow($result))
0175 {
0176 $folder[$row['folder_id']] = array(
0177 'folder_name' => $row['folder_name'],
0178 'num_messages' => $row['pm_count'],
0179 'unread_messages' => ((isset($num_unread[$row['folder_id']])) ? $num_unread[$row['folder_id']] : 0)
0180 );
0181 }
0182 $db->sql_freeresult($result);
0183
0184 $folder[PRIVMSGS_OUTBOX] = array(
0185 'folder_name' => $user->lang['PM_OUTBOX'],
0186 'num_messages' => $num_messages[PRIVMSGS_OUTBOX],
0187 'unread_messages' => $num_unread[PRIVMSGS_OUTBOX]
0188 );
0189
0190 $folder[PRIVMSGS_SENTBOX] = array(
0191 'folder_name' => $user->lang['PM_SENTBOX'],
0192 'num_messages' => $num_messages[PRIVMSGS_SENTBOX],
0193 'unread_messages' => $num_unread[PRIVMSGS_SENTBOX]
0194 );
0195
0196 // Define Folder Array for template designers (and for making custom folders usable by the template too)
0197 foreach ($folder as $f_id => $folder_ary)
0198 {
0199 $folder_id_name = ($f_id == PRIVMSGS_INBOX) ? 'inbox' : (($f_id == PRIVMSGS_OUTBOX) ? 'outbox' : 'sentbox');
0200
0201 $template->assign_block_vars('folder', array(
0202 'FOLDER_ID' => $f_id,
0203 'FOLDER_NAME' => $folder_ary['folder_name'],
0204 'NUM_MESSAGES' => $folder_ary['num_messages'],
0205 'UNREAD_MESSAGES' => $folder_ary['unread_messages'],
0206
0207 'U_FOLDER' => ($f_id > 0) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $f_id) : append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $folder_id_name),
0208
0209 'S_CUR_FOLDER' => ($f_id === $folder_id) ? true : false,
0210 'S_UNREAD_MESSAGES' => ($folder_ary['unread_messages']) ? true : false,
0211 'S_CUSTOM_FOLDER' => ($f_id > 0) ? true : false)
0212 );
0213 }
0214
0215 if ($folder_id !== false && $folder_id !== PRIVMSGS_HOLD_BOX && !isset($folder[$folder_id]))
0216 {
0217 trigger_error('UNKNOWN_FOLDER');
0218 }
0219
0220 return $folder;
0221 }
0222
0223 /**
0224 * Delete Messages From Sentbox
0225 * we are doing this here because this saves us a bunch of checks and queries
0226 */
0227 function clean_sentbox($num_sentbox_messages)
0228 {
0229 global $db, $user, $config;
0230
0231 // Check Message Limit
0232 if ($user->data['message_limit'] && $num_sentbox_messages > $user->data['message_limit'])
0233 {
0234 // Delete old messages
0235 $sql = 'SELECT t.msg_id
0236 FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p
0237 WHERE t.msg_id = p.msg_id
0238 AND t.user_id = ' . $user->data['user_id'] . '
0239 AND t.folder_id = ' . PRIVMSGS_SENTBOX . '
0240 ORDER BY p.message_time ASC';
0241 $result = $db->sql_query_limit($sql, ($num_sentbox_messages - $user->data['message_limit']));
0242
0243 $delete_ids = array();
0244 while ($row = $db->sql_fetchrow($result))
0245 {
0246 $delete_ids[] = $row['msg_id'];
0247 }
0248 $db->sql_freeresult($result);
0249 delete_pm($user->data['user_id'], $delete_ids, PRIVMSGS_SENTBOX);
0250 }
0251 }
0252
0253 /**
0254 * Check Rule against Message Information
0255 */
0256 function check_rule(&$rules, &$rule_row, &$message_row, $user_id)
0257 {
0258 global $user, $config;
0259
0260 if (!isset($rules[$rule_row['rule_check']][$rule_row['rule_connection']]))
0261 {
0262 return false;
0263 }
0264
0265 $check_ary = $rules[$rule_row['rule_check']][$rule_row['rule_connection']];
0266
0267 $result = false;
0268
0269 $check0 = $message_row[$check_ary['check0']];
0270
0271 switch ($rule_row['rule_connection'])
0272 {
0273 case RULE_IS_LIKE:
0274 $result = preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0);
0275 break;
0276
0277 case RULE_IS_NOT_LIKE:
0278 $result = !preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0);
0279 break;
0280
0281 case RULE_IS:
0282 $result = ($check0 == $rule_row['rule_string']);
0283 break;
0284
0285 case RULE_IS_NOT:
0286 $result = ($check0 != $rule_row['rule_string']);
0287 break;
0288
0289 case RULE_BEGINS_WITH:
0290 $result = preg_match("/^" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0);
0291 break;
0292
0293 case RULE_ENDS_WITH:
0294 $result = preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '$/i', $check0);
0295 break;
0296
0297 case RULE_IS_FRIEND:
0298 case RULE_IS_FOE:
0299 case RULE_ANSWERED:
0300 case RULE_FORWARDED:
0301 $result = ($check0 == 1);
0302 break;
0303
0304 case RULE_IS_USER:
0305 $result = ($check0 == $rule_row['rule_user_id']);
0306 break;
0307
0308 case RULE_IS_GROUP:
0309 $result = in_array($rule_row['rule_group_id'], $check0);
0310 break;
0311
0312 case RULE_TO_GROUP:
0313 $result = (in_array('g_' . $message_row[$check_ary['check2']], $check0) || in_array('g_' . $message_row[$check_ary['check2']], $message_row[$check_ary['check1']]));
0314 break;
0315
0316 case RULE_TO_ME:
0317 $result = (in_array('u_' . $user_id, $check0) || in_array('u_' . $user_id, $message_row[$check_ary['check1']]));
0318 break;
0319 }
0320
0321 if (!$result)
0322 {
0323 return false;
0324 }
0325
0326 switch ($rule_row['rule_action'])
0327 {
0328 case ACTION_PLACE_INTO_FOLDER:
0329 return array('action' => $rule_row['rule_action'], 'folder_id' => $rule_row['rule_folder_id']);
0330 break;
0331
0332 case ACTION_MARK_AS_READ:
0333 case ACTION_MARK_AS_IMPORTANT:
0334 return array('action' => $rule_row['rule_action'], 'pm_unread' => $message_row['pm_unread'], 'pm_marked' => $message_row['pm_marked']);
0335 break;
0336
0337 case ACTION_DELETE_MESSAGE:
0338 global $db, $auth;
0339
0340 // Check for admins/mods - users are not allowed to remove those messages...
0341 // We do the check here to make sure the data we use is consistent
0342 $sql = 'SELECT user_id, user_type, user_permissions
0343 FROM ' . USERS_TABLE . '
0344 WHERE user_id = ' . (int) $message_row['author_id'];
0345 $result = $db->sql_query($sql);
0346 $userdata = $db->sql_fetchrow($result);
0347 $db->sql_freeresult($result);
0348
0349 $auth2 = new \phpbb\auth\auth();
0350 $auth2->acl($userdata);
0351
0352 if (!$auth2->acl_get('a_') && !$auth2->acl_get('m_') && !$auth2->acl_getf_global('m_'))
0353 {
0354 return array('action' => $rule_row['rule_action'], 'pm_unread' => $message_row['pm_unread'], 'pm_marked' => $message_row['pm_marked']);
0355 }
0356
0357 return false;
0358 break;
0359
0360 default:
0361 return false;
0362 }
0363
0364 return false;
0365 }
0366
0367 /**
0368 * Update user PM count
0369 */
0370 function update_pm_counts()
0371 {
0372 global $user, $db;
0373
0374 // Update unread count
0375 $sql = 'SELECT COUNT(msg_id) as num_messages
0376 FROM ' . PRIVMSGS_TO_TABLE . '
0377 WHERE pm_unread = 1
0378 AND folder_id <> ' . PRIVMSGS_OUTBOX . '
0379 AND user_id = ' . $user->data['user_id'];
0380 $result = $db->sql_query($sql);
0381 $user->data['user_unread_privmsg'] = (int) $db->sql_fetchfield('num_messages');
0382 $db->sql_freeresult($result);
0383
0384 // Update new pm count
0385 $sql = 'SELECT COUNT(msg_id) as num_messages
0386 FROM ' . PRIVMSGS_TO_TABLE . '
0387 WHERE pm_new = 1
0388 AND folder_id IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
0389 AND user_id = ' . $user->data['user_id'];
0390 $result = $db->sql_query($sql);
0391 $user->data['user_new_privmsg'] = (int) $db->sql_fetchfield('num_messages');
0392 $db->sql_freeresult($result);
0393
0394 $db->sql_query('UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array(
0395 'user_unread_privmsg' => (int) $user->data['user_unread_privmsg'],
0396 'user_new_privmsg' => (int) $user->data['user_new_privmsg'],
0397 )) . ' WHERE user_id = ' . $user->data['user_id']);
0398
0399 // Ok, here we need to repair something, other boxes than privmsgs_no_box and privmsgs_hold_box should not carry the pm_new flag.
0400 if (!$user->data['user_new_privmsg'])
0401 {
0402 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
0403 SET pm_new = 0
0404 WHERE pm_new = 1
0405 AND folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
0406 AND user_id = ' . $user->data['user_id'];
0407 $db->sql_query($sql);
0408 }
0409 }
0410
0411 /**
0412 * Place new messages into appropriate folder
0413 */
0414 function place_pm_into_folder(&$global_privmsgs_rules, $release = false)
0415 {
0416 global $db, $user, $config;
0417
0418 if (!$user->data['user_new_privmsg'])
0419 {
0420 return array('not_moved' => 0, 'removed' => 0);
0421 }
0422
0423 $user_message_rules = (int) $user->data['user_message_rules'];
0424 $user_id = (int) $user->data['user_id'];
0425
0426 $action_ary = $move_into_folder = array();
0427 $num_removed = 0;
0428
0429 // Newly processing on-hold messages
0430 if ($release)
0431 {
0432 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
0433 SET folder_id = ' . PRIVMSGS_NO_BOX . '
0434 WHERE folder_id = ' . PRIVMSGS_HOLD_BOX . "
0435 AND user_id = $user_id";
0436 $db->sql_query($sql);
0437 }
0438
0439 // Get those messages not yet placed into any box
0440 $retrieve_sql = 'SELECT t.*, p.*, u.username, u.user_id, u.group_id
0441 FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p, ' . USERS_TABLE . " u
0442 WHERE t.user_id = $user_id
0443 AND p.author_id = u.user_id
0444 AND t.folder_id = " . PRIVMSGS_NO_BOX . '
0445 AND t.msg_id = p.msg_id';
0446
0447 // Just place into the appropriate arrays if no rules need to be checked
0448 if (!$user_message_rules)
0449 {
0450 $result = $db->sql_query($retrieve_sql);
0451
0452 while ($row = $db->sql_fetchrow($result))
0453 {
0454 $action_ary[$row['msg_id']][] = array('action' => false);
0455 }
0456 $db->sql_freeresult($result);
0457 }
0458 else
0459 {
0460 $user_rules = $zebra = $check_rows = array();
0461 $user_ids = $memberships = array();
0462
0463 // First of all, grab all rules and retrieve friends/foes
0464 $sql = 'SELECT *
0465 FROM ' . PRIVMSGS_RULES_TABLE . "
0466 WHERE user_id = $user_id";
0467 $result = $db->sql_query($sql);
0468 $user_rules = $db->sql_fetchrowset($result);
0469 $db->sql_freeresult($result);
0470
0471 if (sizeof($user_rules))
0472 {
0473 $sql = 'SELECT zebra_id, friend, foe
0474 FROM ' . ZEBRA_TABLE . "
0475 WHERE user_id = $user_id";
0476 $result = $db->sql_query($sql);
0477
0478 while ($row = $db->sql_fetchrow($result))
0479 {
0480 $zebra[$row['zebra_id']] = $row;
0481 }
0482 $db->sql_freeresult($result);
0483 }
0484
0485 // Now build a bare-bone check_row array
0486 $result = $db->sql_query($retrieve_sql);
0487
0488 while ($row = $db->sql_fetchrow($result))
0489 {
0490 $check_rows[] = array_merge($row, array(
0491 'to' => explode(':', $row['to_address']),
0492 'bcc' => explode(':', $row['bcc_address']),
0493 'friend' => (isset($zebra[$row['author_id']])) ? $zebra[$row['author_id']]['friend'] : 0,
0494 'foe' => (isset($zebra[$row['author_id']])) ? $zebra[$row['author_id']]['foe'] : 0,
0495 'user_in_group' => array($user->data['group_id']),
0496 'author_in_group' => array())
0497 );
0498
0499 $user_ids[] = $row['user_id'];
0500 }
0501 $db->sql_freeresult($result);
0502
0503 // Retrieve user memberships
0504 if (sizeof($user_ids))
0505 {
0506 $sql = 'SELECT *
0507 FROM ' . USER_GROUP_TABLE . '
0508 WHERE ' . $db->sql_in_set('user_id', $user_ids) . '
0509 AND user_pending = 0';
0510 $result = $db->sql_query($sql);
0511
0512 while ($row = $db->sql_fetchrow($result))
0513 {
0514 $memberships[$row['user_id']][] = $row['group_id'];
0515 }
0516 $db->sql_freeresult($result);
0517 }
0518
0519 // Now place into the appropriate folder
0520 foreach ($check_rows as $row)
0521 {
0522 // Add membership if set
0523 if (isset($memberships[$row['author_id']]))
0524 {
0525 $row['author_in_group'] = $memberships[$row['user_id']];
0526 }
0527
0528 // Check Rule - this should be very quick since we have all information we need
0529 $is_match = false;
0530 foreach ($user_rules as $rule_row)
0531 {
0532 if (($action = check_rule($global_privmsgs_rules, $rule_row, $row, $user_id)) !== false)
0533 {
0534 $is_match = true;
0535 $action_ary[$row['msg_id']][] = $action;
0536 }
0537 }
0538
0539 if (!$is_match)
0540 {
0541 $action_ary[$row['msg_id']][] = array('action' => false);
0542 }
0543 }
0544
0545 unset($user_rules, $zebra, $check_rows, $user_ids, $memberships);
0546 }
0547
0548 // We place actions into arrays, to save queries.
0549 $sql = $unread_ids = $delete_ids = $important_ids = array();
0550
0551 foreach ($action_ary as $msg_id => $msg_ary)
0552 {
0553 // It is allowed to execute actions more than once, except placing messages into folder
0554 $folder_action = $message_removed = false;
0555
0556 foreach ($msg_ary as $pos => $rule_ary)
0557 {
0558 if ($folder_action && $rule_ary['action'] == ACTION_PLACE_INTO_FOLDER)
0559 {
0560 continue;
0561 }
0562
0563 switch ($rule_ary['action'])
0564 {
0565 case ACTION_PLACE_INTO_FOLDER:
0566 // Folder actions have precedence, so we will remove any other ones
0567 $folder_action = true;
0568 $move_into_folder[(int) $rule_ary['folder_id']][] = $msg_id;
0569 break;
0570
0571 case ACTION_MARK_AS_READ:
0572 if ($rule_ary['pm_unread'])
0573 {
0574 $unread_ids[] = $msg_id;
0575 }
0576 break;
0577
0578 case ACTION_DELETE_MESSAGE:
0579 $delete_ids[] = $msg_id;
0580 $message_removed = true;
0581 break;
0582
0583 case ACTION_MARK_AS_IMPORTANT:
0584 if (!$rule_ary['pm_marked'])
0585 {
0586 $important_ids[] = $msg_id;
0587 }
0588 break;
0589 }
0590 }
0591
0592 // 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
0593 // folder. Here we simply move the message into the INBOX if it gets not removed and also not put into a custom folder.
0594 if (!$folder_action && !$message_removed)
0595 {
0596 $move_into_folder[PRIVMSGS_INBOX][] = $msg_id;
0597 }
0598 }
0599
0600 // Do not change the order of processing
0601 // The number of queries needed to be executed here highly depends on the defined rules and are
0602 // only gone through if new messages arrive.
0603
0604 // Delete messages
0605 if (sizeof($delete_ids))
0606 {
0607 $num_removed += sizeof($delete_ids);
0608 delete_pm($user_id, $delete_ids, PRIVMSGS_NO_BOX);
0609 }
0610
0611 // Set messages to Unread
0612 if (sizeof($unread_ids))
0613 {
0614 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
0615 SET pm_unread = 0
0616 WHERE ' . $db->sql_in_set('msg_id', $unread_ids) . "
0617 AND user_id = $user_id
0618 AND folder_id = " . PRIVMSGS_NO_BOX;
0619 $db->sql_query($sql);
0620 }
0621
0622 // mark messages as important
0623 if (sizeof($important_ids))
0624 {
0625 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
0626 SET pm_marked = 1 - pm_marked
0627 WHERE folder_id = ' . PRIVMSGS_NO_BOX . "
0628 AND user_id = $user_id
0629 AND " . $db->sql_in_set('msg_id', $important_ids);
0630 $db->sql_query($sql);
0631 }
0632
0633 // Move into folder
0634 $folder = array();
0635
0636 if (sizeof($move_into_folder))
0637 {
0638 // Determine Full Folder Action - we need the move to folder id later eventually
0639 $full_folder_action = ($user->data['user_full_folder'] == FULL_FOLDER_NONE) ? ($config['full_folder_action'] - (FULL_FOLDER_NONE*(-1))) : $user->data['user_full_folder'];
0640
0641 $sql_folder = array_keys($move_into_folder);
0642 if ($full_folder_action >= 0)
0643 {
0644 $sql_folder[] = $full_folder_action;
0645 }
0646
0647 $sql = 'SELECT folder_id, pm_count
0648 FROM ' . PRIVMSGS_FOLDER_TABLE . '
0649 WHERE ' . $db->sql_in_set('folder_id', $sql_folder) . "
0650 AND user_id = $user_id";
0651 $result = $db->sql_query($sql);
0652
0653 while ($row = $db->sql_fetchrow($result))
0654 {
0655 $folder[(int) $row['folder_id']] = (int) $row['pm_count'];
0656 }
0657 $db->sql_freeresult($result);
0658
0659 unset($sql_folder);
0660
0661 if (isset($move_into_folder[PRIVMSGS_INBOX]))
0662 {
0663 $sql = 'SELECT COUNT(msg_id) as num_messages
0664 FROM ' . PRIVMSGS_TO_TABLE . "
0665 WHERE user_id = $user_id
0666 AND folder_id = " . PRIVMSGS_INBOX;
0667 $result = $db->sql_query($sql);
0668 $folder[PRIVMSGS_INBOX] = (int) $db->sql_fetchfield('num_messages');
0669 $db->sql_freeresult($result);
0670 }
0671 }
0672
0673 // Here we have ideally only one folder to move into
0674 foreach ($move_into_folder as $folder_id => $msg_ary)
0675 {
0676 $dest_folder = $folder_id;
0677 $full_folder_action = FULL_FOLDER_NONE;
0678
0679 // Check Message Limit - we calculate with the complete array, most of the time it is one message
0680 // But we are making sure that the other way around works too (more messages in queue than allowed to be stored)
0681 if ($user->data['message_limit'] && $folder[$folder_id] && ($folder[$folder_id] + sizeof($msg_ary)) > $user->data['message_limit'])
0682 {
0683 $full_folder_action = ($user->data['user_full_folder'] == FULL_FOLDER_NONE) ? ($config['full_folder_action'] - (FULL_FOLDER_NONE*(-1))) : $user->data['user_full_folder'];
0684
0685 // If destination folder itself is full...
0686 if ($full_folder_action >= 0 && ($folder[$full_folder_action] + sizeof($msg_ary)) > $user->data['message_limit'])
0687 {
0688 $full_folder_action = $config['full_folder_action'] - (FULL_FOLDER_NONE*(-1));
0689 }
0690
0691 // If Full Folder Action is to move to another folder, we simply adjust the destination folder
0692 if ($full_folder_action >= 0)
0693 {
0694 $dest_folder = $full_folder_action;
0695 }
0696 else if ($full_folder_action == FULL_FOLDER_DELETE)
0697 {
0698 // Delete some messages. NOTE: Ordered by msg_id here instead of message_time!
0699 $sql = 'SELECT msg_id
0700 FROM ' . PRIVMSGS_TO_TABLE . "
0701 WHERE user_id = $user_id
0702 AND folder_id = $dest_folder
0703 ORDER BY msg_id ASC";
0704 $result = $db->sql_query_limit($sql, (($folder[$dest_folder] + sizeof($msg_ary)) - $user->data['message_limit']));
0705
0706 $delete_ids = array();
0707 while ($row = $db->sql_fetchrow($result))
0708 {
0709 $delete_ids[] = $row['msg_id'];
0710 }
0711 $db->sql_freeresult($result);
0712
0713 $num_removed += sizeof($delete_ids);
0714 delete_pm($user_id, $delete_ids, $dest_folder);
0715 }
0716 }
0717
0718 //
0719 if ($full_folder_action == FULL_FOLDER_HOLD)
0720 {
0721 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
0722 SET folder_id = ' . PRIVMSGS_HOLD_BOX . '
0723 WHERE folder_id = ' . PRIVMSGS_NO_BOX . "
0724 AND user_id = $user_id
0725 AND " . $db->sql_in_set('msg_id', $msg_ary);
0726 $db->sql_query($sql);
0727 }
0728 else
0729 {
0730 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
0731 SET folder_id = $dest_folder, pm_new = 0
0732 WHERE folder_id = " . PRIVMSGS_NO_BOX . "
0733 AND user_id = $user_id
0734 AND pm_new = 1
0735 AND " . $db->sql_in_set('msg_id', $msg_ary);
0736 $db->sql_query($sql);
0737
0738 if ($dest_folder != PRIVMSGS_INBOX)
0739 {
0740 $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . '
0741 SET pm_count = pm_count + ' . (int) $db->sql_affectedrows() . "
0742 WHERE folder_id = $dest_folder
0743 AND user_id = $user_id";
0744 $db->sql_query($sql);
0745 }
0746 }
0747 }
0748
0749 if (sizeof($action_ary))
0750 {
0751 // Move from OUTBOX to SENTBOX
0752 // We are not checking any full folder status here... SENTBOX is a special treatment (old messages get deleted)
0753 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
0754 SET folder_id = ' . PRIVMSGS_SENTBOX . '
0755 WHERE folder_id = ' . PRIVMSGS_OUTBOX . '
0756 AND ' . $db->sql_in_set('msg_id', array_keys($action_ary));
0757 $db->sql_query($sql);
0758 }
0759
0760 // Update new/unread count
0761 update_pm_counts();
0762
0763 // Now check how many messages got not moved...
0764 $sql = 'SELECT COUNT(msg_id) as num_messages
0765 FROM ' . PRIVMSGS_TO_TABLE . "
0766 WHERE user_id = $user_id
0767 AND folder_id = " . PRIVMSGS_HOLD_BOX;
0768 $result = $db->sql_query($sql);
0769 $num_not_moved = (int) $db->sql_fetchfield('num_messages');
0770 $db->sql_freeresult($result);
0771
0772 return array('not_moved' => $num_not_moved, 'removed' => $num_removed);
0773 }
0774
0775 /**
0776 * Move PM from one to another folder
0777 */
0778 function move_pm($user_id, $message_limit, $move_msg_ids, $dest_folder, $cur_folder_id)
0779 {
0780 global $db, $user;
0781 global $phpbb_root_path, $phpEx;
0782
0783 $num_moved = 0;
0784
0785 if (!is_array($move_msg_ids))
0786 {
0787 $move_msg_ids = array($move_msg_ids);
0788 }
0789
0790 if (sizeof($move_msg_ids) && !in_array($dest_folder, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX)) &&
0791 !in_array($cur_folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)) && $cur_folder_id != $dest_folder)
0792 {
0793 // We have to check the destination folder ;)
0794 if ($dest_folder != PRIVMSGS_INBOX)
0795 {
0796 $sql = 'SELECT folder_id, folder_name, pm_count
0797 FROM ' . PRIVMSGS_FOLDER_TABLE . "
0798 WHERE folder_id = $dest_folder
0799 AND user_id = $user_id";
0800 $result = $db->sql_query($sql);
0801 $row = $db->sql_fetchrow($result);
0802 $db->sql_freeresult($result);
0803
0804 if (!$row)
0805 {
0806 trigger_error('NOT_AUTHORISED');
0807 }
0808
0809 if ($message_limit && $row['pm_count'] + sizeof($move_msg_ids) > $message_limit)
0810 {
0811 $message = sprintf($user->lang['NOT_ENOUGH_SPACE_FOLDER'], $row['folder_name']) . '<br /><br />';
0812 $message .= sprintf($user->lang['CLICK_RETURN_FOLDER'], '<a href="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $row['folder_id']) . '">', '</a>', $row['folder_name']);
0813 trigger_error($message);
0814 }
0815 }
0816 else
0817 {
0818 $sql = 'SELECT COUNT(msg_id) as num_messages
0819 FROM ' . PRIVMSGS_TO_TABLE . '
0820 WHERE folder_id = ' . PRIVMSGS_INBOX . "
0821 AND user_id = $user_id";
0822 $result = $db->sql_query($sql);
0823 $num_messages = (int) $db->sql_fetchfield('num_messages');
0824 $db->sql_freeresult($result);
0825
0826 if ($message_limit && $num_messages + sizeof($move_msg_ids) > $message_limit)
0827 {
0828 $message = sprintf($user->lang['NOT_ENOUGH_SPACE_FOLDER'], $user->lang['PM_INBOX']) . '<br /><br />';
0829 $message .= sprintf($user->lang['CLICK_RETURN_FOLDER'], '<a href="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox') . '">', '</a>', $user->lang['PM_INBOX']);
0830 trigger_error($message);
0831 }
0832 }
0833
0834 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
0835 SET folder_id = $dest_folder
0836 WHERE folder_id = $cur_folder_id
0837 AND user_id = $user_id
0838 AND " . $db->sql_in_set('msg_id', $move_msg_ids);
0839 $db->sql_query($sql);
0840 $num_moved = $db->sql_affectedrows();
0841
0842 // Update pm counts
0843 if ($num_moved)
0844 {
0845 if (!in_array($cur_folder_id, array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX)))
0846 {
0847 $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . "
0848 SET pm_count = pm_count - $num_moved
0849 WHERE folder_id = $cur_folder_id
0850 AND user_id = $user_id";
0851 $db->sql_query($sql);
0852 }
0853
0854 if ($dest_folder != PRIVMSGS_INBOX)
0855 {
0856 $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . "
0857 SET pm_count = pm_count + $num_moved
0858 WHERE folder_id = $dest_folder
0859 AND user_id = $user_id";
0860 $db->sql_query($sql);
0861 }
0862 }
0863 }
0864 else if (in_array($cur_folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)))
0865 {
0866 trigger_error('CANNOT_MOVE_SPECIAL');
0867 }
0868
0869 return $num_moved;
0870 }
0871
0872 /**
0873 * Update unread message status
0874 */
0875 function update_unread_status($unread, $msg_id, $user_id, $folder_id)
0876 {
0877 if (!$unread)
0878 {
0879 return;
0880 }
0881
0882 global $db, $user, $phpbb_container;
0883
0884 $phpbb_notifications = $phpbb_container->get('notification_manager');
0885
0886 $phpbb_notifications->mark_notifications_read('notification.type.pm', $msg_id, $user_id);
0887
0888 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
0889 SET pm_unread = 0
0890 WHERE msg_id = $msg_id
0891 AND user_id = $user_id
0892 AND folder_id = $folder_id";
0893 $db->sql_query($sql);
0894
0895 $sql = 'UPDATE ' . USERS_TABLE . "
0896 SET user_unread_privmsg = user_unread_privmsg - 1
0897 WHERE user_id = $user_id";
0898 $db->sql_query($sql);
0899
0900 if ($user->data['user_id'] == $user_id)
0901 {
0902 $user->data['user_unread_privmsg']--;
0903
0904 // Try to cope with previous wrong conversions...
0905 if ($user->data['user_unread_privmsg'] < 0)
0906 {
0907 $sql = 'UPDATE ' . USERS_TABLE . "
0908 SET user_unread_privmsg = 0
0909 WHERE user_id = $user_id";
0910 $db->sql_query($sql);
0911
0912 $user->data['user_unread_privmsg'] = 0;
0913 }
0914 }
0915 }
0916
0917 function mark_folder_read($user_id, $folder_id)
0918 {
0919 global $db;
0920
0921 $sql = 'SELECT msg_id
0922 FROM ' . PRIVMSGS_TO_TABLE . '
0923 WHERE folder_id = ' . ((int) $folder_id) . '
0924 AND user_id = ' . ((int) $user_id) . '
0925 AND pm_unread = 1';
0926 $result = $db->sql_query($sql);
0927
0928 while ($row = $db->sql_fetchrow($result))
0929 {
0930 update_unread_status(true, $row['msg_id'], $user_id, $folder_id);
0931 }
0932 $db->sql_freeresult($result);
0933 }
0934
0935 /**
0936 * Handle all actions possible with marked messages
0937 */
0938 function handle_mark_actions($user_id, $mark_action)
0939 {
0940 global $db, $user, $phpbb_root_path, $phpEx;
0941
0942 $msg_ids = request_var('marked_msg_id', array(0));
0943 $cur_folder_id = request_var('cur_folder_id', PRIVMSGS_NO_BOX);
0944 $confirm = (isset($_POST['confirm'])) ? true : false;
0945
0946 if (!sizeof($msg_ids))
0947 {
0948 return false;
0949 }
0950
0951 switch ($mark_action)
0952 {
0953 case 'mark_important':
0954
0955 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
0956 SET pm_marked = 1 - pm_marked
0957 WHERE folder_id = $cur_folder_id
0958 AND user_id = $user_id
0959 AND " . $db->sql_in_set('msg_id', $msg_ids);
0960 $db->sql_query($sql);
0961
0962 break;
0963
0964 case 'delete_marked':
0965
0966 global $auth;
0967
0968 if (!$auth->acl_get('u_pm_delete'))
0969 {
0970 trigger_error('NO_AUTH_DELETE_MESSAGE');
0971 }
0972
0973 if (confirm_box(true))
0974 {
0975 delete_pm($user_id, $msg_ids, $cur_folder_id);
0976
0977 $success_msg = (sizeof($msg_ids) == 1) ? 'MESSAGE_DELETED' : 'MESSAGES_DELETED';
0978 $redirect = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $cur_folder_id);
0979
0980 meta_refresh(3, $redirect);
0981 trigger_error($user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_FOLDER'], '<a href="' . $redirect . '">', '</a>'));
0982 }
0983 else
0984 {
0985 $s_hidden_fields = array(
0986 'cur_folder_id' => $cur_folder_id,
0987 'mark_option' => 'delete_marked',
0988 'submit_mark' => true,
0989 'marked_msg_id' => $msg_ids
0990 );
0991
0992 confirm_box(false, 'DELETE_MARKED_PM', build_hidden_fields($s_hidden_fields));
0993 }
0994
0995 break;
0996
0997 default:
0998 return false;
0999 }
1000
1001 return true;
1002 }
1003
1004 /**
1005 * Delete PM(s)
1006 */
1007 function delete_pm($user_id, $msg_ids, $folder_id)
1008 {
1009 global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_dispatcher;
1010
1011 $user_id = (int) $user_id;
1012 $folder_id = (int) $folder_id;
1013
1014 if (!$user_id)
1015 {
1016 return false;
1017 }
1018
1019 if (!is_array($msg_ids))
1020 {
1021 if (!$msg_ids)
1022 {
1023 return false;
1024 }
1025 $msg_ids = array($msg_ids);
1026 }
1027
1028 if (!sizeof($msg_ids))
1029 {
1030 return false;
1031 }
1032
1033 /**
1034 * Get all info for PM(s) before they are deleted
1035 *
1036 * @event core.delete_pm_before
1037 * @var int user_id ID of the user requested the message delete
1038 * @var array msg_ids array of all messages to be deleted
1039 * @var int folder_id ID of the user folder where the messages are stored
1040 * @since 3.1.0-b5
1041 */
1042 $vars = array('user_id', 'msg_ids', 'folder_id');
1043 extract($phpbb_dispatcher->trigger_event('core.delete_pm_before', compact($vars)));
1044
1045 // Get PM Information for later deleting
1046 $sql = 'SELECT msg_id, pm_unread, pm_new
1047 FROM ' . PRIVMSGS_TO_TABLE . '
1048 WHERE ' . $db->sql_in_set('msg_id', array_map('intval', $msg_ids)) . "
1049 AND folder_id = $folder_id
1050 AND user_id = $user_id";
1051 $result = $db->sql_query($sql);
1052
1053 $delete_rows = array();
1054 $num_unread = $num_new = $num_deleted = 0;
1055 while ($row = $db->sql_fetchrow($result))
1056 {
1057 $num_unread += (int) $row['pm_unread'];
1058 $num_new += (int) $row['pm_new'];
1059
1060 $delete_rows[$row['msg_id']] = 1;
1061 }
1062 $db->sql_freeresult($result);
1063 unset($msg_ids);
1064
1065 if (!sizeof($delete_rows))
1066 {
1067 return false;
1068 }
1069
1070 $db->sql_transaction('begin');
1071
1072 // if no one has read the message yet (meaning it is in users outbox)
1073 // then mark the message as deleted...
1074 if ($folder_id == PRIVMSGS_OUTBOX)
1075 {
1076 // Remove PM from Outbox
1077 $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . "
1078 WHERE user_id = $user_id AND folder_id = " . PRIVMSGS_OUTBOX . '
1079 AND ' . $db->sql_in_set('msg_id', array_keys($delete_rows));
1080 $db->sql_query($sql);
1081
1082 // Update PM Information for safety
1083 $sql = 'UPDATE ' . PRIVMSGS_TABLE . " SET message_text = ''
1084 WHERE " . $db->sql_in_set('msg_id', array_keys($delete_rows));
1085 $db->sql_query($sql);
1086
1087 // Set delete flag for those intended to receive the PM
1088 // We do not remove the message actually, to retain some basic information (sent time for example)
1089 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
1090 SET pm_deleted = 1
1091 WHERE ' . $db->sql_in_set('msg_id', array_keys($delete_rows));
1092 $db->sql_query($sql);
1093
1094 $num_deleted = $db->sql_affectedrows();
1095 }
1096 else
1097 {
1098 // Delete private message data
1099 $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . "
1100 WHERE user_id = $user_id
1101 AND folder_id = $folder_id
1102 AND " . $db->sql_in_set('msg_id', array_keys($delete_rows));
1103 $db->sql_query($sql);
1104 $num_deleted = $db->sql_affectedrows();
1105 }
1106
1107 // if folder id is user defined folder then decrease pm_count
1108 if (!in_array($folder_id, array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX, PRIVMSGS_NO_BOX)))
1109 {
1110 $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . "
1111 SET pm_count = pm_count - $num_deleted
1112 WHERE folder_id = $folder_id";
1113 $db->sql_query($sql);
1114 }
1115
1116 // Update unread and new status field
1117 if ($num_unread || $num_new)
1118 {
1119 $set_sql = ($num_unread) ? 'user_unread_privmsg = user_unread_privmsg - ' . $num_unread : '';
1120
1121 if ($num_new)
1122 {
1123 $set_sql .= ($set_sql != '') ? ', ' : '';
1124 $set_sql .= 'user_new_privmsg = user_new_privmsg - ' . $num_new;
1125 }
1126
1127 $db->sql_query('UPDATE ' . USERS_TABLE . " SET $set_sql WHERE user_id = $user_id");
1128
1129 $user->data['user_new_privmsg'] -= $num_new;
1130 $user->data['user_unread_privmsg'] -= $num_unread;
1131 }
1132
1133 $phpbb_notifications = $phpbb_container->get('notification_manager');
1134
1135 $phpbb_notifications->delete_notifications('notification.type.pm', array_keys($delete_rows));
1136
1137 // Now we have to check which messages we can delete completely
1138 $sql = 'SELECT msg_id
1139 FROM ' . PRIVMSGS_TO_TABLE . '
1140 WHERE ' . $db->sql_in_set('msg_id', array_keys($delete_rows));
1141 $result = $db->sql_query($sql);
1142
1143 while ($row = $db->sql_fetchrow($result))
1144 {
1145 unset($delete_rows[$row['msg_id']]);
1146 }
1147 $db->sql_freeresult($result);
1148
1149 $delete_ids = array_keys($delete_rows);
1150
1151 if (sizeof($delete_ids))
1152 {
1153 // Check if there are any attachments we need to remove
1154 if (!function_exists('delete_attachments'))
1155 {
1156 include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
1157 }
1158
1159 delete_attachments('message', $delete_ids, false);
1160
1161 $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
1162 WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
1163 $db->sql_query($sql);
1164 }
1165
1166 $db->sql_transaction('commit');
1167
1168 return true;
1169 }
1170
1171 /**
1172 * Delete all PM(s) for a given user and delete the ones without references
1173 *
1174 * @param int $user_id ID of the user whose private messages we want to delete
1175 *
1176 * @return boolean False if there were no pms found, true otherwise.
1177 */
1178 function phpbb_delete_user_pms($user_id)
1179 {
1180 global $db, $user, $phpbb_root_path, $phpEx;
1181
1182 $user_id = (int) $user_id;
1183
1184 if (!$user_id)
1185 {
1186 return false;
1187 }
1188
1189 return phpbb_delete_users_pms(array($user_id));
1190 }
1191
1192 /**
1193 * Delete all PM(s) for given users and delete the ones without references
1194 *
1195 * @param array $user_ids IDs of the users whose private messages we want to delete
1196 *
1197 * @return boolean False if there were no pms found, true otherwise.
1198 */
1199 function phpbb_delete_users_pms($user_ids)
1200 {
1201 global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container;
1202
1203 $user_id_sql = $db->sql_in_set('user_id', $user_ids);
1204 $author_id_sql = $db->sql_in_set('author_id', $user_ids);
1205
1206 // Get PM Information for later deleting
1207 // The two queries where split, so we can use our indexes
1208 $undelivered_msg = $delete_ids = array();
1209
1210 // Part 1: get PMs the user received
1211 $sql = 'SELECT msg_id
1212 FROM ' . PRIVMSGS_TO_TABLE . '
1213 WHERE ' . $user_id_sql;
1214 $result = $db->sql_query($sql);
1215
1216 while ($row = $db->sql_fetchrow($result))
1217 {
1218 $msg_id = (int) $row['msg_id'];
1219 $delete_ids[$msg_id] = $msg_id;
1220 }
1221 $db->sql_freeresult($result);
1222
1223 // Part 2: get PMs the users sent, but are yet to be received.
1224 // We cannot simply delete them. First we have to check
1225 // whether another user already received and read the message.
1226 $sql = 'SELECT msg_id
1227 FROM ' . PRIVMSGS_TO_TABLE . '
1228 WHERE ' . $author_id_sql . '
1229 AND folder_id = ' . PRIVMSGS_NO_BOX;
1230 $result = $db->sql_query($sql);
1231
1232 while ($row = $db->sql_fetchrow($result))
1233 {
1234 $msg_id = (int) $row['msg_id'];
1235 $undelivered_msg[$msg_id] = $msg_id;
1236 }
1237 $db->sql_freeresult($result);
1238
1239 if (empty($delete_ids) && empty($undelivered_msg))
1240 {
1241 return false;
1242 }
1243
1244 $db->sql_transaction('begin');
1245
1246 $phpbb_notifications = $phpbb_container->get('notification_manager');
1247
1248 if (!empty($undelivered_msg))
1249 {
1250 // A pm is delivered, if for any recipient the message was moved
1251 // from their NO_BOX to another folder. We do not delete such
1252 // messages, but only delete them for users, who have not yet
1253 // received them.
1254 $sql = 'SELECT msg_id
1255 FROM ' . PRIVMSGS_TO_TABLE . '
1256 WHERE ' . $author_id_sql . '
1257 AND folder_id <> ' . PRIVMSGS_NO_BOX . '
1258 AND folder_id <> ' . PRIVMSGS_OUTBOX . '
1259 AND folder_id <> ' . PRIVMSGS_SENTBOX;
1260 $result = $db->sql_query($sql);
1261
1262 $delivered_msg = array();
1263 while ($row = $db->sql_fetchrow($result))
1264 {
1265 $msg_id = (int) $row['msg_id'];
1266 $delivered_msg[$msg_id] = $msg_id;
1267 unset($undelivered_msg[$msg_id]);
1268 }
1269 $db->sql_freeresult($result);
1270
1271 $undelivered_user = array();
1272
1273 // Count the messages we delete, so we can correct the user pm data
1274 $sql = 'SELECT user_id, COUNT(msg_id) as num_undelivered_privmsgs
1275 FROM ' . PRIVMSGS_TO_TABLE . '
1276 WHERE ' . $author_id_sql . '
1277 AND folder_id = ' . PRIVMSGS_NO_BOX . '
1278 AND ' . $db->sql_in_set('msg_id', array_merge($undelivered_msg, $delivered_msg)) . '
1279 GROUP BY user_id';
1280 $result = $db->sql_query($sql);
1281
1282 while ($row = $db->sql_fetchrow($result))
1283 {
1284 $num_pms = (int) $row['num_undelivered_privmsgs'];
1285 $undelivered_user[$num_pms][] = (int) $row['user_id'];
1286
1287 if (sizeof($undelivered_user[$num_pms]) > 50)
1288 {
1289 // If there are too many users affected the query might get
1290 // too long, so we update the value for the first bunch here.
1291 $sql = 'UPDATE ' . USERS_TABLE . '
1292 SET user_new_privmsg = user_new_privmsg - ' . $num_pms . ',
1293 user_unread_privmsg = user_unread_privmsg - ' . $num_pms . '
1294 WHERE ' . $db->sql_in_set('user_id', $undelivered_user[$num_pms]);
1295 $db->sql_query($sql);
1296 unset($undelivered_user[$num_pms]);
1297 }
1298 }
1299 $db->sql_freeresult($result);
1300
1301 foreach ($undelivered_user as $num_pms => $undelivered_user_set)
1302 {
1303 $sql = 'UPDATE ' . USERS_TABLE . '
1304 SET user_new_privmsg = user_new_privmsg - ' . $num_pms . ',
1305 user_unread_privmsg = user_unread_privmsg - ' . $num_pms . '
1306 WHERE ' . $db->sql_in_set('user_id', $undelivered_user_set);
1307 $db->sql_query($sql);
1308 }
1309
1310 if (!empty($delivered_msg))
1311 {
1312 $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . '
1313 WHERE folder_id = ' . PRIVMSGS_NO_BOX . '
1314 AND ' . $db->sql_in_set('msg_id', $delivered_msg);
1315 $db->sql_query($sql);
1316
1317 $phpbb_notifications->delete_notifications('notification.type.pm', $delivered_msg);
1318 }
1319
1320 if (!empty($undelivered_msg))
1321 {
1322 $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . '
1323 WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg);
1324 $db->sql_query($sql);
1325
1326 $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
1327 WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg);
1328 $db->sql_query($sql);
1329
1330 $phpbb_notifications->delete_notifications('notification.type.pm', $undelivered_msg);
1331 }
1332 }
1333
1334 // Reset the user's pm count to 0
1335 $sql = 'UPDATE ' . USERS_TABLE . '
1336 SET user_new_privmsg = 0,
1337 user_unread_privmsg = 0
1338 WHERE ' . $user_id_sql;
1339 $db->sql_query($sql);
1340
1341 // Delete private message data of the user
1342 $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . '
1343 WHERE ' . $user_id_sql;
1344 $db->sql_query($sql);
1345
1346 if (!empty($delete_ids))
1347 {
1348 // Now we have to check which messages we can delete completely
1349 $sql = 'SELECT msg_id
1350 FROM ' . PRIVMSGS_TO_TABLE . '
1351 WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
1352 $result = $db->sql_query($sql);
1353
1354 while ($row = $db->sql_fetchrow($result))
1355 {
1356 unset($delete_ids[$row['msg_id']]);
1357 }
1358 $db->sql_freeresult($result);
1359
1360 if (!empty($delete_ids))
1361 {
1362 // Check if there are any attachments we need to remove
1363 if (!function_exists('delete_attachments'))
1364 {
1365 include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
1366 }
1367
1368 delete_attachments('message', $delete_ids, false);
1369
1370 $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
1371 WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
1372 $db->sql_query($sql);
1373
1374 $phpbb_notifications->delete_notifications('notification.type.pm', $delete_ids);
1375 }
1376 }
1377
1378 // Set the remaining author id to anonymous
1379 // This way users are still able to read messages from users being removed
1380 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
1381 SET author_id = ' . ANONYMOUS . '
1382 WHERE ' . $author_id_sql;
1383 $db->sql_query($sql);
1384
1385 $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
1386 SET author_id = ' . ANONYMOUS . '
1387 WHERE ' . $author_id_sql;
1388 $db->sql_query($sql);
1389
1390 $db->sql_transaction('commit');
1391
1392 return true;
1393 }
1394
1395 /**
1396 * Rebuild message header
1397 */
1398 function rebuild_header($check_ary)
1399 {
1400 global $db;
1401
1402 $address = array();
1403
1404 foreach ($check_ary as $check_type => $address_field)
1405 {
1406 // Split Addresses into users and groups
1407 preg_match_all('/:?(u|g)_([0-9]+):?/', $address_field, $match);
1408
1409 $u = $g = array();
1410 foreach ($match[1] as $id => $type)
1411 {
1412 ${$type}[] = (int) $match[2][$id];
1413 }
1414
1415 $_types = array('u', 'g');
1416 foreach ($_types as $type)
1417 {
1418 if (sizeof($$type))
1419 {
1420 foreach ($$type as $id)
1421 {
1422 $address[$type][$id] = $check_type;
1423 }
1424 }
1425 }
1426 }
1427
1428 return $address;
1429 }
1430
1431 /**
1432 * Print out/assign recipient information
1433 */
1434 function write_pm_addresses($check_ary, $author_id, $plaintext = false)
1435 {
1436 global $db, $user, $template, $phpbb_root_path, $phpEx;
1437
1438 $addresses = array();
1439
1440 foreach ($check_ary as $check_type => $address_field)
1441 {
1442 if (!is_array($address_field))
1443 {
1444 // Split Addresses into users and groups
1445 preg_match_all('/:?(u|g)_([0-9]+):?/', $address_field, $match);
1446
1447 $u = $g = array();
1448 foreach ($match[1] as $id => $type)
1449 {
1450 ${$type}[] = (int) $match[2][$id];
1451 }
1452 }
1453 else
1454 {
1455 $u = $address_field['u'];
1456 $g = $address_field['g'];
1457 }
1458
1459 $address = array();
1460 if (sizeof($u))
1461 {
1462 $sql = 'SELECT user_id, username, user_colour
1463 FROM ' . USERS_TABLE . '
1464 WHERE ' . $db->sql_in_set('user_id', $u);
1465 $result = $db->sql_query($sql);
1466
1467 while ($row = $db->sql_fetchrow($result))
1468 {
1469 if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
1470 {
1471 if ($plaintext)
1472 {
1473 $address[] = $row['username'];
1474 }
1475 else
1476 {
1477 $address['user'][$row['user_id']] = array('name' => $row['username'], 'colour' => $row['user_colour']);
1478 }
1479 }
1480 }
1481 $db->sql_freeresult($result);
1482 }
1483
1484 if (sizeof($g))
1485 {
1486 if ($plaintext)
1487 {
1488 $sql = 'SELECT group_name, group_type
1489 FROM ' . GROUPS_TABLE . '
1490 WHERE ' . $db->sql_in_set('group_id', $g);
1491 $result = $db->sql_query($sql);
1492
1493 while ($row = $db->sql_fetchrow($result))
1494 {
1495 if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
1496 {
1497 $address[] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
1498 }
1499 }
1500 $db->sql_freeresult($result);
1501 }
1502 else
1503 {
1504 $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_type, ug.user_id
1505 FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug
1506 WHERE ' . $db->sql_in_set('g.group_id', $g) . '
1507 AND g.group_id = ug.group_id
1508 AND ug.user_pending = 0';
1509 $result = $db->sql_query($sql);
1510
1511 while ($row = $db->sql_fetchrow($result))
1512 {
1513 if (!isset($address['group'][$row['group_id']]))
1514 {
1515 if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
1516 {
1517 $row['group_name'] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
1518 $address['group'][$row['group_id']] = array('name' => $row['group_name'], 'colour' => $row['group_colour']);
1519 }
1520 }
1521
1522 if (isset($address['user'][$row['user_id']]))
1523 {
1524 $address['user'][$row['user_id']]['in_group'] = $row['group_id'];
1525 }
1526 }
1527 $db->sql_freeresult($result);
1528 }
1529 }
1530
1531 if (sizeof($address) && !$plaintext)
1532 {
1533 $template->assign_var('S_' . strtoupper($check_type) . '_RECIPIENT', true);
1534
1535 foreach ($address as $type => $adr_ary)
1536 {
1537 foreach ($adr_ary as $id => $row)
1538 {
1539 $tpl_ary = array(
1540 'IS_GROUP' => ($type == 'group') ? true : false,
1541 'IS_USER' => ($type == 'user') ? true : false,
1542 'UG_ID' => $id,
1543 'NAME' => $row['name'],
1544 'COLOUR' => ($row['colour']) ? '#' . $row['colour'] : '',
1545 'TYPE' => $type,
1546 );
1547
1548 if ($type == 'user')
1549 {
1550 $tpl_ary = array_merge($tpl_ary, array(
1551 'U_VIEW' => get_username_string('profile', $id, $row['name'], $row['colour']),
1552 'NAME_FULL' => get_username_string('full', $id, $row['name'], $row['colour']),
1553 ));
1554 }
1555 else
1556 {
1557 $tpl_ary = array_merge($tpl_ary, array(
1558 'U_VIEW' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $id),
1559 ));
1560 }
1561
1562 $template->assign_block_vars($check_type . '_recipient', $tpl_ary);
1563 }
1564 }
1565 }
1566
1567 $addresses[$check_type] = $address;
1568 }
1569
1570 return $addresses;
1571 }
1572
1573 /**
1574 * Get folder status
1575 */
1576 function get_folder_status($folder_id, $folder)
1577 {
1578 global $db, $user, $config;
1579
1580 if (isset($folder[$folder_id]))
1581 {
1582 $folder = $folder[$folder_id];
1583 }
1584 else
1585 {
1586 return false;
1587 }
1588
1589 $return = array(
1590 'folder_name' => $folder['folder_name'],
1591 'cur' => $folder['num_messages'],
1592 'remaining' => ($user->data['message_limit']) ? $user->data['message_limit'] - $folder['num_messages'] : 0,
1593 'max' => $user->data['message_limit'],
1594 'percent' => ($user->data['message_limit']) ? (($user->data['message_limit'] > 0) ? floor(($folder['num_messages'] / $user->data['message_limit']) * 100) : 100) : 0,
1595 );
1596
1597 $return['message'] = $user->lang('FOLDER_STATUS_MSG', $user->lang('MESSAGES_COUNT', (int) $return['max']), $return['cur'], $return['percent']);
1598
1599 return $return;
1600 }
1601
1602 //
1603 // COMPOSE MESSAGES
1604 //
1605
1606 /**
1607 * Submit PM
1608 */
1609 function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
1610 {
1611 global $db, $auth, $config, $phpEx, $template, $user, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher;
1612
1613 // We do not handle erasing pms here
1614 if ($mode == 'delete')
1615 {
1616 return false;
1617 }
1618
1619 $current_time = time();
1620
1621 /**
1622 * Get all parts of the PM that are to be submited to the DB.
1623 *
1624 * @event core.submit_pm_before
1625 * @var string mode PM Post mode - post|reply|quote|quotepost|forward|edit
1626 * @var string subject Subject of the private message
1627 * @var array data The whole row data of the PM.
1628 * @since 3.1.0-b3
1629 */
1630 $vars = array('mode', 'subject', 'data');
1631 extract($phpbb_dispatcher->trigger_event('core.submit_pm_before', compact($vars)));
1632
1633 // Collect some basic information about which tables and which rows to update/insert
1634 $sql_data = array();
1635 $root_level = 0;
1636
1637 // Recipient Information
1638 $recipients = $to = $bcc = array();
1639
1640 if ($mode != 'edit')
1641 {
1642 // Build Recipient List
1643 // u|g => array($user_id => 'to'|'bcc')
1644 $_types = array('u', 'g');
1645 foreach ($_types as $ug_type)
1646 {
1647 if (isset($data['address_list'][$ug_type]) && sizeof($data['address_list'][$ug_type]))
1648 {
1649 foreach ($data['address_list'][$ug_type] as $id => $field)
1650 {
1651 $id = (int) $id;
1652
1653 // Do not rely on the address list being "valid"
1654 if (!$id || ($ug_type == 'u' && $id == ANONYMOUS))
1655 {
1656 continue;
1657 }
1658
1659 $field = ($field == 'to') ? 'to' : 'bcc';
1660 if ($ug_type == 'u')
1661 {
1662 $recipients[$id] = $field;
1663 }
1664 ${$field}[] = $ug_type . '_' . $id;
1665 }
1666 }
1667 }
1668
1669 if (isset($data['address_list']['g']) && sizeof($data['address_list']['g']))
1670 {
1671 // We need to check the PM status of group members (do they want to receive PM's?)
1672 // Only check if not a moderator or admin, since they are allowed to override this user setting
1673 $sql_allow_pm = (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) ? ' AND u.user_allow_pm = 1' : '';
1674
1675 $sql = 'SELECT u.user_type, ug.group_id, ug.user_id
1676 FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . ' ug
1677 WHERE ' . $db->sql_in_set('ug.group_id', array_keys($data['address_list']['g'])) . '
1678 AND ug.user_pending = 0
1679 AND u.user_id = ug.user_id
1680 AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')' .
1681 $sql_allow_pm;
1682 $result = $db->sql_query($sql);
1683
1684 while ($row = $db->sql_fetchrow($result))
1685 {
1686 $field = ($data['address_list']['g'][$row['group_id']] == 'to') ? 'to' : 'bcc';
1687 $recipients[$row['user_id']] = $field;
1688 }
1689 $db->sql_freeresult($result);
1690 }
1691
1692 if (!sizeof($recipients))
1693 {
1694 trigger_error('NO_RECIPIENT');
1695 }
1696 }
1697
1698 // First of all make sure the subject are having the correct length.
1699 $subject = truncate_string($subject);
1700
1701 $db->sql_transaction('begin');
1702
1703 $sql = '';
1704
1705 switch ($mode)
1706 {
1707 case 'reply':
1708 case 'quote':
1709 $root_level = ($data['reply_from_root_level']) ? $data['reply_from_root_level'] : $data['reply_from_msg_id'];
1710
1711 // Set message_replied switch for this user
1712 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
1713 SET pm_replied = 1
1714 WHERE user_id = ' . $data['from_user_id'] . '
1715 AND msg_id = ' . $data['reply_from_msg_id'];
1716
1717 // no break
1718
1719 case 'forward':
1720 case 'post':
1721 case 'quotepost':
1722 $sql_data = array(
1723 'root_level' => $root_level,
1724 'author_id' => $data['from_user_id'],
1725 'icon_id' => $data['icon_id'],
1726 'author_ip' => $data['from_user_ip'],
1727 'message_time' => $current_time,
1728 'enable_bbcode' => $data['enable_bbcode'],
1729 'enable_smilies' => $data['enable_smilies'],
1730 'enable_magic_url' => $data['enable_urls'],
1731 'enable_sig' => $data['enable_sig'],
1732 'message_subject' => $subject,
1733 'message_text' => $data['message'],
1734 'message_attachment'=> (!empty($data['attachment_data'])) ? 1 : 0,
1735 'bbcode_bitfield' => $data['bbcode_bitfield'],
1736 'bbcode_uid' => $data['bbcode_uid'],
1737 'to_address' => implode(':', $to),
1738 'bcc_address' => implode(':', $bcc),
1739 'message_reported' => 0,
1740 );
1741 break;
1742
1743 case 'edit':
1744 $sql_data = array(
1745 'icon_id' => $data['icon_id'],
1746 'message_edit_time' => $current_time,
1747 'enable_bbcode' => $data['enable_bbcode'],
1748 'enable_smilies' => $data['enable_smilies'],
1749 'enable_magic_url' => $data['enable_urls'],
1750 'enable_sig' => $data['enable_sig'],
1751 'message_subject' => $subject,
1752 'message_text' => $data['message'],
1753 'message_attachment'=> (!empty($data['attachment_data'])) ? 1 : 0,
1754 'bbcode_bitfield' => $data['bbcode_bitfield'],
1755 'bbcode_uid' => $data['bbcode_uid']
1756 );
1757 break;
1758 }
1759
1760 if (sizeof($sql_data))
1761 {
1762 $query = '';
1763
1764 if ($mode == 'post' || $mode == 'reply' || $mode == 'quote' || $mode == 'quotepost' || $mode == 'forward')
1765 {
1766 $db->sql_query('INSERT INTO ' . PRIVMSGS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_data));
1767 $data['msg_id'] = $db->sql_nextid();
1768 }
1769 else if ($mode == 'edit')
1770 {
1771 $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
1772 SET message_edit_count = message_edit_count + 1, ' . $db->sql_build_array('UPDATE', $sql_data) . '
1773 WHERE msg_id = ' . $data['msg_id'];
1774 $db->sql_query($sql);
1775 }
1776 }
1777
1778 if ($mode != 'edit')
1779 {
1780 if ($sql)
1781 {
1782 $db->sql_query($sql);
1783 }
1784 unset($sql);
1785
1786 $sql_ary = array();
1787 foreach ($recipients as $user_id => $type)
1788 {
1789 $sql_ary[] = array(
1790 'msg_id' => (int) $data['msg_id'],
1791 'user_id' => (int) $user_id,
1792 'author_id' => (int) $data['from_user_id'],
1793 'folder_id' => PRIVMSGS_NO_BOX,
1794 'pm_new' => 1,
1795 'pm_unread' => 1,
1796 'pm_forwarded' => ($mode == 'forward') ? 1 : 0
1797 );
1798 }
1799
1800 $db->sql_multi_insert(PRIVMSGS_TO_TABLE, $sql_ary);
1801
1802 $sql = 'UPDATE ' . USERS_TABLE . '
1803 SET user_new_privmsg = user_new_privmsg + 1, user_unread_privmsg = user_unread_privmsg + 1, user_last_privmsg = ' . time() . '
1804 WHERE ' . $db->sql_in_set('user_id', array_keys($recipients));
1805 $db->sql_query($sql);
1806
1807 // Put PM into outbox
1808 if ($put_in_outbox)
1809 {
1810 $db->sql_query('INSERT INTO ' . PRIVMSGS_TO_TABLE . ' ' . $db->sql_build_array('INSERT', array(
1811 'msg_id' => (int) $data['msg_id'],
1812 'user_id' => (int) $data['from_user_id'],
1813 'author_id' => (int) $data['from_user_id'],
1814 'folder_id' => PRIVMSGS_OUTBOX,
1815 'pm_new' => 0,
1816 'pm_unread' => 0,
1817 'pm_forwarded' => ($mode == 'forward') ? 1 : 0))
1818 );
1819 }
1820 }
1821
1822 // Set user last post time
1823 if ($mode == 'reply' || $mode == 'quote' || $mode == 'quotepost' || $mode == 'forward' || $mode == 'post')
1824 {
1825 $sql = 'UPDATE ' . USERS_TABLE . "
1826 SET user_lastpost_time = $current_time
1827 WHERE user_id = " . $data['from_user_id'];
1828 $db->sql_query($sql);
1829 }
1830
1831 // Submit Attachments
1832 if (!empty($data['attachment_data']) && $data['msg_id'] && in_array($mode, array('post', 'reply', 'quote', 'quotepost', 'edit', 'forward')))
1833 {
1834 $space_taken = $files_added = 0;
1835 $orphan_rows = array();
1836
1837 foreach ($data['attachment_data'] as $pos => $attach_row)
1838 {
1839 $orphan_rows[(int) $attach_row['attach_id']] = array();
1840 }
1841
1842 if (sizeof($orphan_rows))
1843 {
1844 $sql = 'SELECT attach_id, filesize, physical_filename
1845 FROM ' . ATTACHMENTS_TABLE . '
1846 WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan_rows)) . '
1847 AND in_message = 1
1848 AND is_orphan = 1
1849 AND poster_id = ' . $user->data['user_id'];
1850 $result = $db->sql_query($sql);
1851
1852 $orphan_rows = array();
1853 while ($row = $db->sql_fetchrow($result))
1854 {
1855 $orphan_rows[$row['attach_id']] = $row;
1856 }
1857 $db->sql_freeresult($result);
1858 }
1859
1860 foreach ($data['attachment_data'] as $pos => $attach_row)
1861 {
1862 if ($attach_row['is_orphan'] && !isset($orphan_rows[$attach_row['attach_id']]))
1863 {
1864 continue;
1865 }
1866
1867 if (!$attach_row['is_orphan'])
1868 {
1869 // update entry in db if attachment already stored in db and filespace
1870 $sql = 'UPDATE ' . ATTACHMENTS_TABLE . "
1871 SET attach_comment = '" . $db->sql_escape($attach_row['attach_comment']) . "'
1872 WHERE attach_id = " . (int) $attach_row['attach_id'] . '
1873 AND is_orphan = 0';
1874 $db->sql_query($sql);
1875 }
1876 else
1877 {
1878 // insert attachment into db
1879 if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . utf8_basename($orphan_rows[$attach_row['attach_id']]['physical_filename'])))
1880 {
1881 continue;
1882 }
1883
1884 $space_taken += $orphan_rows[$attach_row['attach_id']]['filesize'];
1885 $files_added++;
1886
1887 $attach_sql = array(
1888 'post_msg_id' => $data['msg_id'],
1889 'topic_id' => 0,
1890 'is_orphan' => 0,
1891 'poster_id' => $data['from_user_id'],
1892 'attach_comment' => $attach_row['attach_comment'],
1893 );
1894
1895 $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $attach_sql) . '
1896 WHERE attach_id = ' . $attach_row['attach_id'] . '
1897 AND is_orphan = 1
1898 AND poster_id = ' . $user->data['user_id'];
1899 $db->sql_query($sql);
1900 }
1901 }
1902
1903 if ($space_taken && $files_added)
1904 {
1905 set_config_count('upload_dir_size', $space_taken, true);
1906 set_config_count('num_files', $files_added, true);
1907 }
1908 }
1909
1910 // Delete draft if post was loaded...
1911 $draft_id = request_var('draft_loaded', 0);
1912 if ($draft_id)
1913 {
1914 $sql = 'DELETE FROM ' . DRAFTS_TABLE . "
1915 WHERE draft_id = $draft_id
1916 AND user_id = " . $data['from_user_id'];
1917 $db->sql_query($sql);
1918 }
1919
1920 $db->sql_transaction('commit');
1921
1922 // Send Notifications
1923 $pm_data = array_merge($data, array(
1924 'message_subject' => $subject,
1925 'recipients' => $recipients,
1926 ));
1927
1928 $phpbb_notifications = $phpbb_container->get('notification_manager');
1929
1930 if ($mode == 'edit')
1931 {
1932 $phpbb_notifications->update_notifications('notification.type.pm', $pm_data);
1933 }
1934 else
1935 {
1936 $phpbb_notifications->add_notifications('notification.type.pm', $pm_data);
1937 }
1938
1939 /**
1940 * Get PM message ID after submission to DB
1941 *
1942 * @event core.submit_pm_after
1943 * @var string mode PM Post mode - post|reply|quote|quotepost|forward|edit
1944 * @var string subject Subject of the private message
1945 * @var array data The whole row data of the PM.
1946 * @var array pm_data The data sent to notification class
1947 * @since 3.1.0-b5
1948 */
1949 $vars = array('mode', 'subject', 'data', 'pm_data');
1950 extract($phpbb_dispatcher->trigger_event('core.submit_pm_after', compact($vars)));
1951
1952 return $data['msg_id'];
1953 }
1954
1955 /**
1956 * Display Message History
1957 */
1958 function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode = false)
1959 {
1960 global $db, $user, $config, $template, $phpbb_root_path, $phpEx, $auth, $bbcode;
1961
1962 // Select all receipts and the author from the pm we currently view, to only display their pm-history
1963 $sql = 'SELECT author_id, user_id
1964 FROM ' . PRIVMSGS_TO_TABLE . "
1965 WHERE msg_id = $msg_id
1966 AND folder_id <> " . PRIVMSGS_HOLD_BOX;
1967 $result = $db->sql_query($sql);
1968
1969 $recipients = array();
1970 while ($row = $db->sql_fetchrow($result))
1971 {
1972 $recipients[] = (int) $row['user_id'];
1973 $recipients[] = (int) $row['author_id'];
1974 }
1975 $db->sql_freeresult($result);
1976 $recipients = array_unique($recipients);
1977
1978 // Get History Messages (could be newer)
1979 $sql = 'SELECT t.*, p.*, u.*
1980 FROM ' . PRIVMSGS_TABLE . ' p, ' . PRIVMSGS_TO_TABLE . ' t, ' . USERS_TABLE . ' u
1981 WHERE t.msg_id = p.msg_id
1982 AND p.author_id = u.user_id
1983 AND t.folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
1984 AND ' . $db->sql_in_set('t.author_id', $recipients, false, true) . "
1985 AND t.user_id = $user_id";
1986
1987 // We no longer need those.
1988 unset($recipients);
1989
1990 if (!$message_row['root_level'])
1991 {
1992 $sql .= " AND (p.root_level = $msg_id OR (p.root_level = 0 AND p.msg_id = $msg_id))";
1993 }
1994 else
1995 {
1996 $sql .= " AND (p.root_level = " . $message_row['root_level'] . ' OR p.msg_id = ' . $message_row['root_level'] . ')';
1997 }
1998 $sql .= ' ORDER BY p.message_time DESC';
1999
2000 $result = $db->sql_query($sql);
2001 $row = $db->sql_fetchrow($result);
2002
2003 if (!$row)
2004 {
2005 $db->sql_freeresult($result);
2006 return false;
2007 }
2008
2009 $title = $row['message_subject'];
2010
2011 $rowset = array();
2012 $bbcode_bitfield = '';
2013 $folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm') . '&folder=';
2014
2015 do
2016 {
2017 $folder_id = (int) $row['folder_id'];
2018
2019 $row['folder'][] = (isset($folder[$folder_id])) ? '<a href="' . $folder_url . $folder_id . '">' . $folder[$folder_id]['folder_name'] . '</a>' : $user->lang['UNKNOWN_FOLDER'];
2020
2021 if (isset($rowset[$row['msg_id']]))
2022 {
2023 $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'];
2024 }
2025 else
2026 {
2027 $rowset[$row['msg_id']] = $row;
2028 $bbcode_bitfield = $bbcode_bitfield | base64_decode($row['bbcode_bitfield']);
2029 }
2030 }
2031 while ($row = $db->sql_fetchrow($result));
2032 $db->sql_freeresult($result);
2033
2034 if (sizeof($rowset) == 1 && !$in_post_mode)
2035 {
2036 return false;
2037 }
2038
2039 // Instantiate BBCode class
2040 if ((empty($bbcode) || $bbcode === false) && $bbcode_bitfield !== '')
2041 {
2042 if (!class_exists('bbcode'))
2043 {
2044 include($phpbb_root_path . 'includes/bbcode.' . $phpEx);
2045 }
2046 $bbcode = new bbcode(base64_encode($bbcode_bitfield));
2047 }
2048
2049 $title = censor_text($title);
2050
2051 $url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm');
2052 $next_history_pm = $previous_history_pm = $prev_id = 0;
2053
2054 // Re-order rowset to be able to get the next/prev message rows...
2055 $rowset = array_values($rowset);
2056
2057 for ($i = 0, $size = sizeof($rowset); $i < $size; $i++)
2058 {
2059 $row = &$rowset[$i];
2060 $id = (int) $row['msg_id'];
2061
2062 $author_id = $row['author_id'];
2063 $folder_id = (int) $row['folder_id'];
2064
2065 $subject = $row['message_subject'];
2066 $message = $row['message_text'];
2067
2068 $message = censor_text($message);
2069
2070 $decoded_message = false;
2071
2072 if ($in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS)
2073 {
2074 $decoded_message = $message;
2075 decode_message($decoded_message, $row['bbcode_uid']);
2076
2077 $decoded_message = bbcode_nl2br($decoded_message);
2078 }
2079
2080 $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0);
2081 $parse_flags |= ($row['enable_smilies'] ? OPTION_FLAG_SMILIES : 0);
2082
2083 $message = generate_text_for_display($message, $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false);
2084
2085 $subject = censor_text($subject);
2086
2087 if ($id == $msg_id)
2088 {
2089 $next_history_pm = (isset($rowset[$i + 1])) ? (int) $rowset[$i + 1]['msg_id'] : 0;
2090 $previous_history_pm = $prev_id;
2091 }
2092
2093 $template->assign_block_vars('history_row', array(
2094 'MESSAGE_AUTHOR_QUOTE' => (($decoded_message) ? addslashes(get_username_string('username', $author_id, $row['username'], $row['user_colour'], $row['username'])) : ''),
2095 'MESSAGE_AUTHOR_FULL' => get_username_string('full', $author_id, $row['username'], $row['user_colour'], $row['username']),
2096 'MESSAGE_AUTHOR_COLOUR' => get_username_string('colour', $author_id, $row['username'], $row['user_colour'], $row['username']),
2097 'MESSAGE_AUTHOR' => get_username_string('username', $author_id, $row['username'], $row['user_colour'], $row['username']),
2098 'U_MESSAGE_AUTHOR' => get_username_string('profile', $author_id, $row['username'], $row['user_colour'], $row['username']),
2099
2100 'SUBJECT' => $subject,
2101 'SENT_DATE' => $user->format_date($row['message_time']),
2102 'MESSAGE' => $message,
2103 'FOLDER' => implode($user->lang['COMMA_SEPARATOR'], $row['folder']),
2104 'DECODED_MESSAGE' => $decoded_message,
2105
2106 'S_CURRENT_MSG' => ($row['msg_id'] == $msg_id),
2107 'S_AUTHOR_DELETED' => ($author_id == ANONYMOUS) ? true : false,
2108 'S_IN_POST_MODE' => $in_post_mode,
2109
2110 'MSG_ID' => $row['msg_id'],
2111 'U_VIEW_MESSAGE' => "$url&f=$folder_id&p=" . $row['msg_id'],
2112 'U_QUOTE' => (!$in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS) ? "$url&mode=compose&action=quote&f=" . $folder_id . "&p=" . $row['msg_id'] : '',
2113 'U_POST_REPLY_PM' => ($author_id != $user->data['user_id'] && $author_id != ANONYMOUS && $auth->acl_get('u_sendpm')) ? "$url&mode=compose&action=reply&f=$folder_id&p=" . $row['msg_id'] : '')
2114 );
2115 unset($rowset[$i]);
2116 $prev_id = $id;
2117 }
2118
2119 $template->assign_vars(array(
2120 'QUOTE_IMG' => $user->img('icon_post_quote', $user->lang['REPLY_WITH_QUOTE']),
2121 'HISTORY_TITLE' => $title,
2122
2123 'U_VIEW_NEXT_HISTORY' => ($next_history_pm) ? "$url&p=" . $next_history_pm : '',
2124 'U_VIEW_PREVIOUS_HISTORY' => ($previous_history_pm) ? "$url&p=" . $previous_history_pm : '',
2125 ));
2126
2127 return true;
2128 }
2129
2130 /**
2131 * Set correct users max messages in PM folder.
2132 * If several group memberships define different amount of messages, the highest will be chosen.
2133 */
2134 function set_user_message_limit()
2135 {
2136 global $user, $db, $config;
2137
2138 // Get maximum about from user memberships - if it is 0, there is no limit set and we use the maximum value within the config.
2139 $sql = 'SELECT MAX(g.group_message_limit) as max_message_limit
2140 FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug
2141 WHERE ug.user_id = ' . $user->data['user_id'] . '
2142 AND ug.user_pending = 0
2143 AND ug.group_id = g.group_id';
2144 $result = $db->sql_query($sql);
2145 $message_limit = (int) $db->sql_fetchfield('max_message_limit');
2146 $db->sql_freeresult($result);
2147
2148 $user->data['message_limit'] = (!$message_limit) ? $config['pm_max_msgs'] : $message_limit;
2149 }
2150
2151 /**
2152 * Generates an array of coloured recipient names from a list of PMs - (groups & users)
2153 *
2154 * @param array $pm_by_id An array of rows from PRIVMSGS_TABLE, keys are the msg_ids.
2155 *
2156 * @return array 2D Array: array(msg_id => array('username or group string', ...), ...)
2157 * Usernames are generated with {@link get_username_string get_username_string}
2158 * Groups are coloured and have a link to the membership page
2159 */
2160 function get_recipient_strings($pm_by_id)
2161 {
2162 global $db, $phpbb_root_path, $phpEx, $user;
2163
2164 $address_list = $recipient_list = $address = array();
2165
2166 $_types = array('u', 'g');
2167
2168 foreach ($pm_by_id as $message_id => $row)
2169 {
2170 $address[$message_id] = rebuild_header(array('to' => $row['to_address'], 'bcc' => $row['bcc_address']));
2171
2172 foreach ($_types as $ug_type)
2173 {
2174 if (isset($address[$message_id][$ug_type]) && sizeof($address[$message_id][$ug_type]))
2175 {
2176 foreach ($address[$message_id][$ug_type] as $ug_id => $in_to)
2177 {
2178 $recipient_list[$ug_type][$ug_id] = array('name' => $user->lang['NA'], 'colour' => '');
2179 }
2180 }
2181 }
2182 }
2183
2184 foreach ($_types as $ug_type)
2185 {
2186 if (!empty($recipient_list[$ug_type]))
2187 {
2188 if ($ug_type == 'u')
2189 {
2190 $sql = 'SELECT user_id as id, username as name, user_colour as colour
2191 FROM ' . USERS_TABLE . '
2192 WHERE ';
2193 }
2194 else
2195 {
2196 $sql = 'SELECT group_id as id, group_name as name, group_colour as colour, group_type
2197 FROM ' . GROUPS_TABLE . '
2198 WHERE ';
2199 }
2200 $sql .= $db->sql_in_set(($ug_type == 'u') ? 'user_id' : 'group_id', array_map('intval', array_keys($recipient_list[$ug_type])));
2201
2202 $result = $db->sql_query($sql);
2203
2204 while ($row = $db->sql_fetchrow($result))
2205 {
2206 if ($ug_type == 'g')
2207 {
2208 $row['name'] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['name']] : $row['name'];
2209 }
2210
2211 $recipient_list[$ug_type][$row['id']] = array('name' => $row['name'], 'colour' => $row['colour']);
2212 }
2213 $db->sql_freeresult($result);
2214 }
2215 }
2216
2217 foreach ($address as $message_id => $adr_ary)
2218 {
2219 foreach ($adr_ary as $type => $id_ary)
2220 {
2221 foreach ($id_ary as $ug_id => $_id)
2222 {
2223 if ($type == 'u')
2224 {
2225 $address_list[$message_id][] = get_username_string('full', $ug_id, $recipient_list[$type][$ug_id]['name'], $recipient_list[$type][$ug_id]['colour']);
2226 }
2227 else
2228 {
2229 $user_colour = ($recipient_list[$type][$ug_id]['colour']) ? ' style="font-weight: bold; color:#' . $recipient_list[$type][$ug_id]['colour'] . '"' : '';
2230 $link = '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $ug_id) . '"' . $user_colour . '>';
2231 $address_list[$message_id][] = $link . $recipient_list[$type][$ug_id]['name'] . (($link) ? '</a>' : '');
2232 }
2233 }
2234 }
2235 }
2236
2237 return $address_list;
2238 }
2239