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