Verzeichnisstruktur phpBB-3.2.0
- Veröffentlicht
- 06.01.2017
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 (sizeof($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' => array($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 (sizeof($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 (sizeof($delete_ids))
0604 {
0605 $num_removed += sizeof($delete_ids);
0606 delete_pm($user_id, $delete_ids, PRIVMSGS_NO_BOX);
0607 }
0608
0609 // Set messages to Unread
0610 if (sizeof($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 (sizeof($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 (sizeof($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] + sizeof($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] + sizeof($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] + sizeof($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 += sizeof($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 (sizeof($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 (sizeof($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'] + sizeof($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 + sizeof($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 (!sizeof($msg_ids))
0953 {
0954 return false;
0955 }
0956
0957 switch ($mark_action)
0958 {
0959 case 'mark_important':
0960
0961 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
0962 SET pm_marked = 1 - pm_marked
0963 WHERE folder_id = $cur_folder_id
0964 AND user_id = $user_id
0965 AND " . $db->sql_in_set('msg_id', $msg_ids);
0966 $db->sql_query($sql);
0967
0968 break;
0969
0970 case 'delete_marked':
0971
0972 global $auth;
0973
0974 if (!$auth->acl_get('u_pm_delete'))
0975 {
0976 send_status_line(403, 'Forbidden');
0977 trigger_error('NO_AUTH_DELETE_MESSAGE');
0978 }
0979
0980 if (confirm_box(true))
0981 {
0982 delete_pm($user_id, $msg_ids, $cur_folder_id);
0983
0984 $success_msg = (sizeof($msg_ids) == 1) ? 'MESSAGE_DELETED' : 'MESSAGES_DELETED';
0985 $redirect = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=' . $cur_folder_id);
0986
0987 meta_refresh(3, $redirect);
0988 trigger_error($user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_FOLDER'], '<a href="' . $redirect . '">', '</a>'));
0989 }
0990 else
0991 {
0992 $s_hidden_fields = array(
0993 'cur_folder_id' => $cur_folder_id,
0994 'mark_option' => 'delete_marked',
0995 'submit_mark' => true,
0996 'marked_msg_id' => $msg_ids
0997 );
0998
0999 confirm_box(false, 'DELETE_MARKED_PM', build_hidden_fields($s_hidden_fields));
1000 }
1001
1002 break;
1003
1004 default:
1005 return false;
1006 }
1007
1008 return true;
1009 }
1010
1011 /**
1012 * Delete PM(s)
1013 */
1014 function delete_pm($user_id, $msg_ids, $folder_id)
1015 {
1016 global $db, $user, $phpbb_container, $phpbb_dispatcher;
1017
1018 $user_id = (int) $user_id;
1019 $folder_id = (int) $folder_id;
1020
1021 if (!$user_id)
1022 {
1023 return false;
1024 }
1025
1026 if (!is_array($msg_ids))
1027 {
1028 if (!$msg_ids)
1029 {
1030 return false;
1031 }
1032 $msg_ids = array($msg_ids);
1033 }
1034
1035 if (!sizeof($msg_ids))
1036 {
1037 return false;
1038 }
1039
1040 /**
1041 * Get all info for PM(s) before they are deleted
1042 *
1043 * @event core.delete_pm_before
1044 * @var int user_id ID of the user requested the message delete
1045 * @var array msg_ids array of all messages to be deleted
1046 * @var int folder_id ID of the user folder where the messages are stored
1047 * @since 3.1.0-b5
1048 */
1049 $vars = array('user_id', 'msg_ids', 'folder_id');
1050 extract($phpbb_dispatcher->trigger_event('core.delete_pm_before', compact($vars)));
1051
1052 // Get PM Information for later deleting
1053 $sql = 'SELECT msg_id, pm_unread, pm_new
1054 FROM ' . PRIVMSGS_TO_TABLE . '
1055 WHERE ' . $db->sql_in_set('msg_id', array_map('intval', $msg_ids)) . "
1056 AND folder_id = $folder_id
1057 AND user_id = $user_id";
1058 $result = $db->sql_query($sql);
1059
1060 $delete_rows = array();
1061 $num_unread = $num_new = $num_deleted = 0;
1062 while ($row = $db->sql_fetchrow($result))
1063 {
1064 $num_unread += (int) $row['pm_unread'];
1065 $num_new += (int) $row['pm_new'];
1066
1067 $delete_rows[$row['msg_id']] = 1;
1068 }
1069 $db->sql_freeresult($result);
1070 unset($msg_ids);
1071
1072 if (!sizeof($delete_rows))
1073 {
1074 return false;
1075 }
1076
1077 $db->sql_transaction('begin');
1078
1079 // if no one has read the message yet (meaning it is in users outbox)
1080 // then mark the message as deleted...
1081 if ($folder_id == PRIVMSGS_OUTBOX)
1082 {
1083 // Remove PM from Outbox
1084 $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . "
1085 WHERE user_id = $user_id AND folder_id = " . PRIVMSGS_OUTBOX . '
1086 AND ' . $db->sql_in_set('msg_id', array_keys($delete_rows));
1087 $db->sql_query($sql);
1088
1089 // Update PM Information for safety
1090 $sql = 'UPDATE ' . PRIVMSGS_TABLE . " SET message_text = ''
1091 WHERE " . $db->sql_in_set('msg_id', array_keys($delete_rows));
1092 $db->sql_query($sql);
1093
1094 // Set delete flag for those intended to receive the PM
1095 // We do not remove the message actually, to retain some basic information (sent time for example)
1096 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
1097 SET pm_deleted = 1
1098 WHERE ' . $db->sql_in_set('msg_id', array_keys($delete_rows));
1099 $db->sql_query($sql);
1100
1101 $num_deleted = $db->sql_affectedrows();
1102 }
1103 else
1104 {
1105 // Delete private message data
1106 $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . "
1107 WHERE user_id = $user_id
1108 AND folder_id = $folder_id
1109 AND " . $db->sql_in_set('msg_id', array_keys($delete_rows));
1110 $db->sql_query($sql);
1111 $num_deleted = $db->sql_affectedrows();
1112 }
1113
1114 // if folder id is user defined folder then decrease pm_count
1115 if (!in_array($folder_id, array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX, PRIVMSGS_NO_BOX)))
1116 {
1117 $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . "
1118 SET pm_count = pm_count - $num_deleted
1119 WHERE folder_id = $folder_id";
1120 $db->sql_query($sql);
1121 }
1122
1123 // Update unread and new status field
1124 if ($num_unread || $num_new)
1125 {
1126 $set_sql = ($num_unread) ? 'user_unread_privmsg = user_unread_privmsg - ' . $num_unread : '';
1127
1128 if ($num_new)
1129 {
1130 $set_sql .= ($set_sql != '') ? ', ' : '';
1131 $set_sql .= 'user_new_privmsg = user_new_privmsg - ' . $num_new;
1132 }
1133
1134 $db->sql_query('UPDATE ' . USERS_TABLE . " SET $set_sql WHERE user_id = $user_id");
1135
1136 $user->data['user_new_privmsg'] -= $num_new;
1137 $user->data['user_unread_privmsg'] -= $num_unread;
1138 }
1139
1140 /* @var $phpbb_notifications \phpbb\notification\manager */
1141 $phpbb_notifications = $phpbb_container->get('notification_manager');
1142
1143 $phpbb_notifications->delete_notifications('notification.type.pm', array_keys($delete_rows));
1144
1145 // Now we have to check which messages we can delete completely
1146 $sql = 'SELECT msg_id
1147 FROM ' . PRIVMSGS_TO_TABLE . '
1148 WHERE ' . $db->sql_in_set('msg_id', array_keys($delete_rows));
1149 $result = $db->sql_query($sql);
1150
1151 while ($row = $db->sql_fetchrow($result))
1152 {
1153 unset($delete_rows[$row['msg_id']]);
1154 }
1155 $db->sql_freeresult($result);
1156
1157 $delete_ids = array_keys($delete_rows);
1158
1159 if (sizeof($delete_ids))
1160 {
1161 // Check if there are any attachments we need to remove
1162 /** @var \phpbb\attachment\manager $attachment_manager */
1163 $attachment_manager = $phpbb_container->get('attachment.manager');
1164 $attachment_manager->delete('message', $delete_ids, false);
1165 unset($attachment_manager);
1166
1167 $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
1168 WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
1169 $db->sql_query($sql);
1170 }
1171
1172 $db->sql_transaction('commit');
1173
1174 return true;
1175 }
1176
1177 /**
1178 * Delete all PM(s) for a given user and delete the ones without references
1179 *
1180 * @param int $user_id ID of the user whose private messages we want to delete
1181 *
1182 * @return boolean False if there were no pms found, true otherwise.
1183 */
1184 function phpbb_delete_user_pms($user_id)
1185 {
1186 $user_id = (int) $user_id;
1187
1188 if (!$user_id)
1189 {
1190 return false;
1191 }
1192
1193 return phpbb_delete_users_pms(array($user_id));
1194 }
1195
1196 /**
1197 * Delete all PM(s) for given users and delete the ones without references
1198 *
1199 * @param array $user_ids IDs of the users whose private messages we want to delete
1200 *
1201 * @return boolean False if there were no pms found, true otherwise.
1202 */
1203 function phpbb_delete_users_pms($user_ids)
1204 {
1205 global $db, $phpbb_container;
1206
1207 $user_id_sql = $db->sql_in_set('user_id', $user_ids);
1208 $author_id_sql = $db->sql_in_set('author_id', $user_ids);
1209
1210 // Get PM Information for later deleting
1211 // The two queries where split, so we can use our indexes
1212 $undelivered_msg = $delete_ids = array();
1213
1214 // Part 1: get PMs the user received
1215 $sql = 'SELECT msg_id
1216 FROM ' . PRIVMSGS_TO_TABLE . '
1217 WHERE ' . $user_id_sql;
1218 $result = $db->sql_query($sql);
1219
1220 while ($row = $db->sql_fetchrow($result))
1221 {
1222 $msg_id = (int) $row['msg_id'];
1223 $delete_ids[$msg_id] = $msg_id;
1224 }
1225 $db->sql_freeresult($result);
1226
1227 // Part 2: get PMs the users sent, but are yet to be received.
1228 // We cannot simply delete them. First we have to check
1229 // whether another user already received and read the message.
1230 $sql = 'SELECT msg_id
1231 FROM ' . PRIVMSGS_TO_TABLE . '
1232 WHERE ' . $author_id_sql . '
1233 AND folder_id = ' . PRIVMSGS_NO_BOX;
1234 $result = $db->sql_query($sql);
1235
1236 while ($row = $db->sql_fetchrow($result))
1237 {
1238 $msg_id = (int) $row['msg_id'];
1239 $undelivered_msg[$msg_id] = $msg_id;
1240 }
1241 $db->sql_freeresult($result);
1242
1243 if (empty($delete_ids) && empty($undelivered_msg))
1244 {
1245 return false;
1246 }
1247
1248 $db->sql_transaction('begin');
1249
1250 /* @var $phpbb_notifications \phpbb\notification\manager */
1251 $phpbb_notifications = $phpbb_container->get('notification_manager');
1252
1253 if (!empty($undelivered_msg))
1254 {
1255 // A pm is delivered, if for any recipient the message was moved
1256 // from their NO_BOX to another folder. We do not delete such
1257 // messages, but only delete them for users, who have not yet
1258 // received them.
1259 $sql = 'SELECT msg_id
1260 FROM ' . PRIVMSGS_TO_TABLE . '
1261 WHERE ' . $author_id_sql . '
1262 AND folder_id <> ' . PRIVMSGS_NO_BOX . '
1263 AND folder_id <> ' . PRIVMSGS_OUTBOX . '
1264 AND folder_id <> ' . PRIVMSGS_SENTBOX;
1265 $result = $db->sql_query($sql);
1266
1267 $delivered_msg = array();
1268 while ($row = $db->sql_fetchrow($result))
1269 {
1270 $msg_id = (int) $row['msg_id'];
1271 $delivered_msg[$msg_id] = $msg_id;
1272 unset($undelivered_msg[$msg_id]);
1273 }
1274 $db->sql_freeresult($result);
1275
1276 $undelivered_user = array();
1277
1278 // Count the messages we delete, so we can correct the user pm data
1279 $sql = 'SELECT user_id, COUNT(msg_id) as num_undelivered_privmsgs
1280 FROM ' . PRIVMSGS_TO_TABLE . '
1281 WHERE ' . $author_id_sql . '
1282 AND folder_id = ' . PRIVMSGS_NO_BOX . '
1283 AND ' . $db->sql_in_set('msg_id', array_merge($undelivered_msg, $delivered_msg)) . '
1284 GROUP BY user_id';
1285 $result = $db->sql_query($sql);
1286
1287 while ($row = $db->sql_fetchrow($result))
1288 {
1289 $num_pms = (int) $row['num_undelivered_privmsgs'];
1290 $undelivered_user[$num_pms][] = (int) $row['user_id'];
1291
1292 if (sizeof($undelivered_user[$num_pms]) > 50)
1293 {
1294 // If there are too many users affected the query might get
1295 // too long, so we update the value for the first bunch here.
1296 $sql = 'UPDATE ' . USERS_TABLE . '
1297 SET user_new_privmsg = user_new_privmsg - ' . $num_pms . ',
1298 user_unread_privmsg = user_unread_privmsg - ' . $num_pms . '
1299 WHERE ' . $db->sql_in_set('user_id', $undelivered_user[$num_pms]);
1300 $db->sql_query($sql);
1301 unset($undelivered_user[$num_pms]);
1302 }
1303 }
1304 $db->sql_freeresult($result);
1305
1306 foreach ($undelivered_user as $num_pms => $undelivered_user_set)
1307 {
1308 $sql = 'UPDATE ' . USERS_TABLE . '
1309 SET user_new_privmsg = user_new_privmsg - ' . $num_pms . ',
1310 user_unread_privmsg = user_unread_privmsg - ' . $num_pms . '
1311 WHERE ' . $db->sql_in_set('user_id', $undelivered_user_set);
1312 $db->sql_query($sql);
1313 }
1314
1315 if (!empty($delivered_msg))
1316 {
1317 $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . '
1318 WHERE folder_id = ' . PRIVMSGS_NO_BOX . '
1319 AND ' . $db->sql_in_set('msg_id', $delivered_msg);
1320 $db->sql_query($sql);
1321
1322 $phpbb_notifications->delete_notifications('notification.type.pm', $delivered_msg);
1323 }
1324
1325 if (!empty($undelivered_msg))
1326 {
1327 $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . '
1328 WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg);
1329 $db->sql_query($sql);
1330
1331 $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
1332 WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg);
1333 $db->sql_query($sql);
1334
1335 $phpbb_notifications->delete_notifications('notification.type.pm', $undelivered_msg);
1336 }
1337 }
1338
1339 // Reset the user's pm count to 0
1340 $sql = 'UPDATE ' . USERS_TABLE . '
1341 SET user_new_privmsg = 0,
1342 user_unread_privmsg = 0
1343 WHERE ' . $user_id_sql;
1344 $db->sql_query($sql);
1345
1346 // Delete private message data of the user
1347 $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . '
1348 WHERE ' . $user_id_sql;
1349 $db->sql_query($sql);
1350
1351 if (!empty($delete_ids))
1352 {
1353 // Now we have to check which messages we can delete completely
1354 $sql = 'SELECT msg_id
1355 FROM ' . PRIVMSGS_TO_TABLE . '
1356 WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
1357 $result = $db->sql_query($sql);
1358
1359 while ($row = $db->sql_fetchrow($result))
1360 {
1361 unset($delete_ids[$row['msg_id']]);
1362 }
1363 $db->sql_freeresult($result);
1364
1365 if (!empty($delete_ids))
1366 {
1367 // Check if there are any attachments we need to remove
1368 /** @var \phpbb\attachment\manager $attachment_manager */
1369 $attachment_manager = $phpbb_container->get('attachment.manager');
1370 $attachment_manager->delete('message', $delete_ids, false);
1371 unset($attachment_manager);
1372
1373 $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
1374 WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
1375 $db->sql_query($sql);
1376
1377 $phpbb_notifications->delete_notifications('notification.type.pm', $delete_ids);
1378 }
1379 }
1380
1381 // Set the remaining author id to anonymous
1382 // This way users are still able to read messages from users being removed
1383 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
1384 SET author_id = ' . ANONYMOUS . '
1385 WHERE ' . $author_id_sql;
1386 $db->sql_query($sql);
1387
1388 $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
1389 SET author_id = ' . ANONYMOUS . '
1390 WHERE ' . $author_id_sql;
1391 $db->sql_query($sql);
1392
1393 $db->sql_transaction('commit');
1394
1395 return true;
1396 }
1397
1398 /**
1399 * Rebuild message header
1400 */
1401 function rebuild_header($check_ary)
1402 {
1403 $address = array();
1404
1405 foreach ($check_ary as $check_type => $address_field)
1406 {
1407 // Split Addresses into users and groups
1408 preg_match_all('/:?(u|g)_([0-9]+):?/', $address_field, $match);
1409
1410 $u = $g = array();
1411 foreach ($match[1] as $id => $type)
1412 {
1413 ${$type}[] = (int) $match[2][$id];
1414 }
1415
1416 $_types = array('u', 'g');
1417 foreach ($_types as $type)
1418 {
1419 if (sizeof(${$type}))
1420 {
1421 foreach (${$type} as $id)
1422 {
1423 $address[$type][$id] = $check_type;
1424 }
1425 }
1426 }
1427 }
1428
1429 return $address;
1430 }
1431
1432 /**
1433 * Print out/assign recipient information
1434 */
1435 function write_pm_addresses($check_ary, $author_id, $plaintext = false)
1436 {
1437 global $db, $user, $template, $phpbb_root_path, $phpEx, $phpbb_container;
1438
1439 /** @var \phpbb\group\helper $group_helper */
1440 $group_helper = $phpbb_container->get('group_helper');
1441
1442 $addresses = array();
1443
1444 foreach ($check_ary as $check_type => $address_field)
1445 {
1446 if (!is_array($address_field))
1447 {
1448 // Split Addresses into users and groups
1449 preg_match_all('/:?(u|g)_([0-9]+):?/', $address_field, $match);
1450
1451 $u = $g = array();
1452 foreach ($match[1] as $id => $type)
1453 {
1454 ${$type}[] = (int) $match[2][$id];
1455 }
1456 }
1457 else
1458 {
1459 $u = $address_field['u'];
1460 $g = $address_field['g'];
1461 }
1462
1463 $address = array();
1464 if (sizeof($u))
1465 {
1466 $sql = 'SELECT user_id, username, user_colour
1467 FROM ' . USERS_TABLE . '
1468 WHERE ' . $db->sql_in_set('user_id', $u);
1469 $result = $db->sql_query($sql);
1470
1471 while ($row = $db->sql_fetchrow($result))
1472 {
1473 if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
1474 {
1475 if ($plaintext)
1476 {
1477 $address[] = $row['username'];
1478 }
1479 else
1480 {
1481 $address['user'][$row['user_id']] = array('name' => $row['username'], 'colour' => $row['user_colour']);
1482 }
1483 }
1484 }
1485 $db->sql_freeresult($result);
1486 }
1487
1488 if (sizeof($g))
1489 {
1490 if ($plaintext)
1491 {
1492 $sql = 'SELECT group_name, group_type
1493 FROM ' . GROUPS_TABLE . '
1494 WHERE ' . $db->sql_in_set('group_id', $g);
1495 $result = $db->sql_query($sql);
1496
1497 while ($row = $db->sql_fetchrow($result))
1498 {
1499 if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
1500 {
1501 $address[] = $group_helper->get_name($row['group_name']);
1502 }
1503 }
1504 $db->sql_freeresult($result);
1505 }
1506 else
1507 {
1508 $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_type, ug.user_id
1509 FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug
1510 WHERE ' . $db->sql_in_set('g.group_id', $g) . '
1511 AND g.group_id = ug.group_id
1512 AND ug.user_pending = 0';
1513 $result = $db->sql_query($sql);
1514
1515 while ($row = $db->sql_fetchrow($result))
1516 {
1517 if (!isset($address['group'][$row['group_id']]))
1518 {
1519 if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
1520 {
1521 $row['group_name'] = $group_helper->get_name($row['group_name']);
1522 $address['group'][$row['group_id']] = array('name' => $row['group_name'], 'colour' => $row['group_colour']);
1523 }
1524 }
1525
1526 if (isset($address['user'][$row['user_id']]))
1527 {
1528 $address['user'][$row['user_id']]['in_group'] = $row['group_id'];
1529 }
1530 }
1531 $db->sql_freeresult($result);
1532 }
1533 }
1534
1535 if (sizeof($address) && !$plaintext)
1536 {
1537 $template->assign_var('S_' . strtoupper($check_type) . '_RECIPIENT', true);
1538
1539 foreach ($address as $type => $adr_ary)
1540 {
1541 foreach ($adr_ary as $id => $row)
1542 {
1543 $tpl_ary = array(
1544 'IS_GROUP' => ($type == 'group') ? true : false,
1545 'IS_USER' => ($type == 'user') ? true : false,
1546 'UG_ID' => $id,
1547 'NAME' => $row['name'],
1548 'COLOUR' => ($row['colour']) ? '#' . $row['colour'] : '',
1549 'TYPE' => $type,
1550 );
1551
1552 if ($type == 'user')
1553 {
1554 $tpl_ary = array_merge($tpl_ary, array(
1555 'U_VIEW' => get_username_string('profile', $id, $row['name'], $row['colour']),
1556 'NAME_FULL' => get_username_string('full', $id, $row['name'], $row['colour']),
1557 ));
1558 }
1559 else
1560 {
1561 $tpl_ary = array_merge($tpl_ary, array(
1562 'U_VIEW' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $id),
1563 ));
1564 }
1565
1566 $template->assign_block_vars($check_type . '_recipient', $tpl_ary);
1567 }
1568 }
1569 }
1570
1571 $addresses[$check_type] = $address;
1572 }
1573
1574 return $addresses;
1575 }
1576
1577 /**
1578 * Get folder status
1579 */
1580 function get_folder_status($folder_id, $folder)
1581 {
1582 global $user;
1583
1584 if (isset($folder[$folder_id]))
1585 {
1586 $folder = $folder[$folder_id];
1587 }
1588 else
1589 {
1590 return false;
1591 }
1592
1593 $return = array(
1594 'folder_name' => $folder['folder_name'],
1595 'cur' => $folder['num_messages'],
1596 'remaining' => ($user->data['message_limit']) ? $user->data['message_limit'] - $folder['num_messages'] : 0,
1597 'max' => $user->data['message_limit'],
1598 'percent' => ($user->data['message_limit']) ? (($user->data['message_limit'] > 0) ? floor(($folder['num_messages'] / $user->data['message_limit']) * 100) : 100) : 0,
1599 );
1600
1601 $return['message'] = $user->lang('FOLDER_STATUS_MSG', $user->lang('MESSAGES_COUNT', (int) $return['max']), (int) $return['cur'], $return['percent']);
1602
1603 return $return;
1604 }
1605
1606 //
1607 // COMPOSE MESSAGES
1608 //
1609
1610 /**
1611 * Submit PM
1612 */
1613 function submit_pm($mode, $subject, &$data_ary, $put_in_outbox = true)
1614 {
1615 global $db, $auth, $config, $user, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher, $request;
1616
1617 // We do not handle erasing pms here
1618 if ($mode == 'delete')
1619 {
1620 return false;
1621 }
1622
1623 $current_time = time();
1624
1625 $data = $data_ary;
1626 /**
1627 * Get all parts of the PM that are to be submited to the DB.
1628 *
1629 * @event core.submit_pm_before
1630 * @var string mode PM Post mode - post|reply|quote|quotepost|forward|edit
1631 * @var string subject Subject of the private message
1632 * @var array data The whole row data of the PM.
1633 * @since 3.1.0-b3
1634 */
1635 $vars = array('mode', 'subject', 'data');
1636 extract($phpbb_dispatcher->trigger_event('core.submit_pm_before', compact($vars)));
1637 $data_ary = $data;
1638 unset($data);
1639
1640 // Collect some basic information about which tables and which rows to update/insert
1641 $sql_data = array();
1642 $root_level = 0;
1643
1644 // Recipient Information
1645 $recipients = $to = $bcc = array();
1646
1647 if ($mode != 'edit')
1648 {
1649 // Build Recipient List
1650 // u|g => array($user_id => 'to'|'bcc')
1651 $_types = array('u', 'g');
1652 foreach ($_types as $ug_type)
1653 {
1654 if (isset($data_ary['address_list'][$ug_type]) && sizeof($data_ary['address_list'][$ug_type]))
1655 {
1656 foreach ($data_ary['address_list'][$ug_type] as $id => $field)
1657 {
1658 $id = (int) $id;
1659
1660 // Do not rely on the address list being "valid"
1661 if (!$id || ($ug_type == 'u' && $id == ANONYMOUS))
1662 {
1663 continue;
1664 }
1665
1666 $field = ($field == 'to') ? 'to' : 'bcc';
1667 if ($ug_type == 'u')
1668 {
1669 $recipients[$id] = $field;
1670 }
1671 ${$field}[] = $ug_type . '_' . $id;
1672 }
1673 }
1674 }
1675
1676 if (isset($data_ary['address_list']['g']) && sizeof($data_ary['address_list']['g']))
1677 {
1678 // We need to check the PM status of group members (do they want to receive PM's?)
1679 // Only check if not a moderator or admin, since they are allowed to override this user setting
1680 $sql_allow_pm = (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) ? ' AND u.user_allow_pm = 1' : '';
1681
1682 $sql = 'SELECT u.user_type, ug.group_id, ug.user_id
1683 FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . ' ug
1684 WHERE ' . $db->sql_in_set('ug.group_id', array_keys($data_ary['address_list']['g'])) . '
1685 AND ug.user_pending = 0
1686 AND u.user_id = ug.user_id
1687 AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')' .
1688 $sql_allow_pm;
1689 $result = $db->sql_query($sql);
1690
1691 while ($row = $db->sql_fetchrow($result))
1692 {
1693 $field = ($data_ary['address_list']['g'][$row['group_id']] == 'to') ? 'to' : 'bcc';
1694 $recipients[$row['user_id']] = $field;
1695 }
1696 $db->sql_freeresult($result);
1697 }
1698
1699 if (!sizeof($recipients))
1700 {
1701 trigger_error('NO_RECIPIENT');
1702 }
1703 }
1704
1705 // First of all make sure the subject are having the correct length.
1706 $subject = truncate_string($subject);
1707
1708 $db->sql_transaction('begin');
1709
1710 $sql = '';
1711
1712 switch ($mode)
1713 {
1714 case 'reply':
1715 case 'quote':
1716 $root_level = ($data_ary['reply_from_root_level']) ? $data_ary['reply_from_root_level'] : $data_ary['reply_from_msg_id'];
1717
1718 // Set message_replied switch for this user
1719 $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
1720 SET pm_replied = 1
1721 WHERE user_id = ' . $data_ary['from_user_id'] . '
1722 AND msg_id = ' . $data_ary['reply_from_msg_id'];
1723
1724 // no break
1725
1726 case 'forward':
1727 case 'post':
1728 case 'quotepost':
1729 $sql_data = array(
1730 'root_level' => $root_level,
1731 'author_id' => $data_ary['from_user_id'],
1732 'icon_id' => $data_ary['icon_id'],
1733 'author_ip' => $data_ary['from_user_ip'],
1734 'message_time' => $current_time,
1735 'enable_bbcode' => $data_ary['enable_bbcode'],
1736 'enable_smilies' => $data_ary['enable_smilies'],
1737 'enable_magic_url' => $data_ary['enable_urls'],
1738 'enable_sig' => $data_ary['enable_sig'],
1739 'message_subject' => $subject,
1740 'message_text' => $data_ary['message'],
1741 'message_attachment'=> (!empty($data_ary['attachment_data'])) ? 1 : 0,
1742 'bbcode_bitfield' => $data_ary['bbcode_bitfield'],
1743 'bbcode_uid' => $data_ary['bbcode_uid'],
1744 'to_address' => implode(':', $to),
1745 'bcc_address' => implode(':', $bcc),
1746 'message_reported' => 0,
1747 );
1748 break;
1749
1750 case 'edit':
1751 $sql_data = array(
1752 'icon_id' => $data_ary['icon_id'],
1753 'message_edit_time' => $current_time,
1754 'enable_bbcode' => $data_ary['enable_bbcode'],
1755 'enable_smilies' => $data_ary['enable_smilies'],
1756 'enable_magic_url' => $data_ary['enable_urls'],
1757 'enable_sig' => $data_ary['enable_sig'],
1758 'message_subject' => $subject,
1759 'message_text' => $data_ary['message'],
1760 'message_attachment'=> (!empty($data_ary['attachment_data'])) ? 1 : 0,
1761 'bbcode_bitfield' => $data_ary['bbcode_bitfield'],
1762 'bbcode_uid' => $data_ary['bbcode_uid']
1763 );
1764 break;
1765 }
1766
1767 if (sizeof($sql_data))
1768 {
1769 if ($mode == 'post' || $mode == 'reply' || $mode == 'quote' || $mode == 'quotepost' || $mode == 'forward')
1770 {
1771 $db->sql_query('INSERT INTO ' . PRIVMSGS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_data));
1772 $data_ary['msg_id'] = $db->sql_nextid();
1773 }
1774 else if ($mode == 'edit')
1775 {
1776 $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
1777 SET message_edit_count = message_edit_count + 1, ' . $db->sql_build_array('UPDATE', $sql_data) . '
1778 WHERE msg_id = ' . $data_ary['msg_id'];
1779 $db->sql_query($sql);
1780 }
1781 }
1782
1783 if ($mode != 'edit')
1784 {
1785 if ($sql)
1786 {
1787 $db->sql_query($sql);
1788 }
1789 unset($sql);
1790
1791 $sql_ary = array();
1792 foreach ($recipients as $user_id => $type)
1793 {
1794 $sql_ary[] = array(
1795 'msg_id' => (int) $data_ary['msg_id'],
1796 'user_id' => (int) $user_id,
1797 'author_id' => (int) $data_ary['from_user_id'],
1798 'folder_id' => PRIVMSGS_NO_BOX,
1799 'pm_new' => 1,
1800 'pm_unread' => 1,
1801 'pm_forwarded' => ($mode == 'forward') ? 1 : 0
1802 );
1803 }
1804
1805 $db->sql_multi_insert(PRIVMSGS_TO_TABLE, $sql_ary);
1806
1807 $sql = 'UPDATE ' . USERS_TABLE . '
1808 SET user_new_privmsg = user_new_privmsg + 1, user_unread_privmsg = user_unread_privmsg + 1, user_last_privmsg = ' . time() . '
1809 WHERE ' . $db->sql_in_set('user_id', array_keys($recipients));
1810 $db->sql_query($sql);
1811
1812 // Put PM into outbox
1813 if ($put_in_outbox)
1814 {
1815 $db->sql_query('INSERT INTO ' . PRIVMSGS_TO_TABLE . ' ' . $db->sql_build_array('INSERT', array(
1816 'msg_id' => (int) $data_ary['msg_id'],
1817 'user_id' => (int) $data_ary['from_user_id'],
1818 'author_id' => (int) $data_ary['from_user_id'],
1819 'folder_id' => PRIVMSGS_OUTBOX,
1820 'pm_new' => 0,
1821 'pm_unread' => 0,
1822 'pm_forwarded' => ($mode == 'forward') ? 1 : 0))
1823 );
1824 }
1825 }
1826
1827 // Set user last post time
1828 if ($mode == 'reply' || $mode == 'quote' || $mode == 'quotepost' || $mode == 'forward' || $mode == 'post')
1829 {
1830 $sql = 'UPDATE ' . USERS_TABLE . "
1831 SET user_lastpost_time = $current_time
1832 WHERE user_id = " . $data_ary['from_user_id'];
1833 $db->sql_query($sql);
1834 }
1835
1836 // Submit Attachments
1837 if (!empty($data_ary['attachment_data']) && $data_ary['msg_id'] && in_array($mode, array('post', 'reply', 'quote', 'quotepost', 'edit', 'forward')))
1838 {
1839 $space_taken = $files_added = 0;
1840 $orphan_rows = array();
1841
1842 foreach ($data_ary['attachment_data'] as $pos => $attach_row)
1843 {
1844 $orphan_rows[(int) $attach_row['attach_id']] = array();
1845 }
1846
1847 if (sizeof($orphan_rows))
1848 {
1849 $sql = 'SELECT attach_id, filesize, physical_filename
1850 FROM ' . ATTACHMENTS_TABLE . '
1851 WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan_rows)) . '
1852 AND in_message = 1
1853 AND is_orphan = 1
1854 AND poster_id = ' . $user->data['user_id'];
1855 $result = $db->sql_query($sql);
1856
1857 $orphan_rows = array();
1858 while ($row = $db->sql_fetchrow($result))
1859 {
1860 $orphan_rows[$row['attach_id']] = $row;
1861 }
1862 $db->sql_freeresult($result);
1863 }
1864
1865 foreach ($data_ary['attachment_data'] as $pos => $attach_row)
1866 {
1867 if ($attach_row['is_orphan'] && !isset($orphan_rows[$attach_row['attach_id']]))
1868 {
1869 continue;
1870 }
1871
1872 if (!$attach_row['is_orphan'])
1873 {
1874 // update entry in db if attachment already stored in db and filespace
1875 $sql = 'UPDATE ' . ATTACHMENTS_TABLE . "
1876 SET attach_comment = '" . $db->sql_escape($attach_row['attach_comment']) . "'
1877 WHERE attach_id = " . (int) $attach_row['attach_id'] . '
1878 AND is_orphan = 0';
1879 $db->sql_query($sql);
1880 }
1881 else
1882 {
1883 // insert attachment into db
1884 if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . utf8_basename($orphan_rows[$attach_row['attach_id']]['physical_filename'])))
1885 {
1886 continue;
1887 }
1888
1889 $space_taken += $orphan_rows[$attach_row['attach_id']]['filesize'];
1890 $files_added++;
1891
1892 $attach_sql = array(
1893 'post_msg_id' => $data_ary['msg_id'],
1894 'topic_id' => 0,
1895 'is_orphan' => 0,
1896 'poster_id' => $data_ary['from_user_id'],
1897 'attach_comment' => $attach_row['attach_comment'],
1898 );
1899
1900 $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $attach_sql) . '
1901 WHERE attach_id = ' . $attach_row['attach_id'] . '
1902 AND is_orphan = 1
1903 AND poster_id = ' . $user->data['user_id'];
1904 $db->sql_query($sql);
1905 }
1906 }
1907
1908 if ($space_taken && $files_added)
1909 {
1910 $config->increment('upload_dir_size', $space_taken, false);
1911 $config->increment('num_files', $files_added, false);
1912 }
1913 }
1914
1915 // Delete draft if post was loaded...
1916 $draft_id = $request->variable('draft_loaded', 0);
1917 if ($draft_id)
1918 {
1919 $sql = 'DELETE FROM ' . DRAFTS_TABLE . "
1920 WHERE draft_id = $draft_id
1921 AND user_id = " . $data_ary['from_user_id'];
1922 $db->sql_query($sql);
1923 }
1924
1925 $db->sql_transaction('commit');
1926
1927 // Send Notifications
1928 $pm_data = array_merge($data_ary, array(
1929 'message_subject' => $subject,
1930 'recipients' => $recipients,
1931 ));
1932
1933 /* @var $phpbb_notifications \phpbb\notification\manager */
1934 $phpbb_notifications = $phpbb_container->get('notification_manager');
1935
1936 if ($mode == 'edit')
1937 {
1938 $phpbb_notifications->update_notifications('notification.type.pm', $pm_data);
1939 }
1940 else
1941 {
1942 $phpbb_notifications->add_notifications('notification.type.pm', $pm_data);
1943 }
1944
1945 $data = $data_ary;
1946 /**
1947 * Get PM message ID after submission to DB
1948 *
1949 * @event core.submit_pm_after
1950 * @var string mode PM Post mode - post|reply|quote|quotepost|forward|edit
1951 * @var string subject Subject of the private message
1952 * @var array data The whole row data of the PM.
1953 * @var array pm_data The data sent to notification class
1954 * @since 3.1.0-b5
1955 */
1956 $vars = array('mode', 'subject', 'data', 'pm_data');
1957 extract($phpbb_dispatcher->trigger_event('core.submit_pm_after', compact($vars)));
1958 $data_ary = $data;
1959 unset($data);
1960
1961 return $data_ary['msg_id'];
1962 }
1963
1964 /**
1965 * Display Message History
1966 */
1967 function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode = false)
1968 {
1969 global $db, $user, $template, $phpbb_root_path, $phpEx, $auth;
1970
1971 // Select all receipts and the author from the pm we currently view, to only display their pm-history
1972 $sql = 'SELECT author_id, user_id
1973 FROM ' . PRIVMSGS_TO_TABLE . "
1974 WHERE msg_id = $msg_id
1975 AND folder_id <> " . PRIVMSGS_HOLD_BOX;
1976 $result = $db->sql_query($sql);
1977
1978 $recipients = array();
1979 while ($row = $db->sql_fetchrow($result))
1980 {
1981 $recipients[] = (int) $row['user_id'];
1982 $recipients[] = (int) $row['author_id'];
1983 }
1984 $db->sql_freeresult($result);
1985 $recipients = array_unique($recipients);
1986
1987 // Get History Messages (could be newer)
1988 $sql = 'SELECT t.*, p.*, u.*
1989 FROM ' . PRIVMSGS_TABLE . ' p, ' . PRIVMSGS_TO_TABLE . ' t, ' . USERS_TABLE . ' u
1990 WHERE t.msg_id = p.msg_id
1991 AND p.author_id = u.user_id
1992 AND t.folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
1993 AND ' . $db->sql_in_set('t.author_id', $recipients, false, true) . "
1994 AND t.user_id = $user_id";
1995
1996 // We no longer need those.
1997 unset($recipients);
1998
1999 if (!$message_row['root_level'])
2000 {
2001 $sql .= " AND (p.root_level = $msg_id OR (p.root_level = 0 AND p.msg_id = $msg_id))";
2002 }
2003 else
2004 {
2005 $sql .= " AND (p.root_level = " . $message_row['root_level'] . ' OR p.msg_id = ' . $message_row['root_level'] . ')';
2006 }
2007 $sql .= ' ORDER BY p.message_time DESC';
2008
2009 $result = $db->sql_query($sql);
2010 $row = $db->sql_fetchrow($result);
2011
2012 if (!$row)
2013 {
2014 $db->sql_freeresult($result);
2015 return false;
2016 }
2017
2018 $title = $row['message_subject'];
2019
2020 $rowset = array();
2021 $folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm') . '&folder=';
2022
2023 do
2024 {
2025 $folder_id = (int) $row['folder_id'];
2026
2027 $row['folder'][] = (isset($folder[$folder_id])) ? '<a href="' . $folder_url . $folder_id . '">' . $folder[$folder_id]['folder_name'] . '</a>' : $user->lang['UNKNOWN_FOLDER'];
2028
2029 if (isset($rowset[$row['msg_id']]))
2030 {
2031 $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'];
2032 }
2033 else
2034 {
2035 $rowset[$row['msg_id']] = $row;
2036 }
2037 }
2038 while ($row = $db->sql_fetchrow($result));
2039 $db->sql_freeresult($result);
2040
2041 if (sizeof($rowset) == 1 && !$in_post_mode)
2042 {
2043 return false;
2044 }
2045
2046 $title = censor_text($title);
2047
2048 $url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm');
2049 $next_history_pm = $previous_history_pm = $prev_id = 0;
2050
2051 // Re-order rowset to be able to get the next/prev message rows...
2052 $rowset = array_values($rowset);
2053
2054 for ($i = 0, $size = sizeof($rowset); $i < $size; $i++)
2055 {
2056 $row = &$rowset[$i];
2057 $id = (int) $row['msg_id'];
2058
2059 $author_id = $row['author_id'];
2060 $folder_id = (int) $row['folder_id'];
2061
2062 $subject = $row['message_subject'];
2063 $message = $row['message_text'];
2064
2065 $message = censor_text($message);
2066
2067 $decoded_message = false;
2068
2069 if ($in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS)
2070 {
2071 $decoded_message = $message;
2072 decode_message($decoded_message, $row['bbcode_uid']);
2073
2074 $decoded_message = bbcode_nl2br($decoded_message);
2075 }
2076
2077 $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0);
2078 $parse_flags |= ($row['enable_smilies'] ? OPTION_FLAG_SMILIES : 0);
2079
2080 $message = generate_text_for_display($message, $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false);
2081
2082 $subject = censor_text($subject);
2083
2084 if ($id == $msg_id)
2085 {
2086 $next_history_pm = (isset($rowset[$i + 1])) ? (int) $rowset[$i + 1]['msg_id'] : 0;
2087 $previous_history_pm = $prev_id;
2088 }
2089
2090 $template->assign_block_vars('history_row', array(
2091 'MESSAGE_AUTHOR_QUOTE' => (($decoded_message) ? addslashes(get_username_string('username', $author_id, $row['username'], $row['user_colour'], $row['username'])) : ''),
2092 'MESSAGE_AUTHOR_FULL' => get_username_string('full', $author_id, $row['username'], $row['user_colour'], $row['username']),
2093 'MESSAGE_AUTHOR_COLOUR' => get_username_string('colour', $author_id, $row['username'], $row['user_colour'], $row['username']),
2094 'MESSAGE_AUTHOR' => get_username_string('username', $author_id, $row['username'], $row['user_colour'], $row['username']),
2095 'U_MESSAGE_AUTHOR' => get_username_string('profile', $author_id, $row['username'], $row['user_colour'], $row['username']),
2096
2097 'SUBJECT' => $subject,
2098 'SENT_DATE' => $user->format_date($row['message_time']),
2099 'MESSAGE' => $message,
2100 'FOLDER' => implode($user->lang['COMMA_SEPARATOR'], $row['folder']),
2101 'DECODED_MESSAGE' => $decoded_message,
2102
2103 'S_CURRENT_MSG' => ($row['msg_id'] == $msg_id),
2104 'S_AUTHOR_DELETED' => ($author_id == ANONYMOUS) ? true : false,
2105 'S_IN_POST_MODE' => $in_post_mode,
2106
2107 'MSG_ID' => $row['msg_id'],
2108 'MESSAGE_TIME' => $row['message_time'],
2109 'USER_ID' => $row['user_id'],
2110 'U_VIEW_MESSAGE' => "$url&f=$folder_id&p=" . $row['msg_id'],
2111 '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'] : '',
2112 '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'] : '')
2113 );
2114 unset($rowset[$i]);
2115 $prev_id = $id;
2116 }
2117
2118 $template->assign_vars(array(
2119 'QUOTE_IMG' => $user->img('icon_post_quote', $user->lang['REPLY_WITH_QUOTE']),
2120 'HISTORY_TITLE' => $title,
2121
2122 'U_VIEW_NEXT_HISTORY' => ($next_history_pm) ? "$url&p=" . $next_history_pm : '',
2123 'U_VIEW_PREVIOUS_HISTORY' => ($previous_history_pm) ? "$url&p=" . $previous_history_pm : '',
2124 ));
2125
2126 return true;
2127 }
2128
2129 /**
2130 * Set correct users max messages in PM folder.
2131 * If several group memberships define different amount of messages, the highest will be chosen.
2132 */
2133 function set_user_message_limit()
2134 {
2135 global $user, $db, $config;
2136
2137 // Get maximum about from user memberships
2138 $message_limit = phpbb_get_max_setting_from_group($db, $user->data['user_id'], 'message_limit');
2139
2140 // If it is 0, there is no limit set and we use the maximum value within the config.
2141 $user->data['message_limit'] = (!$message_limit) ? $config['pm_max_msgs'] : $message_limit;
2142 }
2143
2144 /**
2145 * Get the maximum PM setting for the groups of the user
2146 *
2147 * @param \phpbb\db\driver\driver_interface $db
2148 * @param int $user_id
2149 * @param string $setting Only 'max_recipients' and 'message_limit' are supported
2150 * @return int The maximum setting for all groups of the user, unless one group has '0'
2151 * @throws \InvalidArgumentException If selected group setting is not supported
2152 */
2153 function phpbb_get_max_setting_from_group(\phpbb\db\driver\driver_interface $db, $user_id, $setting)
2154 {
2155 if ($setting !== 'max_recipients' && $setting !== 'message_limit')
2156 {
2157 throw new InvalidArgumentException('Setting "' . $setting . '" is not supported');
2158 }
2159
2160 // Get maximum number of allowed recipients
2161 $sql = 'SELECT MAX(g.group_' . $setting . ') as max_setting
2162 FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug
2163 WHERE ug.user_id = ' . (int) $user_id . '
2164 AND ug.user_pending = 0
2165 AND ug.group_id = g.group_id';
2166 $result = $db->sql_query($sql);
2167 $row = $db->sql_fetchrow($result);
2168 $db->sql_freeresult($result);
2169 $max_setting = (int) $row['max_setting'];
2170
2171 return $max_setting;
2172 }
2173
2174 /**
2175 * Generates an array of coloured recipient names from a list of PMs - (groups & users)
2176 *
2177 * @param array $pm_by_id An array of rows from PRIVMSGS_TABLE, keys are the msg_ids.
2178 *
2179 * @return array 2D Array: array(msg_id => array('username or group string', ...), ...)
2180 * Usernames are generated with {@link get_username_string get_username_string}
2181 * Groups are coloured and have a link to the membership page
2182 */
2183 function get_recipient_strings($pm_by_id)
2184 {
2185 global $db, $phpbb_root_path, $phpEx, $user, $phpbb_container;
2186
2187 /** @var \phpbb\group\helper $group_helper */
2188 $group_helper = $phpbb_container->get('group_helper');
2189
2190 $address_list = $recipient_list = $address = array();
2191
2192 $_types = array('u', 'g');
2193
2194 foreach ($pm_by_id as $message_id => $row)
2195 {
2196 $address[$message_id] = rebuild_header(array('to' => $row['to_address'], 'bcc' => $row['bcc_address']));
2197
2198 foreach ($_types as $ug_type)
2199 {
2200 if (isset($address[$message_id][$ug_type]) && sizeof($address[$message_id][$ug_type]))
2201 {
2202 foreach ($address[$message_id][$ug_type] as $ug_id => $in_to)
2203 {
2204 $recipient_list[$ug_type][$ug_id] = array('name' => $user->lang['NA'], 'colour' => '');
2205 }
2206 }
2207 }
2208 }
2209
2210 foreach ($_types as $ug_type)
2211 {
2212 if (!empty($recipient_list[$ug_type]))
2213 {
2214 if ($ug_type == 'u')
2215 {
2216 $sql = 'SELECT user_id as id, username as name, user_colour as colour
2217 FROM ' . USERS_TABLE . '
2218 WHERE ';
2219 }
2220 else
2221 {
2222 $sql = 'SELECT group_id as id, group_name as name, group_colour as colour, group_type
2223 FROM ' . GROUPS_TABLE . '
2224 WHERE ';
2225 }
2226 $sql .= $db->sql_in_set(($ug_type == 'u') ? 'user_id' : 'group_id', array_map('intval', array_keys($recipient_list[$ug_type])));
2227
2228 $result = $db->sql_query($sql);
2229
2230 while ($row = $db->sql_fetchrow($result))
2231 {
2232 if ($ug_type == 'g')
2233 {
2234 $row['name'] = $group_helper->get_name($row['name']);
2235 }
2236
2237 $recipient_list[$ug_type][$row['id']] = array('name' => $row['name'], 'colour' => $row['colour']);
2238 }
2239 $db->sql_freeresult($result);
2240 }
2241 }
2242
2243 foreach ($address as $message_id => $adr_ary)
2244 {
2245 foreach ($adr_ary as $type => $id_ary)
2246 {
2247 foreach ($id_ary as $ug_id => $_id)
2248 {
2249 if ($type == 'u')
2250 {
2251 $address_list[$message_id][] = get_username_string('full', $ug_id, $recipient_list[$type][$ug_id]['name'], $recipient_list[$type][$ug_id]['colour']);
2252 }
2253 else
2254 {
2255 $user_colour = ($recipient_list[$type][$ug_id]['colour']) ? ' style="font-weight: bold; color:#' . $recipient_list[$type][$ug_id]['colour'] . '"' : '';
2256 $link = '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $ug_id) . '"' . $user_colour . '>';
2257 $address_list[$message_id][] = $link . $recipient_list[$type][$ug_id]['name'] . (($link) ? '</a>' : '');
2258 }
2259 }
2260 }
2261 }
2262
2263 return $address_list;
2264 }
2265