[ Index ]

PHP Cross Reference of phpBB-3.3.7-deutsch

title

Body

[close]

/includes/ -> functions_privmsgs.php (source)

   1  <?php
   2  /**
   3  *
   4  * This file is part of the phpBB Forum Software package.
   5  *
   6  * @copyright (c) phpBB Limited <https://www.phpbb.com>
   7  * @license GNU General Public License, version 2 (GPL-2.0)
   8  *
   9  * For full copyright and license information, please see
  10  * the docs/CREDITS.txt file.
  11  *
  12  */
  13  
  14  /**
  15  */
  16  if (!defined('IN_PHPBB'))
  17  {
  18      exit;
  19  }
  20  
  21  /*
  22      Ability to simply add own rules by doing three things:
  23          1) Add an appropriate constant
  24          2) Add a new check array to the global_privmsgs_rules variable and the condition array (if one is required)
  25          3) Implement the rule logic in the check_rule() function
  26          4) Add a new language variable to ucp.php
  27  
  28          The user is then able to select the new rule. It will be checked against and handled as specified.
  29          To add new actions (yes, checks can be added here too) to the rule management, the core code has to be modified.
  30  */
  31  
  32  define('RULE_IS_LIKE', 1);        // Is Like
  33  define('RULE_IS_NOT_LIKE', 2);    // Is Not Like
  34  define('RULE_IS', 3);            // Is
  35  define('RULE_IS_NOT', 4);        // Is Not
  36  define('RULE_BEGINS_WITH', 5);    // Begins with
  37  define('RULE_ENDS_WITH', 6);    // Ends with
  38  define('RULE_IS_FRIEND', 7);    // Is Friend
  39  define('RULE_IS_FOE', 8);        // Is Foe
  40  define('RULE_IS_USER', 9);        // Is User
  41  define('RULE_IS_GROUP', 10);    // Is In Usergroup
  42  define('RULE_ANSWERED', 11);    // Answered
  43  define('RULE_FORWARDED', 12);    // Forwarded
  44  define('RULE_TO_GROUP', 14);    // Usergroup
  45  define('RULE_TO_ME', 15);        // Me
  46  
  47  define('ACTION_PLACE_INTO_FOLDER', 1);
  48  define('ACTION_MARK_AS_READ', 2);
  49  define('ACTION_MARK_AS_IMPORTANT', 3);
  50  define('ACTION_DELETE_MESSAGE', 4);
  51  
  52  define('CHECK_SUBJECT', 1);
  53  define('CHECK_SENDER', 2);
  54  define('CHECK_MESSAGE', 3);
  55  define('CHECK_STATUS', 4);
  56  define('CHECK_TO', 5);
  57  
  58  /**
  59  * Global private message rules
  60  * These rules define what to do if a rule is hit
  61  */
  62  $global_privmsgs_rules = array(
  63      CHECK_SUBJECT    => array(
  64          RULE_IS_LIKE        => array('check0' => 'message_subject'),
  65          RULE_IS_NOT_LIKE    => array('check0' => 'message_subject'),
  66          RULE_IS                => array('check0' => 'message_subject'),
  67          RULE_IS_NOT            => array('check0' => 'message_subject'),
  68          RULE_BEGINS_WITH    => array('check0' => 'message_subject'),
  69          RULE_ENDS_WITH        => array('check0' => 'message_subject'),
  70      ),
  71  
  72      CHECK_SENDER    => array(
  73          RULE_IS_LIKE        => array('check0' => 'username'),
  74          RULE_IS_NOT_LIKE    => array('check0' => 'username'),
  75          RULE_IS                => array('check0' => 'username'),
  76          RULE_IS_NOT            => array('check0' => 'username'),
  77          RULE_BEGINS_WITH    => array('check0' => 'username'),
  78          RULE_ENDS_WITH        => array('check0' => 'username'),
  79          RULE_IS_FRIEND        => array('check0' => 'friend'),
  80          RULE_IS_FOE            => array('check0' => 'foe'),
  81          RULE_IS_USER        => array('check0' => 'author_id'),
  82          RULE_IS_GROUP        => array('check0' => 'author_in_group'),
  83      ),
  84  
  85      CHECK_MESSAGE    => array(
  86          RULE_IS_LIKE        => array('check0' => 'message_text'),
  87          RULE_IS_NOT_LIKE    => array('check0' => 'message_text'),
  88          RULE_IS                => array('check0' => 'message_text'),
  89          RULE_IS_NOT            => array('check0' => 'message_text'),
  90      ),
  91  
  92      CHECK_STATUS    => array(
  93          RULE_ANSWERED        => array('check0' => 'pm_replied'),
  94          RULE_FORWARDED        => array('check0' => 'pm_forwarded'),
  95      ),
  96  
  97      CHECK_TO        => array(
  98          RULE_TO_GROUP        => array('check0' => 'to', 'check1' => 'bcc', 'check2' => 'user_in_group'),
  99          RULE_TO_ME            => array('check0' => 'to', 'check1' => 'bcc'),
 100      )
 101  );
 102  
 103  /**
 104  * This is for defining which condition fields to show for which Rule
 105  */
 106  $global_rule_conditions = array(
 107      RULE_IS_LIKE        => 'text',
 108      RULE_IS_NOT_LIKE    => 'text',
 109      RULE_IS                => 'text',
 110      RULE_IS_NOT            => 'text',
 111      RULE_BEGINS_WITH    => 'text',
 112      RULE_ENDS_WITH        => 'text',
 113      RULE_IS_USER        => 'user',
 114      RULE_IS_GROUP        => 'group'
 115  );
 116  
 117  /**
 118  * Get all folder
 119  */
 120  function get_folder($user_id, $folder_id = false)
 121  {
 122      global $db, $user, $template;
 123      global $phpbb_root_path, $phpEx;
 124  
 125      $folder = array();
 126  
 127      // Get folder information
 128      $sql = 'SELECT folder_id, COUNT(msg_id) as num_messages, SUM(pm_unread) as num_unread
 129          FROM ' . PRIVMSGS_TO_TABLE . "
 130          WHERE user_id = $user_id
 131              AND folder_id <> " . PRIVMSGS_NO_BOX . '
 132          GROUP BY folder_id';
 133      $result = $db->sql_query($sql);
 134  
 135      $num_messages = $num_unread = array();
 136      while ($row = $db->sql_fetchrow($result))
 137      {
 138          $num_messages[(int) $row['folder_id']] = $row['num_messages'];
 139          $num_unread[(int) $row['folder_id']] = $row['num_unread'];
 140      }
 141      $db->sql_freeresult($result);
 142  
 143      // Make sure the default boxes are defined
 144      $available_folder = array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX);
 145  
 146      foreach ($available_folder as $default_folder)
 147      {
 148          if (!isset($num_messages[$default_folder]))
 149          {
 150              $num_messages[$default_folder] = 0;
 151          }
 152  
 153          if (!isset($num_unread[$default_folder]))
 154          {
 155              $num_unread[$default_folder] = 0;
 156          }
 157      }
 158  
 159      // Adjust unread status for outbox
 160      $num_unread[PRIVMSGS_OUTBOX] = $num_messages[PRIVMSGS_OUTBOX];
 161  
 162      $folder[PRIVMSGS_INBOX] = array(
 163          'folder_name'        => $user->lang['PM_INBOX'],
 164          'num_messages'        => $num_messages[PRIVMSGS_INBOX],
 165          'unread_messages'    => $num_unread[PRIVMSGS_INBOX]
 166      );
 167  
 168      // Custom Folder
 169      $sql = 'SELECT folder_id, folder_name, pm_count
 170          FROM ' . PRIVMSGS_FOLDER_TABLE . "
 171              WHERE user_id = $user_id";
 172      $result = $db->sql_query($sql);
 173  
 174      while ($row = $db->sql_fetchrow($result))
 175      {
 176          $folder[$row['folder_id']] = array(
 177              'folder_name'        => $row['folder_name'],
 178              'num_messages'        => $row['pm_count'],
 179              'unread_messages'    => ((isset($num_unread[$row['folder_id']])) ? $num_unread[$row['folder_id']] : 0)
 180          );
 181      }
 182      $db->sql_freeresult($result);
 183  
 184      $folder[PRIVMSGS_OUTBOX] = array(
 185          'folder_name'        => $user->lang['PM_OUTBOX'],
 186          'num_messages'        => $num_messages[PRIVMSGS_OUTBOX],
 187          'unread_messages'    => $num_unread[PRIVMSGS_OUTBOX]
 188      );
 189  
 190      $folder[PRIVMSGS_SENTBOX] = array(
 191          'folder_name'        => $user->lang['PM_SENTBOX'],
 192          'num_messages'        => $num_messages[PRIVMSGS_SENTBOX],
 193          'unread_messages'    => $num_unread[PRIVMSGS_SENTBOX]
 194      );
 195  
 196      // Define Folder Array for template designers (and for making custom folders usable by the template too)
 197      foreach ($folder as $f_id => $folder_ary)
 198      {
 199          $folder_id_name = ($f_id == PRIVMSGS_INBOX) ? 'inbox' : (($f_id == PRIVMSGS_OUTBOX) ? 'outbox' : 'sentbox');
 200  
 201          $template->assign_block_vars('folder', array(
 202              'FOLDER_ID'            => $f_id,
 203              'FOLDER_NAME'        => $folder_ary['folder_name'],
 204              'NUM_MESSAGES'        => $folder_ary['num_messages'],
 205              'UNREAD_MESSAGES'    => $folder_ary['unread_messages'],
 206  
 207              'U_FOLDER'            => ($f_id > 0) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=' . $f_id) : append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=' . $folder_id_name),
 208  
 209              'S_CUR_FOLDER'        => ($f_id === $folder_id) ? true : false,
 210              'S_UNREAD_MESSAGES'    => ($folder_ary['unread_messages']) ? true : false,
 211              'S_CUSTOM_FOLDER'    => ($f_id > 0) ? true : false)
 212          );
 213      }
 214  
 215      if ($folder_id !== false && $folder_id !== PRIVMSGS_HOLD_BOX && !isset($folder[$folder_id]))
 216      {
 217          trigger_error('UNKNOWN_FOLDER');
 218      }
 219  
 220      return $folder;
 221  }
 222  
 223  /**
 224  * Delete Messages From Sentbox
 225  * we are doing this here because this saves us a bunch of checks and queries
 226  */
 227  function clean_sentbox($num_sentbox_messages)
 228  {
 229      global $db, $user;
 230  
 231      // Check Message Limit
 232      if ($user->data['message_limit'] && $num_sentbox_messages > $user->data['message_limit'])
 233      {
 234          // Delete old messages
 235          $sql = 'SELECT t.msg_id
 236              FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p
 237              WHERE t.msg_id = p.msg_id
 238                  AND t.user_id = ' . $user->data['user_id'] . '
 239                  AND t.folder_id = ' . PRIVMSGS_SENTBOX . '
 240              ORDER BY p.message_time ASC';
 241          $result = $db->sql_query_limit($sql, ($num_sentbox_messages - $user->data['message_limit']));
 242  
 243          $delete_ids = array();
 244          while ($row = $db->sql_fetchrow($result))
 245          {
 246              $delete_ids[] = $row['msg_id'];
 247          }
 248          $db->sql_freeresult($result);
 249          delete_pm($user->data['user_id'], $delete_ids, PRIVMSGS_SENTBOX);
 250      }
 251  }
 252  
 253  /**
 254  * Check Rule against Message Information
 255  */
 256  function check_rule(&$rules, &$rule_row, &$message_row, $user_id)
 257  {
 258      if (!isset($rules[$rule_row['rule_check']][$rule_row['rule_connection']]))
 259      {
 260          return false;
 261      }
 262  
 263      $check_ary = $rules[$rule_row['rule_check']][$rule_row['rule_connection']];
 264  
 265      $result = false;
 266  
 267      $check0 = $message_row[$check_ary['check0']];
 268  
 269      switch ($rule_row['rule_connection'])
 270      {
 271          case RULE_IS_LIKE:
 272              $result = preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0);
 273          break;
 274  
 275          case RULE_IS_NOT_LIKE:
 276              $result = !preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0);
 277          break;
 278  
 279          case RULE_IS:
 280              $result = ($check0 == $rule_row['rule_string']);
 281          break;
 282  
 283          case RULE_IS_NOT:
 284              $result = ($check0 != $rule_row['rule_string']);
 285          break;
 286  
 287          case RULE_BEGINS_WITH:
 288              $result = preg_match("/^" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0);
 289          break;
 290  
 291          case RULE_ENDS_WITH:
 292              $result = preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '$/i', $check0);
 293          break;
 294  
 295          case RULE_IS_FRIEND:
 296          case RULE_IS_FOE:
 297          case RULE_ANSWERED:
 298          case RULE_FORWARDED:
 299              $result = ($check0 == 1);
 300          break;
 301  
 302          case RULE_IS_USER:
 303              $result = ($check0 == $rule_row['rule_user_id']);
 304          break;
 305  
 306          case RULE_IS_GROUP:
 307              $result = in_array($rule_row['rule_group_id'], $check0);
 308          break;
 309  
 310          case RULE_TO_GROUP:
 311              $result = (in_array('g_' . $message_row[$check_ary['check2']], $check0) || in_array('g_' . $message_row[$check_ary['check2']], $message_row[$check_ary['check1']]));
 312          break;
 313  
 314          case RULE_TO_ME:
 315              $result = (in_array('u_' . $user_id, $check0) || in_array('u_' . $user_id, $message_row[$check_ary['check1']]));
 316          break;
 317      }
 318  
 319      if (!$result)
 320      {
 321          return false;
 322      }
 323  
 324      switch ($rule_row['rule_action'])
 325      {
 326          case ACTION_PLACE_INTO_FOLDER:
 327              return array('action' => $rule_row['rule_action'], 'folder_id' => $rule_row['rule_folder_id']);
 328          break;
 329  
 330          case ACTION_MARK_AS_READ:
 331          case ACTION_MARK_AS_IMPORTANT:
 332              return array('action' => $rule_row['rule_action'], 'pm_unread' => $message_row['pm_unread'], 'pm_marked' => $message_row['pm_marked']);
 333          break;
 334  
 335          case ACTION_DELETE_MESSAGE:
 336              global $db;
 337  
 338              // Check for admins/mods - users are not allowed to remove those messages...
 339              // We do the check here to make sure the data we use is consistent
 340              $sql = 'SELECT user_id, user_type, user_permissions
 341                  FROM ' . USERS_TABLE . '
 342                  WHERE user_id = ' . (int) $message_row['author_id'];
 343              $result = $db->sql_query($sql);
 344              $userdata = $db->sql_fetchrow($result);
 345              $db->sql_freeresult($result);
 346  
 347              $auth2 = new \phpbb\auth\auth();
 348              $auth2->acl($userdata);
 349  
 350              if (!$auth2->acl_get('a_') && !$auth2->acl_get('m_') && !$auth2->acl_getf_global('m_'))
 351              {
 352                  return array('action' => $rule_row['rule_action'], 'pm_unread' => $message_row['pm_unread'], 'pm_marked' => $message_row['pm_marked']);
 353              }
 354  
 355              return false;
 356          break;
 357  
 358          default:
 359              return false;
 360      }
 361  
 362      return false;
 363  }
 364  
 365  /**
 366  * Update user PM count
 367  */
 368  function update_pm_counts()
 369  {
 370      global $user, $db;
 371  
 372      // Update unread count
 373      $sql = 'SELECT COUNT(msg_id) as num_messages
 374          FROM ' . PRIVMSGS_TO_TABLE . '
 375          WHERE pm_unread = 1
 376              AND folder_id <> ' . PRIVMSGS_OUTBOX . '
 377              AND user_id = ' . $user->data['user_id'];
 378      $result = $db->sql_query($sql);
 379      $user->data['user_unread_privmsg'] = (int) $db->sql_fetchfield('num_messages');
 380      $db->sql_freeresult($result);
 381  
 382      // Update new pm count
 383      $sql = 'SELECT COUNT(msg_id) as num_messages
 384          FROM ' . PRIVMSGS_TO_TABLE . '
 385          WHERE pm_new = 1
 386              AND folder_id IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
 387              AND user_id = ' . $user->data['user_id'];
 388      $result = $db->sql_query($sql);
 389      $user->data['user_new_privmsg'] = (int) $db->sql_fetchfield('num_messages');
 390      $db->sql_freeresult($result);
 391  
 392      $db->sql_query('UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array(
 393          'user_unread_privmsg'    => (int) $user->data['user_unread_privmsg'],
 394          'user_new_privmsg'        => (int) $user->data['user_new_privmsg'],
 395      )) . ' WHERE user_id = ' . $user->data['user_id']);
 396  
 397      // Ok, here we need to repair something, other boxes than privmsgs_no_box and privmsgs_hold_box should not carry the pm_new flag.
 398      if (!$user->data['user_new_privmsg'])
 399      {
 400          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 401              SET pm_new = 0
 402              WHERE pm_new = 1
 403                  AND folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
 404                  AND user_id = ' . $user->data['user_id'];
 405          $db->sql_query($sql);
 406      }
 407  }
 408  
 409  /**
 410  * Place new messages into appropriate folder
 411  */
 412  function place_pm_into_folder(&$global_privmsgs_rules, $release = false)
 413  {
 414      global $db, $user, $config;
 415  
 416      if (!$user->data['user_new_privmsg'])
 417      {
 418          return array('not_moved' => 0, 'removed' => 0);
 419      }
 420  
 421      $user_message_rules = (int) $user->data['user_message_rules'];
 422      $user_id = (int) $user->data['user_id'];
 423  
 424      $action_ary = $move_into_folder = array();
 425      $num_removed = 0;
 426  
 427      // Newly processing on-hold messages
 428      if ($release)
 429      {
 430          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 431              SET folder_id = ' . PRIVMSGS_NO_BOX . '
 432              WHERE folder_id = ' . PRIVMSGS_HOLD_BOX . "
 433                  AND user_id = $user_id";
 434          $db->sql_query($sql);
 435      }
 436  
 437      // Get those messages not yet placed into any box
 438      $retrieve_sql = 'SELECT t.*, p.*, u.username, u.user_id, u.group_id
 439          FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p, ' . USERS_TABLE . " u
 440          WHERE t.user_id = $user_id
 441              AND p.author_id = u.user_id
 442              AND t.folder_id = " . PRIVMSGS_NO_BOX . '
 443              AND t.msg_id = p.msg_id';
 444  
 445      // Just place into the appropriate arrays if no rules need to be checked
 446      if (!$user_message_rules)
 447      {
 448          $result = $db->sql_query($retrieve_sql);
 449  
 450          while ($row = $db->sql_fetchrow($result))
 451          {
 452              $action_ary[$row['msg_id']][] = array('action' => false);
 453          }
 454          $db->sql_freeresult($result);
 455      }
 456      else
 457      {
 458          $user_rules = $zebra = $check_rows = array();
 459          $user_ids = $memberships = array();
 460  
 461          // First of all, grab all rules and retrieve friends/foes
 462          $sql = 'SELECT *
 463              FROM ' . PRIVMSGS_RULES_TABLE . "
 464              WHERE user_id = $user_id";
 465          $result = $db->sql_query($sql);
 466          $user_rules = $db->sql_fetchrowset($result);
 467          $db->sql_freeresult($result);
 468  
 469          if (count($user_rules))
 470          {
 471              $sql = 'SELECT zebra_id, friend, foe
 472                  FROM ' . ZEBRA_TABLE . "
 473                  WHERE user_id = $user_id";
 474              $result = $db->sql_query($sql);
 475  
 476              while ($row = $db->sql_fetchrow($result))
 477              {
 478                  $zebra[$row['zebra_id']] = $row;
 479              }
 480              $db->sql_freeresult($result);
 481          }
 482  
 483          // Now build a bare-bone check_row array
 484          $result = $db->sql_query($retrieve_sql);
 485  
 486          while ($row = $db->sql_fetchrow($result))
 487          {
 488              $check_rows[] = array_merge($row, array(
 489                  'to'                => explode(':', $row['to_address']),
 490                  'bcc'                => explode(':', $row['bcc_address']),
 491                  'friend'            => (isset($zebra[$row['author_id']])) ? $zebra[$row['author_id']]['friend'] : 0,
 492                  'foe'                => (isset($zebra[$row['author_id']])) ? $zebra[$row['author_id']]['foe'] : 0,
 493                  'user_in_group'        => $user->data['group_id'],
 494                  'author_in_group'    => array())
 495              );
 496  
 497              $user_ids[] = $row['user_id'];
 498          }
 499          $db->sql_freeresult($result);
 500  
 501          // Retrieve user memberships
 502          if (count($user_ids))
 503          {
 504              $sql = 'SELECT *
 505                  FROM ' . USER_GROUP_TABLE . '
 506                  WHERE ' . $db->sql_in_set('user_id', $user_ids) . '
 507                      AND user_pending = 0';
 508              $result = $db->sql_query($sql);
 509  
 510              while ($row = $db->sql_fetchrow($result))
 511              {
 512                  $memberships[$row['user_id']][] = $row['group_id'];
 513              }
 514              $db->sql_freeresult($result);
 515          }
 516  
 517          // Now place into the appropriate folder
 518          foreach ($check_rows as $row)
 519          {
 520              // Add membership if set
 521              if (isset($memberships[$row['author_id']]))
 522              {
 523                  $row['author_in_group'] = $memberships[$row['user_id']];
 524              }
 525  
 526              // Check Rule - this should be very quick since we have all information we need
 527              $is_match = false;
 528              foreach ($user_rules as $rule_row)
 529              {
 530                  if (($action = check_rule($global_privmsgs_rules, $rule_row, $row, $user_id)) !== false)
 531                  {
 532                      $is_match = true;
 533                      $action_ary[$row['msg_id']][] = $action;
 534                  }
 535              }
 536  
 537              if (!$is_match)
 538              {
 539                  $action_ary[$row['msg_id']][] = array('action' => false);
 540              }
 541          }
 542  
 543          unset($user_rules, $zebra, $check_rows, $user_ids, $memberships);
 544      }
 545  
 546      // We place actions into arrays, to save queries.
 547      $unread_ids = $delete_ids = $important_ids = array();
 548  
 549      foreach ($action_ary as $msg_id => $msg_ary)
 550      {
 551          // It is allowed to execute actions more than once, except placing messages into folder
 552          $folder_action = $message_removed = false;
 553  
 554          foreach ($msg_ary as $pos => $rule_ary)
 555          {
 556              if ($folder_action && $rule_ary['action'] == ACTION_PLACE_INTO_FOLDER)
 557              {
 558                  continue;
 559              }
 560  
 561              switch ($rule_ary['action'])
 562              {
 563                  case ACTION_PLACE_INTO_FOLDER:
 564                      // Folder actions have precedence, so we will remove any other ones
 565                      $folder_action = true;
 566                      $move_into_folder[(int) $rule_ary['folder_id']][] = $msg_id;
 567                  break;
 568  
 569                  case ACTION_MARK_AS_READ:
 570                      if ($rule_ary['pm_unread'])
 571                      {
 572                          $unread_ids[] = $msg_id;
 573                      }
 574                  break;
 575  
 576                  case ACTION_DELETE_MESSAGE:
 577                      $delete_ids[] = $msg_id;
 578                      $message_removed = true;
 579                  break;
 580  
 581                  case ACTION_MARK_AS_IMPORTANT:
 582                      if (!$rule_ary['pm_marked'])
 583                      {
 584                          $important_ids[] = $msg_id;
 585                      }
 586                  break;
 587              }
 588          }
 589  
 590          // 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
 591          // folder. Here we simply move the message into the INBOX if it gets not removed and also not put into a custom folder.
 592          if (!$folder_action && !$message_removed)
 593          {
 594              $move_into_folder[PRIVMSGS_INBOX][] = $msg_id;
 595          }
 596      }
 597  
 598      // Do not change the order of processing
 599      // The number of queries needed to be executed here highly depends on the defined rules and are
 600      // only gone through if new messages arrive.
 601  
 602      // Delete messages
 603      if (count($delete_ids))
 604      {
 605          $num_removed += count($delete_ids);
 606          delete_pm($user_id, $delete_ids, PRIVMSGS_NO_BOX);
 607      }
 608  
 609      // Set messages to Unread
 610      if (count($unread_ids))
 611      {
 612          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 613              SET pm_unread = 0
 614              WHERE ' . $db->sql_in_set('msg_id', $unread_ids) . "
 615                  AND user_id = $user_id
 616                  AND folder_id = " . PRIVMSGS_NO_BOX;
 617          $db->sql_query($sql);
 618      }
 619  
 620      // mark messages as important
 621      if (count($important_ids))
 622      {
 623          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 624              SET pm_marked = 1 - pm_marked
 625              WHERE folder_id = ' . PRIVMSGS_NO_BOX . "
 626                  AND user_id = $user_id
 627                  AND " . $db->sql_in_set('msg_id', $important_ids);
 628          $db->sql_query($sql);
 629      }
 630  
 631      // Move into folder
 632      $folder = array();
 633  
 634      if (count($move_into_folder))
 635      {
 636          // Determine Full Folder Action - we need the move to folder id later eventually
 637          $full_folder_action = ($user->data['user_full_folder'] == FULL_FOLDER_NONE) ? ($config['full_folder_action'] - (FULL_FOLDER_NONE*(-1))) : $user->data['user_full_folder'];
 638  
 639          $sql_folder = array_keys($move_into_folder);
 640          if ($full_folder_action >= 0)
 641          {
 642              $sql_folder[] = $full_folder_action;
 643          }
 644  
 645          $sql = 'SELECT folder_id, pm_count
 646              FROM ' . PRIVMSGS_FOLDER_TABLE . '
 647              WHERE ' . $db->sql_in_set('folder_id', $sql_folder) . "
 648                  AND user_id = $user_id";
 649          $result = $db->sql_query($sql);
 650  
 651          while ($row = $db->sql_fetchrow($result))
 652          {
 653              $folder[(int) $row['folder_id']] = (int) $row['pm_count'];
 654          }
 655          $db->sql_freeresult($result);
 656  
 657          unset($sql_folder);
 658  
 659          if (isset($move_into_folder[PRIVMSGS_INBOX]))
 660          {
 661              $sql = 'SELECT COUNT(msg_id) as num_messages
 662                  FROM ' . PRIVMSGS_TO_TABLE . "
 663                  WHERE user_id = $user_id
 664                      AND folder_id = " . PRIVMSGS_INBOX;
 665              $result = $db->sql_query($sql);
 666              $folder[PRIVMSGS_INBOX] = (int) $db->sql_fetchfield('num_messages');
 667              $db->sql_freeresult($result);
 668          }
 669      }
 670  
 671      // Here we have ideally only one folder to move into
 672      foreach ($move_into_folder as $folder_id => $msg_ary)
 673      {
 674          $dest_folder = $folder_id;
 675          $full_folder_action = FULL_FOLDER_NONE;
 676  
 677          // Check Message Limit - we calculate with the complete array, most of the time it is one message
 678          // But we are making sure that the other way around works too (more messages in queue than allowed to be stored)
 679          if ($user->data['message_limit'] && $folder[$folder_id] && ($folder[$folder_id] + count($msg_ary)) > $user->data['message_limit'])
 680          {
 681              $full_folder_action = ($user->data['user_full_folder'] == FULL_FOLDER_NONE) ? ($config['full_folder_action'] - (FULL_FOLDER_NONE*(-1))) : $user->data['user_full_folder'];
 682  
 683              // If destination folder itself is full...
 684              if ($full_folder_action >= 0 && ($folder[$full_folder_action] + count($msg_ary)) > $user->data['message_limit'])
 685              {
 686                  $full_folder_action = $config['full_folder_action'] - (FULL_FOLDER_NONE*(-1));
 687              }
 688  
 689              // If Full Folder Action is to move to another folder, we simply adjust the destination folder
 690              if ($full_folder_action >= 0)
 691              {
 692                  $dest_folder = $full_folder_action;
 693              }
 694              else if ($full_folder_action == FULL_FOLDER_DELETE)
 695              {
 696                  // Delete some messages. NOTE: Ordered by msg_id here instead of message_time!
 697                  $sql = 'SELECT msg_id
 698                      FROM ' . PRIVMSGS_TO_TABLE . "
 699                      WHERE user_id = $user_id
 700                          AND folder_id = $dest_folder
 701                      ORDER BY msg_id ASC";
 702                  $result = $db->sql_query_limit($sql, (($folder[$dest_folder] + count($msg_ary)) - $user->data['message_limit']));
 703  
 704                  $delete_ids = array();
 705                  while ($row = $db->sql_fetchrow($result))
 706                  {
 707                      $delete_ids[] = $row['msg_id'];
 708                  }
 709                  $db->sql_freeresult($result);
 710  
 711                  $num_removed += count($delete_ids);
 712                  delete_pm($user_id, $delete_ids, $dest_folder);
 713              }
 714          }
 715  
 716          //
 717          if ($full_folder_action == FULL_FOLDER_HOLD)
 718          {
 719              $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 720                  SET folder_id = ' . PRIVMSGS_HOLD_BOX . '
 721                  WHERE folder_id = ' . PRIVMSGS_NO_BOX . "
 722                      AND user_id = $user_id
 723                      AND " . $db->sql_in_set('msg_id', $msg_ary);
 724              $db->sql_query($sql);
 725          }
 726          else
 727          {
 728              $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
 729                  SET folder_id = $dest_folder, pm_new = 0
 730                  WHERE folder_id = " . PRIVMSGS_NO_BOX . "
 731                      AND user_id = $user_id
 732                      AND pm_new = 1
 733                      AND " . $db->sql_in_set('msg_id', $msg_ary);
 734              $db->sql_query($sql);
 735  
 736              if ($dest_folder != PRIVMSGS_INBOX)
 737              {
 738                  $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . '
 739                      SET pm_count = pm_count + ' . (int) $db->sql_affectedrows() . "
 740                      WHERE folder_id = $dest_folder
 741                          AND user_id = $user_id";
 742                  $db->sql_query($sql);
 743              }
 744          }
 745      }
 746  
 747      if (count($action_ary))
 748      {
 749          // Move from OUTBOX to SENTBOX
 750          // We are not checking any full folder status here... SENTBOX is a special treatment (old messages get deleted)
 751          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 752              SET folder_id = ' . PRIVMSGS_SENTBOX . '
 753              WHERE folder_id = ' . PRIVMSGS_OUTBOX . '
 754                  AND ' . $db->sql_in_set('msg_id', array_keys($action_ary));
 755          $db->sql_query($sql);
 756      }
 757  
 758      // Update new/unread count
 759      update_pm_counts();
 760  
 761      // Now check how many messages got not moved...
 762      $sql = 'SELECT COUNT(msg_id) as num_messages
 763          FROM ' . PRIVMSGS_TO_TABLE . "
 764          WHERE user_id = $user_id
 765              AND folder_id = " . PRIVMSGS_HOLD_BOX;
 766      $result = $db->sql_query($sql);
 767      $num_not_moved = (int) $db->sql_fetchfield('num_messages');
 768      $db->sql_freeresult($result);
 769  
 770      return array('not_moved' => $num_not_moved, 'removed' => $num_removed);
 771  }
 772  
 773  /**
 774  * Move PM from one to another folder
 775  */
 776  function move_pm($user_id, $message_limit, $move_msg_ids, $dest_folder, $cur_folder_id)
 777  {
 778      global $db, $user;
 779      global $phpbb_root_path, $phpEx;
 780  
 781      $num_moved = 0;
 782  
 783      if (!is_array($move_msg_ids))
 784      {
 785          $move_msg_ids = array($move_msg_ids);
 786      }
 787  
 788      if (count($move_msg_ids) && !in_array($dest_folder, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX)) &&
 789          !in_array($cur_folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)) && $cur_folder_id != $dest_folder)
 790      {
 791          // We have to check the destination folder ;)
 792          if ($dest_folder != PRIVMSGS_INBOX)
 793          {
 794              $sql = 'SELECT folder_id, folder_name, pm_count
 795                  FROM ' . PRIVMSGS_FOLDER_TABLE . "
 796                  WHERE folder_id = $dest_folder
 797                      AND user_id = $user_id";
 798              $result = $db->sql_query($sql);
 799              $row = $db->sql_fetchrow($result);
 800              $db->sql_freeresult($result);
 801  
 802              if (!$row)
 803              {
 804                  send_status_line(403, 'Forbidden');
 805                  trigger_error('NOT_AUTHORISED');
 806              }
 807  
 808              if ($message_limit && $row['pm_count'] + count($move_msg_ids) > $message_limit)
 809              {
 810                  $message = sprintf($user->lang['NOT_ENOUGH_SPACE_FOLDER'], $row['folder_name']) . '<br /><br />';
 811                  $message .= sprintf($user->lang['CLICK_RETURN_FOLDER'], '<a href="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=' . $row['folder_id']) . '">', '</a>', $row['folder_name']);
 812                  trigger_error($message);
 813              }
 814          }
 815          else
 816          {
 817              $sql = 'SELECT COUNT(msg_id) as num_messages
 818                  FROM ' . PRIVMSGS_TO_TABLE . '
 819                  WHERE folder_id = ' . PRIVMSGS_INBOX . "
 820                      AND user_id = $user_id";
 821              $result = $db->sql_query($sql);
 822              $num_messages = (int) $db->sql_fetchfield('num_messages');
 823              $db->sql_freeresult($result);
 824  
 825              if ($message_limit && $num_messages + count($move_msg_ids) > $message_limit)
 826              {
 827                  $message = sprintf($user->lang['NOT_ENOUGH_SPACE_FOLDER'], $user->lang['PM_INBOX']) . '<br /><br />';
 828                  $message .= sprintf($user->lang['CLICK_RETURN_FOLDER'], '<a href="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=inbox') . '">', '</a>', $user->lang['PM_INBOX']);
 829                  trigger_error($message);
 830              }
 831          }
 832  
 833          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
 834              SET folder_id = $dest_folder
 835              WHERE folder_id = $cur_folder_id
 836                  AND user_id = $user_id
 837                  AND " . $db->sql_in_set('msg_id', $move_msg_ids);
 838          $db->sql_query($sql);
 839          $num_moved = $db->sql_affectedrows();
 840  
 841          // Update pm counts
 842          if ($num_moved)
 843          {
 844              if (!in_array($cur_folder_id, array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX)))
 845              {
 846                  $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . "
 847                      SET pm_count = pm_count - $num_moved
 848                      WHERE folder_id = $cur_folder_id
 849                          AND user_id = $user_id";
 850                  $db->sql_query($sql);
 851              }
 852  
 853              if ($dest_folder != PRIVMSGS_INBOX)
 854              {
 855                  $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . "
 856                      SET pm_count = pm_count + $num_moved
 857                      WHERE folder_id = $dest_folder
 858                          AND user_id = $user_id";
 859                  $db->sql_query($sql);
 860              }
 861          }
 862      }
 863      else if (in_array($cur_folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)))
 864      {
 865          trigger_error('CANNOT_MOVE_SPECIAL');
 866      }
 867  
 868      return $num_moved;
 869  }
 870  
 871  /**
 872  * Update unread message status
 873  */
 874  function update_unread_status($unread, $msg_id, $user_id, $folder_id)
 875  {
 876      if (!$unread)
 877      {
 878          return;
 879      }
 880  
 881      global $db, $user, $phpbb_container;
 882  
 883      /* @var $phpbb_notifications \phpbb\notification\manager */
 884      $phpbb_notifications = $phpbb_container->get('notification_manager');
 885  
 886      $phpbb_notifications->mark_notifications('notification.type.pm', $msg_id, $user_id);
 887  
 888      $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
 889          SET pm_unread = 0
 890          WHERE msg_id = $msg_id
 891              AND user_id = $user_id
 892              AND folder_id = $folder_id
 893              AND pm_unread = 1";
 894      $db->sql_query($sql);
 895  
 896      // If the message is already marked as read, we just skip the rest to avoid negative PM count
 897      if (!$db->sql_affectedrows())
 898      {
 899          return;
 900      }
 901  
 902      $sql = 'UPDATE ' . USERS_TABLE . "
 903          SET user_unread_privmsg = user_unread_privmsg - 1
 904          WHERE user_id = $user_id";
 905      $db->sql_query($sql);
 906  
 907      if ($user->data['user_id'] == $user_id)
 908      {
 909          $user->data['user_unread_privmsg']--;
 910  
 911          // Try to cope with previous wrong conversions...
 912          if ($user->data['user_unread_privmsg'] < 0)
 913          {
 914              $sql = 'UPDATE ' . USERS_TABLE . "
 915                  SET user_unread_privmsg = 0
 916                  WHERE user_id = $user_id";
 917              $db->sql_query($sql);
 918  
 919              $user->data['user_unread_privmsg'] = 0;
 920          }
 921      }
 922  }
 923  
 924  function mark_folder_read($user_id, $folder_id)
 925  {
 926      global $db;
 927  
 928      $sql = 'SELECT msg_id
 929          FROM ' . PRIVMSGS_TO_TABLE . '
 930          WHERE folder_id = ' . ((int) $folder_id) . '
 931              AND user_id = ' . ((int) $user_id) . '
 932              AND pm_unread = 1';
 933      $result = $db->sql_query($sql);
 934  
 935      while ($row = $db->sql_fetchrow($result))
 936      {
 937          update_unread_status(true, $row['msg_id'], $user_id, $folder_id);
 938      }
 939      $db->sql_freeresult($result);
 940  }
 941  
 942  /**
 943  * Handle all actions possible with marked messages
 944  */
 945  function handle_mark_actions($user_id, $mark_action)
 946  {
 947      global $db, $user, $phpbb_root_path, $phpEx, $request;
 948  
 949      $msg_ids        = $request->variable('marked_msg_id', array(0));
 950      $cur_folder_id    = $request->variable('cur_folder_id', PRIVMSGS_NO_BOX);
 951  
 952      if (!count($msg_ids))
 953      {
 954          return false;
 955      }
 956  
 957      switch ($mark_action)
 958      {
 959          case 'mark_important':
 960  
 961              if (!check_form_key('ucp_pm_view'))
 962              {
 963                  trigger_error('FORM_INVALID');
 964              }
 965  
 966              $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
 967                  SET pm_marked = 1 - pm_marked
 968                  WHERE folder_id = $cur_folder_id
 969                      AND user_id = $user_id
 970                      AND " . $db->sql_in_set('msg_id', $msg_ids);
 971              $db->sql_query($sql);
 972  
 973          break;
 974  
 975          case 'delete_marked':
 976  
 977              global $auth;
 978  
 979              if (!$auth->acl_get('u_pm_delete'))
 980              {
 981                  send_status_line(403, 'Forbidden');
 982                  trigger_error('NO_AUTH_DELETE_MESSAGE');
 983              }
 984  
 985              if (confirm_box(true))
 986              {
 987                  delete_pm($user_id, $msg_ids, $cur_folder_id);
 988  
 989                  $success_msg = (count($msg_ids) == 1) ? 'MESSAGE_DELETED' : 'MESSAGES_DELETED';
 990                  $redirect = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=' . $cur_folder_id);
 991  
 992                  meta_refresh(3, $redirect);
 993                  trigger_error($user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_FOLDER'], '<a href="' . $redirect . '">', '</a>'));
 994              }
 995              else
 996              {
 997                  $s_hidden_fields = array(
 998                      'cur_folder_id'    => $cur_folder_id,
 999                      '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&amp;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);
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') . '&amp;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&amp;f=$folder_id&amp;p=" . $row['msg_id'],
2147              'U_QUOTE'            => (!$in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS) ? "$url&amp;mode=compose&amp;action=quote&amp;f=" . $folder_id . "&amp;p=" . $row['msg_id'] : '',
2148              'U_POST_REPLY_PM'    => ($author_id != $user->data['user_id'] && $author_id != ANONYMOUS && $auth->acl_get('u_sendpm')) ? "$url&amp;mode=compose&amp;action=reply&amp;f=$folder_id&amp;p=" . $row['msg_id'] : ''
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&amp;p=" . $next_history_pm : '',
2176          'U_VIEW_PREVIOUS_HISTORY'    => ($previous_history_pm) ? "$url&amp;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&amp;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  }


Generated: Thu Mar 24 21:31:15 2022 Cross-referenced by PHPXref 0.7.1