[ Index ]

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


Generated: Sun Feb 19 19:47:08 2017 Cross-referenced by PHPXref 0.7.1