[ Index ]

PHP Cross Reference of phpBB-3.1.10-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, $config;
 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      global $user, $config;
 259  
 260      if (!isset($rules[$rule_row['rule_check']][$rule_row['rule_connection']]))
 261      {
 262          return false;
 263      }
 264  
 265      $check_ary = $rules[$rule_row['rule_check']][$rule_row['rule_connection']];
 266  
 267      $result = false;
 268  
 269      $check0 = $message_row[$check_ary['check0']];
 270  
 271      switch ($rule_row['rule_connection'])
 272      {
 273          case RULE_IS_LIKE:
 274              $result = preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0);
 275          break;
 276  
 277          case RULE_IS_NOT_LIKE:
 278              $result = !preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0);
 279          break;
 280  
 281          case RULE_IS:
 282              $result = ($check0 == $rule_row['rule_string']);
 283          break;
 284  
 285          case RULE_IS_NOT:
 286              $result = ($check0 != $rule_row['rule_string']);
 287          break;
 288  
 289          case RULE_BEGINS_WITH:
 290              $result = preg_match("/^" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0);
 291          break;
 292  
 293          case RULE_ENDS_WITH:
 294              $result = preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '$/i', $check0);
 295          break;
 296  
 297          case RULE_IS_FRIEND:
 298          case RULE_IS_FOE:
 299          case RULE_ANSWERED:
 300          case RULE_FORWARDED:
 301              $result = ($check0 == 1);
 302          break;
 303  
 304          case RULE_IS_USER:
 305              $result = ($check0 == $rule_row['rule_user_id']);
 306          break;
 307  
 308          case RULE_IS_GROUP:
 309              $result = in_array($rule_row['rule_group_id'], $check0);
 310          break;
 311  
 312          case RULE_TO_GROUP:
 313              $result = (in_array('g_' . $message_row[$check_ary['check2']], $check0) || in_array('g_' . $message_row[$check_ary['check2']], $message_row[$check_ary['check1']]));
 314          break;
 315  
 316          case RULE_TO_ME:
 317              $result = (in_array('u_' . $user_id, $check0) || in_array('u_' . $user_id, $message_row[$check_ary['check1']]));
 318          break;
 319      }
 320  
 321      if (!$result)
 322      {
 323          return false;
 324      }
 325  
 326      switch ($rule_row['rule_action'])
 327      {
 328          case ACTION_PLACE_INTO_FOLDER:
 329              return array('action' => $rule_row['rule_action'], 'folder_id' => $rule_row['rule_folder_id']);
 330          break;
 331  
 332          case ACTION_MARK_AS_READ:
 333          case ACTION_MARK_AS_IMPORTANT:
 334              return array('action' => $rule_row['rule_action'], 'pm_unread' => $message_row['pm_unread'], 'pm_marked' => $message_row['pm_marked']);
 335          break;
 336  
 337          case ACTION_DELETE_MESSAGE:
 338              global $db, $auth;
 339  
 340              // Check for admins/mods - users are not allowed to remove those messages...
 341              // We do the check here to make sure the data we use is consistent
 342              $sql = 'SELECT user_id, user_type, user_permissions
 343                  FROM ' . USERS_TABLE . '
 344                  WHERE user_id = ' . (int) $message_row['author_id'];
 345              $result = $db->sql_query($sql);
 346              $userdata = $db->sql_fetchrow($result);
 347              $db->sql_freeresult($result);
 348  
 349              $auth2 = new \phpbb\auth\auth();
 350              $auth2->acl($userdata);
 351  
 352              if (!$auth2->acl_get('a_') && !$auth2->acl_get('m_') && !$auth2->acl_getf_global('m_'))
 353              {
 354                  return array('action' => $rule_row['rule_action'], 'pm_unread' => $message_row['pm_unread'], 'pm_marked' => $message_row['pm_marked']);
 355              }
 356  
 357              return false;
 358          break;
 359  
 360          default:
 361              return false;
 362      }
 363  
 364      return false;
 365  }
 366  
 367  /**
 368  * Update user PM count
 369  */
 370  function update_pm_counts()
 371  {
 372      global $user, $db;
 373  
 374      // Update unread count
 375      $sql = 'SELECT COUNT(msg_id) as num_messages
 376          FROM ' . PRIVMSGS_TO_TABLE . '
 377          WHERE pm_unread = 1
 378              AND folder_id <> ' . PRIVMSGS_OUTBOX . '
 379              AND user_id = ' . $user->data['user_id'];
 380      $result = $db->sql_query($sql);
 381      $user->data['user_unread_privmsg'] = (int) $db->sql_fetchfield('num_messages');
 382      $db->sql_freeresult($result);
 383  
 384      // Update new pm count
 385      $sql = 'SELECT COUNT(msg_id) as num_messages
 386          FROM ' . PRIVMSGS_TO_TABLE . '
 387          WHERE pm_new = 1
 388              AND folder_id IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
 389              AND user_id = ' . $user->data['user_id'];
 390      $result = $db->sql_query($sql);
 391      $user->data['user_new_privmsg'] = (int) $db->sql_fetchfield('num_messages');
 392      $db->sql_freeresult($result);
 393  
 394      $db->sql_query('UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array(
 395          'user_unread_privmsg'    => (int) $user->data['user_unread_privmsg'],
 396          'user_new_privmsg'        => (int) $user->data['user_new_privmsg'],
 397      )) . ' WHERE user_id = ' . $user->data['user_id']);
 398  
 399      // Ok, here we need to repair something, other boxes than privmsgs_no_box and privmsgs_hold_box should not carry the pm_new flag.
 400      if (!$user->data['user_new_privmsg'])
 401      {
 402          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 403              SET pm_new = 0
 404              WHERE pm_new = 1
 405                  AND folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
 406                  AND user_id = ' . $user->data['user_id'];
 407          $db->sql_query($sql);
 408      }
 409  }
 410  
 411  /**
 412  * Place new messages into appropriate folder
 413  */
 414  function place_pm_into_folder(&$global_privmsgs_rules, $release = false)
 415  {
 416      global $db, $user, $config;
 417  
 418      if (!$user->data['user_new_privmsg'])
 419      {
 420          return array('not_moved' => 0, 'removed' => 0);
 421      }
 422  
 423      $user_message_rules = (int) $user->data['user_message_rules'];
 424      $user_id = (int) $user->data['user_id'];
 425  
 426      $action_ary = $move_into_folder = array();
 427      $num_removed = 0;
 428  
 429      // Newly processing on-hold messages
 430      if ($release)
 431      {
 432          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 433              SET folder_id = ' . PRIVMSGS_NO_BOX . '
 434              WHERE folder_id = ' . PRIVMSGS_HOLD_BOX . "
 435                  AND user_id = $user_id";
 436          $db->sql_query($sql);
 437      }
 438  
 439      // Get those messages not yet placed into any box
 440      $retrieve_sql = 'SELECT t.*, p.*, u.username, u.user_id, u.group_id
 441          FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p, ' . USERS_TABLE . " u
 442          WHERE t.user_id = $user_id
 443              AND p.author_id = u.user_id
 444              AND t.folder_id = " . PRIVMSGS_NO_BOX . '
 445              AND t.msg_id = p.msg_id';
 446  
 447      // Just place into the appropriate arrays if no rules need to be checked
 448      if (!$user_message_rules)
 449      {
 450          $result = $db->sql_query($retrieve_sql);
 451  
 452          while ($row = $db->sql_fetchrow($result))
 453          {
 454              $action_ary[$row['msg_id']][] = array('action' => false);
 455          }
 456          $db->sql_freeresult($result);
 457      }
 458      else
 459      {
 460          $user_rules = $zebra = $check_rows = array();
 461          $user_ids = $memberships = array();
 462  
 463          // First of all, grab all rules and retrieve friends/foes
 464          $sql = 'SELECT *
 465              FROM ' . PRIVMSGS_RULES_TABLE . "
 466              WHERE user_id = $user_id";
 467          $result = $db->sql_query($sql);
 468          $user_rules = $db->sql_fetchrowset($result);
 469          $db->sql_freeresult($result);
 470  
 471          if (sizeof($user_rules))
 472          {
 473              $sql = 'SELECT zebra_id, friend, foe
 474                  FROM ' . ZEBRA_TABLE . "
 475                  WHERE user_id = $user_id";
 476              $result = $db->sql_query($sql);
 477  
 478              while ($row = $db->sql_fetchrow($result))
 479              {
 480                  $zebra[$row['zebra_id']] = $row;
 481              }
 482              $db->sql_freeresult($result);
 483          }
 484  
 485          // Now build a bare-bone check_row array
 486          $result = $db->sql_query($retrieve_sql);
 487  
 488          while ($row = $db->sql_fetchrow($result))
 489          {
 490              $check_rows[] = array_merge($row, array(
 491                  'to'                => explode(':', $row['to_address']),
 492                  'bcc'                => explode(':', $row['bcc_address']),
 493                  'friend'            => (isset($zebra[$row['author_id']])) ? $zebra[$row['author_id']]['friend'] : 0,
 494                  'foe'                => (isset($zebra[$row['author_id']])) ? $zebra[$row['author_id']]['foe'] : 0,
 495                  'user_in_group'        => array($user->data['group_id']),
 496                  'author_in_group'    => array())
 497              );
 498  
 499              $user_ids[] = $row['user_id'];
 500          }
 501          $db->sql_freeresult($result);
 502  
 503          // Retrieve user memberships
 504          if (sizeof($user_ids))
 505          {
 506              $sql = 'SELECT *
 507                  FROM ' . USER_GROUP_TABLE . '
 508                  WHERE ' . $db->sql_in_set('user_id', $user_ids) . '
 509                      AND user_pending = 0';
 510              $result = $db->sql_query($sql);
 511  
 512              while ($row = $db->sql_fetchrow($result))
 513              {
 514                  $memberships[$row['user_id']][] = $row['group_id'];
 515              }
 516              $db->sql_freeresult($result);
 517          }
 518  
 519          // Now place into the appropriate folder
 520          foreach ($check_rows as $row)
 521          {
 522              // Add membership if set
 523              if (isset($memberships[$row['author_id']]))
 524              {
 525                  $row['author_in_group'] = $memberships[$row['user_id']];
 526              }
 527  
 528              // Check Rule - this should be very quick since we have all information we need
 529              $is_match = false;
 530              foreach ($user_rules as $rule_row)
 531              {
 532                  if (($action = check_rule($global_privmsgs_rules, $rule_row, $row, $user_id)) !== false)
 533                  {
 534                      $is_match = true;
 535                      $action_ary[$row['msg_id']][] = $action;
 536                  }
 537              }
 538  
 539              if (!$is_match)
 540              {
 541                  $action_ary[$row['msg_id']][] = array('action' => false);
 542              }
 543          }
 544  
 545          unset($user_rules, $zebra, $check_rows, $user_ids, $memberships);
 546      }
 547  
 548      // We place actions into arrays, to save queries.
 549      $sql = $unread_ids = $delete_ids = $important_ids = array();
 550  
 551      foreach ($action_ary as $msg_id => $msg_ary)
 552      {
 553          // It is allowed to execute actions more than once, except placing messages into folder
 554          $folder_action = $message_removed = false;
 555  
 556          foreach ($msg_ary as $pos => $rule_ary)
 557          {
 558              if ($folder_action && $rule_ary['action'] == ACTION_PLACE_INTO_FOLDER)
 559              {
 560                  continue;
 561              }
 562  
 563              switch ($rule_ary['action'])
 564              {
 565                  case ACTION_PLACE_INTO_FOLDER:
 566                      // Folder actions have precedence, so we will remove any other ones
 567                      $folder_action = true;
 568                      $move_into_folder[(int) $rule_ary['folder_id']][] = $msg_id;
 569                  break;
 570  
 571                  case ACTION_MARK_AS_READ:
 572                      if ($rule_ary['pm_unread'])
 573                      {
 574                          $unread_ids[] = $msg_id;
 575                      }
 576                  break;
 577  
 578                  case ACTION_DELETE_MESSAGE:
 579                      $delete_ids[] = $msg_id;
 580                      $message_removed = true;
 581                  break;
 582  
 583                  case ACTION_MARK_AS_IMPORTANT:
 584                      if (!$rule_ary['pm_marked'])
 585                      {
 586                          $important_ids[] = $msg_id;
 587                      }
 588                  break;
 589              }
 590          }
 591  
 592          // 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
 593          // folder. Here we simply move the message into the INBOX if it gets not removed and also not put into a custom folder.
 594          if (!$folder_action && !$message_removed)
 595          {
 596              $move_into_folder[PRIVMSGS_INBOX][] = $msg_id;
 597          }
 598      }
 599  
 600      // Do not change the order of processing
 601      // The number of queries needed to be executed here highly depends on the defined rules and are
 602      // only gone through if new messages arrive.
 603  
 604      // Delete messages
 605      if (sizeof($delete_ids))
 606      {
 607          $num_removed += sizeof($delete_ids);
 608          delete_pm($user_id, $delete_ids, PRIVMSGS_NO_BOX);
 609      }
 610  
 611      // Set messages to Unread
 612      if (sizeof($unread_ids))
 613      {
 614          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 615              SET pm_unread = 0
 616              WHERE ' . $db->sql_in_set('msg_id', $unread_ids) . "
 617                  AND user_id = $user_id
 618                  AND folder_id = " . PRIVMSGS_NO_BOX;
 619          $db->sql_query($sql);
 620      }
 621  
 622      // mark messages as important
 623      if (sizeof($important_ids))
 624      {
 625          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 626              SET pm_marked = 1 - pm_marked
 627              WHERE folder_id = ' . PRIVMSGS_NO_BOX . "
 628                  AND user_id = $user_id
 629                  AND " . $db->sql_in_set('msg_id', $important_ids);
 630          $db->sql_query($sql);
 631      }
 632  
 633      // Move into folder
 634      $folder = array();
 635  
 636      if (sizeof($move_into_folder))
 637      {
 638          // Determine Full Folder Action - we need the move to folder id later eventually
 639          $full_folder_action = ($user->data['user_full_folder'] == FULL_FOLDER_NONE) ? ($config['full_folder_action'] - (FULL_FOLDER_NONE*(-1))) : $user->data['user_full_folder'];
 640  
 641          $sql_folder = array_keys($move_into_folder);
 642          if ($full_folder_action >= 0)
 643          {
 644              $sql_folder[] = $full_folder_action;
 645          }
 646  
 647          $sql = 'SELECT folder_id, pm_count
 648              FROM ' . PRIVMSGS_FOLDER_TABLE . '
 649              WHERE ' . $db->sql_in_set('folder_id', $sql_folder) . "
 650                  AND user_id = $user_id";
 651          $result = $db->sql_query($sql);
 652  
 653          while ($row = $db->sql_fetchrow($result))
 654          {
 655              $folder[(int) $row['folder_id']] = (int) $row['pm_count'];
 656          }
 657          $db->sql_freeresult($result);
 658  
 659          unset($sql_folder);
 660  
 661          if (isset($move_into_folder[PRIVMSGS_INBOX]))
 662          {
 663              $sql = 'SELECT COUNT(msg_id) as num_messages
 664                  FROM ' . PRIVMSGS_TO_TABLE . "
 665                  WHERE user_id = $user_id
 666                      AND folder_id = " . PRIVMSGS_INBOX;
 667              $result = $db->sql_query($sql);
 668              $folder[PRIVMSGS_INBOX] = (int) $db->sql_fetchfield('num_messages');
 669              $db->sql_freeresult($result);
 670          }
 671      }
 672  
 673      // Here we have ideally only one folder to move into
 674      foreach ($move_into_folder as $folder_id => $msg_ary)
 675      {
 676          $dest_folder = $folder_id;
 677          $full_folder_action = FULL_FOLDER_NONE;
 678  
 679          // Check Message Limit - we calculate with the complete array, most of the time it is one message
 680          // But we are making sure that the other way around works too (more messages in queue than allowed to be stored)
 681          if ($user->data['message_limit'] && $folder[$folder_id] && ($folder[$folder_id] + sizeof($msg_ary)) > $user->data['message_limit'])
 682          {
 683              $full_folder_action = ($user->data['user_full_folder'] == FULL_FOLDER_NONE) ? ($config['full_folder_action'] - (FULL_FOLDER_NONE*(-1))) : $user->data['user_full_folder'];
 684  
 685              // If destination folder itself is full...
 686              if ($full_folder_action >= 0 && ($folder[$full_folder_action] + sizeof($msg_ary)) > $user->data['message_limit'])
 687              {
 688                  $full_folder_action = $config['full_folder_action'] - (FULL_FOLDER_NONE*(-1));
 689              }
 690  
 691              // If Full Folder Action is to move to another folder, we simply adjust the destination folder
 692              if ($full_folder_action >= 0)
 693              {
 694                  $dest_folder = $full_folder_action;
 695              }
 696              else if ($full_folder_action == FULL_FOLDER_DELETE)
 697              {
 698                  // Delete some messages. NOTE: Ordered by msg_id here instead of message_time!
 699                  $sql = 'SELECT msg_id
 700                      FROM ' . PRIVMSGS_TO_TABLE . "
 701                      WHERE user_id = $user_id
 702                          AND folder_id = $dest_folder
 703                      ORDER BY msg_id ASC";
 704                  $result = $db->sql_query_limit($sql, (($folder[$dest_folder] + sizeof($msg_ary)) - $user->data['message_limit']));
 705  
 706                  $delete_ids = array();
 707                  while ($row = $db->sql_fetchrow($result))
 708                  {
 709                      $delete_ids[] = $row['msg_id'];
 710                  }
 711                  $db->sql_freeresult($result);
 712  
 713                  $num_removed += sizeof($delete_ids);
 714                  delete_pm($user_id, $delete_ids, $dest_folder);
 715              }
 716          }
 717  
 718          //
 719          if ($full_folder_action == FULL_FOLDER_HOLD)
 720          {
 721              $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 722                  SET folder_id = ' . PRIVMSGS_HOLD_BOX . '
 723                  WHERE folder_id = ' . PRIVMSGS_NO_BOX . "
 724                      AND user_id = $user_id
 725                      AND " . $db->sql_in_set('msg_id', $msg_ary);
 726              $db->sql_query($sql);
 727          }
 728          else
 729          {
 730              $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
 731                  SET folder_id = $dest_folder, pm_new = 0
 732                  WHERE folder_id = " . PRIVMSGS_NO_BOX . "
 733                      AND user_id = $user_id
 734                      AND pm_new = 1
 735                      AND " . $db->sql_in_set('msg_id', $msg_ary);
 736              $db->sql_query($sql);
 737  
 738              if ($dest_folder != PRIVMSGS_INBOX)
 739              {
 740                  $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . '
 741                      SET pm_count = pm_count + ' . (int) $db->sql_affectedrows() . "
 742                      WHERE folder_id = $dest_folder
 743                          AND user_id = $user_id";
 744                  $db->sql_query($sql);
 745              }
 746          }
 747      }
 748  
 749      if (sizeof($action_ary))
 750      {
 751          // Move from OUTBOX to SENTBOX
 752          // We are not checking any full folder status here... SENTBOX is a special treatment (old messages get deleted)
 753          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 754              SET folder_id = ' . PRIVMSGS_SENTBOX . '
 755              WHERE folder_id = ' . PRIVMSGS_OUTBOX . '
 756                  AND ' . $db->sql_in_set('msg_id', array_keys($action_ary));
 757          $db->sql_query($sql);
 758      }
 759  
 760      // Update new/unread count
 761      update_pm_counts();
 762  
 763      // Now check how many messages got not moved...
 764      $sql = 'SELECT COUNT(msg_id) as num_messages
 765          FROM ' . PRIVMSGS_TO_TABLE . "
 766          WHERE user_id = $user_id
 767              AND folder_id = " . PRIVMSGS_HOLD_BOX;
 768      $result = $db->sql_query($sql);
 769      $num_not_moved = (int) $db->sql_fetchfield('num_messages');
 770      $db->sql_freeresult($result);
 771  
 772      return array('not_moved' => $num_not_moved, 'removed' => $num_removed);
 773  }
 774  
 775  /**
 776  * Move PM from one to another folder
 777  */
 778  function move_pm($user_id, $message_limit, $move_msg_ids, $dest_folder, $cur_folder_id)
 779  {
 780      global $db, $user;
 781      global $phpbb_root_path, $phpEx;
 782  
 783      $num_moved = 0;
 784  
 785      if (!is_array($move_msg_ids))
 786      {
 787          $move_msg_ids = array($move_msg_ids);
 788      }
 789  
 790      if (sizeof($move_msg_ids) && !in_array($dest_folder, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX)) &&
 791          !in_array($cur_folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)) && $cur_folder_id != $dest_folder)
 792      {
 793          // We have to check the destination folder ;)
 794          if ($dest_folder != PRIVMSGS_INBOX)
 795          {
 796              $sql = 'SELECT folder_id, folder_name, pm_count
 797                  FROM ' . PRIVMSGS_FOLDER_TABLE . "
 798                  WHERE folder_id = $dest_folder
 799                      AND user_id = $user_id";
 800              $result = $db->sql_query($sql);
 801              $row = $db->sql_fetchrow($result);
 802              $db->sql_freeresult($result);
 803  
 804              if (!$row)
 805              {
 806                  trigger_error('NOT_AUTHORISED');
 807              }
 808  
 809              if ($message_limit && $row['pm_count'] + sizeof($move_msg_ids) > $message_limit)
 810              {
 811                  $message = sprintf($user->lang['NOT_ENOUGH_SPACE_FOLDER'], $row['folder_name']) . '<br /><br />';
 812                  $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']);
 813                  trigger_error($message);
 814              }
 815          }
 816          else
 817          {
 818              $sql = 'SELECT COUNT(msg_id) as num_messages
 819                  FROM ' . PRIVMSGS_TO_TABLE . '
 820                  WHERE folder_id = ' . PRIVMSGS_INBOX . "
 821                      AND user_id = $user_id";
 822              $result = $db->sql_query($sql);
 823              $num_messages = (int) $db->sql_fetchfield('num_messages');
 824              $db->sql_freeresult($result);
 825  
 826              if ($message_limit && $num_messages + sizeof($move_msg_ids) > $message_limit)
 827              {
 828                  $message = sprintf($user->lang['NOT_ENOUGH_SPACE_FOLDER'], $user->lang['PM_INBOX']) . '<br /><br />';
 829                  $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']);
 830                  trigger_error($message);
 831              }
 832          }
 833  
 834          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
 835              SET folder_id = $dest_folder
 836              WHERE folder_id = $cur_folder_id
 837                  AND user_id = $user_id
 838                  AND " . $db->sql_in_set('msg_id', $move_msg_ids);
 839          $db->sql_query($sql);
 840          $num_moved = $db->sql_affectedrows();
 841  
 842          // Update pm counts
 843          if ($num_moved)
 844          {
 845              if (!in_array($cur_folder_id, array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX)))
 846              {
 847                  $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . "
 848                      SET pm_count = pm_count - $num_moved
 849                      WHERE folder_id = $cur_folder_id
 850                          AND user_id = $user_id";
 851                  $db->sql_query($sql);
 852              }
 853  
 854              if ($dest_folder != PRIVMSGS_INBOX)
 855              {
 856                  $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . "
 857                      SET pm_count = pm_count + $num_moved
 858                      WHERE folder_id = $dest_folder
 859                          AND user_id = $user_id";
 860                  $db->sql_query($sql);
 861              }
 862          }
 863      }
 864      else if (in_array($cur_folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)))
 865      {
 866          trigger_error('CANNOT_MOVE_SPECIAL');
 867      }
 868  
 869      return $num_moved;
 870  }
 871  
 872  /**
 873  * Update unread message status
 874  */
 875  function update_unread_status($unread, $msg_id, $user_id, $folder_id)
 876  {
 877      if (!$unread)
 878      {
 879          return;
 880      }
 881  
 882      global $db, $user, $phpbb_container;
 883  
 884      $phpbb_notifications = $phpbb_container->get('notification_manager');
 885  
 886      $phpbb_notifications->mark_notifications_read('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      $db->sql_query($sql);
 894  
 895      $sql = 'UPDATE ' . USERS_TABLE . "
 896          SET user_unread_privmsg = user_unread_privmsg - 1
 897          WHERE user_id = $user_id";
 898      $db->sql_query($sql);
 899  
 900      if ($user->data['user_id'] == $user_id)
 901      {
 902          $user->data['user_unread_privmsg']--;
 903  
 904          // Try to cope with previous wrong conversions...
 905          if ($user->data['user_unread_privmsg'] < 0)
 906          {
 907              $sql = 'UPDATE ' . USERS_TABLE . "
 908                  SET user_unread_privmsg = 0
 909                  WHERE user_id = $user_id";
 910              $db->sql_query($sql);
 911  
 912              $user->data['user_unread_privmsg'] = 0;
 913          }
 914      }
 915  }
 916  
 917  function mark_folder_read($user_id, $folder_id)
 918  {
 919      global $db;
 920  
 921      $sql = 'SELECT msg_id
 922          FROM ' . PRIVMSGS_TO_TABLE . '
 923          WHERE folder_id = ' . ((int) $folder_id) . '
 924              AND user_id = ' . ((int) $user_id) . '
 925              AND pm_unread = 1';
 926      $result = $db->sql_query($sql);
 927  
 928      while ($row = $db->sql_fetchrow($result))
 929      {
 930          update_unread_status(true, $row['msg_id'], $user_id, $folder_id);
 931      }
 932      $db->sql_freeresult($result);
 933  }
 934  
 935  /**
 936  * Handle all actions possible with marked messages
 937  */
 938  function handle_mark_actions($user_id, $mark_action)
 939  {
 940      global $db, $user, $phpbb_root_path, $phpEx;
 941  
 942      $msg_ids        = request_var('marked_msg_id', array(0));
 943      $cur_folder_id    = request_var('cur_folder_id', PRIVMSGS_NO_BOX);
 944      $confirm        = (isset($_POST['confirm'])) ? true : false;
 945  
 946      if (!sizeof($msg_ids))
 947      {
 948          return false;
 949      }
 950  
 951      switch ($mark_action)
 952      {
 953          case 'mark_important':
 954  
 955              $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
 956                  SET pm_marked = 1 - pm_marked
 957                  WHERE folder_id = $cur_folder_id
 958                      AND user_id = $user_id
 959                      AND " . $db->sql_in_set('msg_id', $msg_ids);
 960              $db->sql_query($sql);
 961  
 962          break;
 963  
 964          case 'delete_marked':
 965  
 966              global $auth;
 967  
 968              if (!$auth->acl_get('u_pm_delete'))
 969              {
 970                  trigger_error('NO_AUTH_DELETE_MESSAGE');
 971              }
 972  
 973              if (confirm_box(true))
 974              {
 975                  delete_pm($user_id, $msg_ids, $cur_folder_id);
 976  
 977                  $success_msg = (sizeof($msg_ids) == 1) ? 'MESSAGE_DELETED' : 'MESSAGES_DELETED';
 978                  $redirect = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=' . $cur_folder_id);
 979  
 980                  meta_refresh(3, $redirect);
 981                  trigger_error($user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_FOLDER'], '<a href="' . $redirect . '">', '</a>'));
 982              }
 983              else
 984              {
 985                  $s_hidden_fields = array(
 986                      'cur_folder_id'    => $cur_folder_id,
 987                      'mark_option'    => 'delete_marked',
 988                      'submit_mark'    => true,
 989                      'marked_msg_id'    => $msg_ids
 990                  );
 991  
 992                  confirm_box(false, 'DELETE_MARKED_PM', build_hidden_fields($s_hidden_fields));
 993              }
 994  
 995          break;
 996  
 997          default:
 998              return false;
 999      }
1000  
1001      return true;
1002  }
1003  
1004  /**
1005  * Delete PM(s)
1006  */
1007  function delete_pm($user_id, $msg_ids, $folder_id)
1008  {
1009      global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_dispatcher;
1010  
1011      $user_id    = (int) $user_id;
1012      $folder_id    = (int) $folder_id;
1013  
1014      if (!$user_id)
1015      {
1016          return false;
1017      }
1018  
1019      if (!is_array($msg_ids))
1020      {
1021          if (!$msg_ids)
1022          {
1023              return false;
1024          }
1025          $msg_ids = array($msg_ids);
1026      }
1027  
1028      if (!sizeof($msg_ids))
1029      {
1030          return false;
1031      }
1032  
1033      /**
1034      * Get all info for PM(s) before they are deleted
1035      *
1036      * @event core.delete_pm_before
1037      * @var    int    user_id     ID of the user requested the message delete
1038      * @var    array    msg_ids    array of all messages to be deleted
1039      * @var    int    folder_id    ID of the user folder where the messages are stored
1040      * @since 3.1.0-b5
1041      */
1042      $vars = array('user_id', 'msg_ids', 'folder_id');
1043      extract($phpbb_dispatcher->trigger_event('core.delete_pm_before', compact($vars)));
1044  
1045      // Get PM Information for later deleting
1046      $sql = 'SELECT msg_id, pm_unread, pm_new
1047          FROM ' . PRIVMSGS_TO_TABLE . '
1048          WHERE ' . $db->sql_in_set('msg_id', array_map('intval', $msg_ids)) . "
1049              AND folder_id = $folder_id
1050              AND user_id = $user_id";
1051      $result = $db->sql_query($sql);
1052  
1053      $delete_rows = array();
1054      $num_unread = $num_new = $num_deleted = 0;
1055      while ($row = $db->sql_fetchrow($result))
1056      {
1057          $num_unread += (int) $row['pm_unread'];
1058          $num_new += (int) $row['pm_new'];
1059  
1060          $delete_rows[$row['msg_id']] = 1;
1061      }
1062      $db->sql_freeresult($result);
1063      unset($msg_ids);
1064  
1065      if (!sizeof($delete_rows))
1066      {
1067          return false;
1068      }
1069  
1070      $db->sql_transaction('begin');
1071  
1072      // if no one has read the message yet (meaning it is in users outbox)
1073      // then mark the message as deleted...
1074      if ($folder_id == PRIVMSGS_OUTBOX)
1075      {
1076          // Remove PM from Outbox
1077          $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . "
1078              WHERE user_id = $user_id AND folder_id = " . PRIVMSGS_OUTBOX . '
1079                  AND ' . $db->sql_in_set('msg_id', array_keys($delete_rows));
1080          $db->sql_query($sql);
1081  
1082          // Update PM Information for safety
1083          $sql = 'UPDATE ' . PRIVMSGS_TABLE . " SET message_text = ''
1084              WHERE " . $db->sql_in_set('msg_id', array_keys($delete_rows));
1085          $db->sql_query($sql);
1086  
1087          // Set delete flag for those intended to receive the PM
1088          // We do not remove the message actually, to retain some basic information (sent time for example)
1089          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
1090              SET pm_deleted = 1
1091              WHERE ' . $db->sql_in_set('msg_id', array_keys($delete_rows));
1092          $db->sql_query($sql);
1093  
1094          $num_deleted = $db->sql_affectedrows();
1095      }
1096      else
1097      {
1098          // Delete private message data
1099          $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . "
1100              WHERE user_id = $user_id
1101                  AND folder_id = $folder_id
1102                  AND " . $db->sql_in_set('msg_id', array_keys($delete_rows));
1103          $db->sql_query($sql);
1104          $num_deleted = $db->sql_affectedrows();
1105      }
1106  
1107      // if folder id is user defined folder then decrease pm_count
1108      if (!in_array($folder_id, array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX, PRIVMSGS_NO_BOX)))
1109      {
1110          $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . "
1111              SET pm_count = pm_count - $num_deleted
1112              WHERE folder_id = $folder_id";
1113          $db->sql_query($sql);
1114      }
1115  
1116      // Update unread and new status field
1117      if ($num_unread || $num_new)
1118      {
1119          $set_sql = ($num_unread) ? 'user_unread_privmsg = user_unread_privmsg - ' . $num_unread : '';
1120  
1121          if ($num_new)
1122          {
1123              $set_sql .= ($set_sql != '') ? ', ' : '';
1124              $set_sql .= 'user_new_privmsg = user_new_privmsg - ' . $num_new;
1125          }
1126  
1127          $db->sql_query('UPDATE ' . USERS_TABLE . " SET $set_sql WHERE user_id = $user_id");
1128  
1129          $user->data['user_new_privmsg'] -= $num_new;
1130          $user->data['user_unread_privmsg'] -= $num_unread;
1131      }
1132  
1133      $phpbb_notifications = $phpbb_container->get('notification_manager');
1134  
1135      $phpbb_notifications->delete_notifications('notification.type.pm', array_keys($delete_rows));
1136  
1137      // Now we have to check which messages we can delete completely
1138      $sql = 'SELECT msg_id
1139          FROM ' . PRIVMSGS_TO_TABLE . '
1140          WHERE ' . $db->sql_in_set('msg_id', array_keys($delete_rows));
1141      $result = $db->sql_query($sql);
1142  
1143      while ($row = $db->sql_fetchrow($result))
1144      {
1145          unset($delete_rows[$row['msg_id']]);
1146      }
1147      $db->sql_freeresult($result);
1148  
1149      $delete_ids = array_keys($delete_rows);
1150  
1151      if (sizeof($delete_ids))
1152      {
1153          // Check if there are any attachments we need to remove
1154          if (!function_exists('delete_attachments'))
1155          {
1156              include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
1157          }
1158  
1159          delete_attachments('message', $delete_ids, false);
1160  
1161          $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
1162              WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
1163          $db->sql_query($sql);
1164      }
1165  
1166      $db->sql_transaction('commit');
1167  
1168      return true;
1169  }
1170  
1171  /**
1172  * Delete all PM(s) for a given user and delete the ones without references
1173  *
1174  * @param    int        $user_id    ID of the user whose private messages we want to delete
1175  *
1176  * @return    boolean        False if there were no pms found, true otherwise.
1177  */
1178  function phpbb_delete_user_pms($user_id)
1179  {
1180      global $db, $user, $phpbb_root_path, $phpEx;
1181  
1182      $user_id = (int) $user_id;
1183  
1184      if (!$user_id)
1185      {
1186          return false;
1187      }
1188  
1189      return phpbb_delete_users_pms(array($user_id));
1190  }
1191  
1192  /**
1193  * Delete all PM(s) for given users and delete the ones without references
1194  *
1195  * @param    array        $user_ids    IDs of the users whose private messages we want to delete
1196  *
1197  * @return    boolean        False if there were no pms found, true otherwise.
1198  */
1199  function phpbb_delete_users_pms($user_ids)
1200  {
1201      global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container;
1202  
1203      $user_id_sql = $db->sql_in_set('user_id', $user_ids);
1204      $author_id_sql = $db->sql_in_set('author_id', $user_ids);
1205  
1206      // Get PM Information for later deleting
1207      // The two queries where split, so we can use our indexes
1208      $undelivered_msg = $delete_ids = array();
1209  
1210      // Part 1: get PMs the user received
1211      $sql = 'SELECT msg_id
1212          FROM ' . PRIVMSGS_TO_TABLE . '
1213          WHERE ' . $user_id_sql;
1214      $result = $db->sql_query($sql);
1215  
1216      while ($row = $db->sql_fetchrow($result))
1217      {
1218          $msg_id = (int) $row['msg_id'];
1219          $delete_ids[$msg_id] = $msg_id;
1220      }
1221      $db->sql_freeresult($result);
1222  
1223      // Part 2: get PMs the users sent, but are yet to be received.
1224      // We cannot simply delete them. First we have to check
1225      // whether another user already received and read the message.
1226      $sql = 'SELECT msg_id
1227          FROM ' . PRIVMSGS_TO_TABLE . '
1228          WHERE ' . $author_id_sql . '
1229              AND folder_id = ' . PRIVMSGS_NO_BOX;
1230      $result = $db->sql_query($sql);
1231  
1232      while ($row = $db->sql_fetchrow($result))
1233      {
1234          $msg_id = (int) $row['msg_id'];
1235          $undelivered_msg[$msg_id] = $msg_id;
1236      }
1237      $db->sql_freeresult($result);
1238  
1239      if (empty($delete_ids) && empty($undelivered_msg))
1240      {
1241          return false;
1242      }
1243  
1244      $db->sql_transaction('begin');
1245  
1246      $phpbb_notifications = $phpbb_container->get('notification_manager');
1247  
1248      if (!empty($undelivered_msg))
1249      {
1250          // A pm is delivered, if for any recipient the message was moved
1251          // from their NO_BOX to another folder. We do not delete such
1252          // messages, but only delete them for users, who have not yet
1253          // received them.
1254          $sql = 'SELECT msg_id
1255              FROM ' . PRIVMSGS_TO_TABLE . '
1256              WHERE ' . $author_id_sql . '
1257                  AND folder_id <> ' . PRIVMSGS_NO_BOX . '
1258                  AND folder_id <> ' . PRIVMSGS_OUTBOX . '
1259                  AND folder_id <> ' . PRIVMSGS_SENTBOX;
1260          $result = $db->sql_query($sql);
1261  
1262          $delivered_msg = array();
1263          while ($row = $db->sql_fetchrow($result))
1264          {
1265              $msg_id = (int) $row['msg_id'];
1266              $delivered_msg[$msg_id] = $msg_id;
1267              unset($undelivered_msg[$msg_id]);
1268          }
1269          $db->sql_freeresult($result);
1270  
1271          $undelivered_user = array();
1272  
1273          // Count the messages we delete, so we can correct the user pm data
1274          $sql = 'SELECT user_id, COUNT(msg_id) as num_undelivered_privmsgs
1275              FROM ' . PRIVMSGS_TO_TABLE . '
1276              WHERE ' . $author_id_sql . '
1277                  AND folder_id = ' . PRIVMSGS_NO_BOX . '
1278                      AND ' . $db->sql_in_set('msg_id', array_merge($undelivered_msg, $delivered_msg)) . '
1279              GROUP BY user_id';
1280          $result = $db->sql_query($sql);
1281  
1282          while ($row = $db->sql_fetchrow($result))
1283          {
1284              $num_pms = (int) $row['num_undelivered_privmsgs'];
1285              $undelivered_user[$num_pms][] = (int) $row['user_id'];
1286  
1287              if (sizeof($undelivered_user[$num_pms]) > 50)
1288              {
1289                  // If there are too many users affected the query might get
1290                  // too long, so we update the value for the first bunch here.
1291                  $sql = 'UPDATE ' . USERS_TABLE . '
1292                      SET user_new_privmsg = user_new_privmsg - ' . $num_pms . ',
1293                          user_unread_privmsg = user_unread_privmsg - ' . $num_pms . '
1294                      WHERE ' . $db->sql_in_set('user_id', $undelivered_user[$num_pms]);
1295                  $db->sql_query($sql);
1296                  unset($undelivered_user[$num_pms]);
1297              }
1298          }
1299          $db->sql_freeresult($result);
1300  
1301          foreach ($undelivered_user as $num_pms => $undelivered_user_set)
1302          {
1303              $sql = 'UPDATE ' . USERS_TABLE . '
1304                  SET user_new_privmsg = user_new_privmsg - ' . $num_pms . ',
1305                      user_unread_privmsg = user_unread_privmsg - ' . $num_pms . '
1306                  WHERE ' . $db->sql_in_set('user_id', $undelivered_user_set);
1307              $db->sql_query($sql);
1308          }
1309  
1310          if (!empty($delivered_msg))
1311          {
1312              $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . '
1313                  WHERE folder_id = ' . PRIVMSGS_NO_BOX . '
1314                      AND ' . $db->sql_in_set('msg_id', $delivered_msg);
1315              $db->sql_query($sql);
1316  
1317              $phpbb_notifications->delete_notifications('notification.type.pm', $delivered_msg);
1318          }
1319  
1320          if (!empty($undelivered_msg))
1321          {
1322              $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . '
1323                  WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg);
1324              $db->sql_query($sql);
1325  
1326              $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
1327                  WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg);
1328              $db->sql_query($sql);
1329  
1330              $phpbb_notifications->delete_notifications('notification.type.pm', $undelivered_msg);
1331          }
1332      }
1333  
1334      // Reset the user's pm count to 0
1335      $sql = 'UPDATE ' . USERS_TABLE . '
1336          SET user_new_privmsg = 0,
1337              user_unread_privmsg = 0
1338          WHERE ' . $user_id_sql;
1339      $db->sql_query($sql);
1340  
1341      // Delete private message data of the user
1342      $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . '
1343          WHERE ' . $user_id_sql;
1344      $db->sql_query($sql);
1345  
1346      if (!empty($delete_ids))
1347      {
1348          // Now we have to check which messages we can delete completely
1349          $sql = 'SELECT msg_id
1350              FROM ' . PRIVMSGS_TO_TABLE . '
1351              WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
1352          $result = $db->sql_query($sql);
1353  
1354          while ($row = $db->sql_fetchrow($result))
1355          {
1356              unset($delete_ids[$row['msg_id']]);
1357          }
1358          $db->sql_freeresult($result);
1359  
1360          if (!empty($delete_ids))
1361          {
1362              // Check if there are any attachments we need to remove
1363              if (!function_exists('delete_attachments'))
1364              {
1365                  include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
1366              }
1367  
1368              delete_attachments('message', $delete_ids, false);
1369  
1370              $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
1371                  WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
1372              $db->sql_query($sql);
1373  
1374              $phpbb_notifications->delete_notifications('notification.type.pm', $delete_ids);
1375          }
1376      }
1377  
1378      // Set the remaining author id to anonymous
1379      // This way users are still able to read messages from users being removed
1380      $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
1381          SET author_id = ' . ANONYMOUS . '
1382          WHERE ' . $author_id_sql;
1383      $db->sql_query($sql);
1384  
1385      $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
1386          SET author_id = ' . ANONYMOUS . '
1387          WHERE ' . $author_id_sql;
1388      $db->sql_query($sql);
1389  
1390      $db->sql_transaction('commit');
1391  
1392      return true;
1393  }
1394  
1395  /**
1396  * Rebuild message header
1397  */
1398  function rebuild_header($check_ary)
1399  {
1400      global $db;
1401  
1402      $address = array();
1403  
1404      foreach ($check_ary as $check_type => $address_field)
1405      {
1406          // Split Addresses into users and groups
1407          preg_match_all('/:?(u|g)_([0-9]+):?/', $address_field, $match);
1408  
1409          $u = $g = array();
1410          foreach ($match[1] as $id => $type)
1411          {
1412              ${$type}[] = (int) $match[2][$id];
1413          }
1414  
1415          $_types = array('u', 'g');
1416          foreach ($_types as $type)
1417          {
1418              if (sizeof(${$type}))
1419              {
1420                  foreach (${$type} as $id)
1421                  {
1422                      $address[$type][$id] = $check_type;
1423                  }
1424              }
1425          }
1426      }
1427  
1428      return $address;
1429  }
1430  
1431  /**
1432  * Print out/assign recipient information
1433  */
1434  function write_pm_addresses($check_ary, $author_id, $plaintext = false)
1435  {
1436      global $db, $user, $template, $phpbb_root_path, $phpEx;
1437  
1438      $addresses = array();
1439  
1440      foreach ($check_ary as $check_type => $address_field)
1441      {
1442          if (!is_array($address_field))
1443          {
1444              // Split Addresses into users and groups
1445              preg_match_all('/:?(u|g)_([0-9]+):?/', $address_field, $match);
1446  
1447              $u = $g = array();
1448              foreach ($match[1] as $id => $type)
1449              {
1450                  ${$type}[] = (int) $match[2][$id];
1451              }
1452          }
1453          else
1454          {
1455              $u = $address_field['u'];
1456              $g = $address_field['g'];
1457          }
1458  
1459          $address = array();
1460          if (sizeof($u))
1461          {
1462              $sql = 'SELECT user_id, username, user_colour
1463                  FROM ' . USERS_TABLE . '
1464                  WHERE ' . $db->sql_in_set('user_id', $u);
1465              $result = $db->sql_query($sql);
1466  
1467              while ($row = $db->sql_fetchrow($result))
1468              {
1469                  if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
1470                  {
1471                      if ($plaintext)
1472                      {
1473                          $address[] = $row['username'];
1474                      }
1475                      else
1476                      {
1477                          $address['user'][$row['user_id']] = array('name' => $row['username'], 'colour' => $row['user_colour']);
1478                      }
1479                  }
1480              }
1481              $db->sql_freeresult($result);
1482          }
1483  
1484          if (sizeof($g))
1485          {
1486              if ($plaintext)
1487              {
1488                  $sql = 'SELECT group_name, group_type
1489                      FROM ' . GROUPS_TABLE . '
1490                          WHERE ' . $db->sql_in_set('group_id', $g);
1491                  $result = $db->sql_query($sql);
1492  
1493                  while ($row = $db->sql_fetchrow($result))
1494                  {
1495                      if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
1496                      {
1497                          $address[] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
1498                      }
1499                  }
1500                  $db->sql_freeresult($result);
1501              }
1502              else
1503              {
1504                  $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_type, ug.user_id
1505                      FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug
1506                          WHERE ' . $db->sql_in_set('g.group_id', $g) . '
1507                          AND g.group_id = ug.group_id
1508                          AND ug.user_pending = 0';
1509                  $result = $db->sql_query($sql);
1510  
1511                  while ($row = $db->sql_fetchrow($result))
1512                  {
1513                      if (!isset($address['group'][$row['group_id']]))
1514                      {
1515                          if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
1516                          {
1517                              $row['group_name'] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
1518                              $address['group'][$row['group_id']] = array('name' => $row['group_name'], 'colour' => $row['group_colour']);
1519                          }
1520                      }
1521  
1522                      if (isset($address['user'][$row['user_id']]))
1523                      {
1524                          $address['user'][$row['user_id']]['in_group'] = $row['group_id'];
1525                      }
1526                  }
1527                  $db->sql_freeresult($result);
1528              }
1529          }
1530  
1531          if (sizeof($address) && !$plaintext)
1532          {
1533              $template->assign_var('S_' . strtoupper($check_type) . '_RECIPIENT', true);
1534  
1535              foreach ($address as $type => $adr_ary)
1536              {
1537                  foreach ($adr_ary as $id => $row)
1538                  {
1539                      $tpl_ary = array(
1540                          'IS_GROUP'    => ($type == 'group') ? true : false,
1541                          'IS_USER'    => ($type == 'user') ? true : false,
1542                          'UG_ID'        => $id,
1543                          'NAME'        => $row['name'],
1544                          'COLOUR'    => ($row['colour']) ? '#' . $row['colour'] : '',
1545                          'TYPE'        => $type,
1546                      );
1547  
1548                      if ($type == 'user')
1549                      {
1550                          $tpl_ary = array_merge($tpl_ary, array(
1551                              'U_VIEW'        => get_username_string('profile', $id, $row['name'], $row['colour']),
1552                              'NAME_FULL'        => get_username_string('full', $id, $row['name'], $row['colour']),
1553                          ));
1554                      }
1555                      else
1556                      {
1557                          $tpl_ary = array_merge($tpl_ary, array(
1558                              'U_VIEW'        => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&amp;g=' . $id),
1559                          ));
1560                      }
1561  
1562                      $template->assign_block_vars($check_type . '_recipient', $tpl_ary);
1563                  }
1564              }
1565          }
1566  
1567          $addresses[$check_type] = $address;
1568      }
1569  
1570      return $addresses;
1571  }
1572  
1573  /**
1574  * Get folder status
1575  */
1576  function get_folder_status($folder_id, $folder)
1577  {
1578      global $db, $user, $config;
1579  
1580      if (isset($folder[$folder_id]))
1581      {
1582          $folder = $folder[$folder_id];
1583      }
1584      else
1585      {
1586          return false;
1587      }
1588  
1589      $return = array(
1590          'folder_name'    => $folder['folder_name'],
1591          'cur'            => $folder['num_messages'],
1592          'remaining'        => ($user->data['message_limit']) ? $user->data['message_limit'] - $folder['num_messages'] : 0,
1593          'max'            => $user->data['message_limit'],
1594          'percent'        => ($user->data['message_limit']) ? (($user->data['message_limit'] > 0) ? floor(($folder['num_messages'] / $user->data['message_limit']) * 100) : 100) : 0,
1595      );
1596  
1597      $return['message']    = $user->lang('FOLDER_STATUS_MSG', $user->lang('MESSAGES_COUNT', (int) $return['max']), (int) $return['cur'], $return['percent']);
1598  
1599      return $return;
1600  }
1601  
1602  //
1603  // COMPOSE MESSAGES
1604  //
1605  
1606  /**
1607  * Submit PM
1608  */
1609  function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
1610  {
1611      global $db, $auth, $config, $phpEx, $template, $user, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher;
1612  
1613      // We do not handle erasing pms here
1614      if ($mode == 'delete')
1615      {
1616          return false;
1617      }
1618  
1619      $current_time = time();
1620  
1621      /**
1622      * Get all parts of the PM that are to be submited to the DB.
1623      *
1624      * @event core.submit_pm_before
1625      * @var    string    mode    PM Post mode - post|reply|quote|quotepost|forward|edit
1626      * @var    string    subject    Subject of the private message
1627      * @var    array    data    The whole row data of the PM.
1628      * @since 3.1.0-b3
1629      */
1630      $vars = array('mode', 'subject', 'data');
1631      extract($phpbb_dispatcher->trigger_event('core.submit_pm_before', compact($vars)));
1632  
1633      // Collect some basic information about which tables and which rows to update/insert
1634      $sql_data = array();
1635      $root_level = 0;
1636  
1637      // Recipient Information
1638      $recipients = $to = $bcc = array();
1639  
1640      if ($mode != 'edit')
1641      {
1642          // Build Recipient List
1643          // u|g => array($user_id => 'to'|'bcc')
1644          $_types = array('u', 'g');
1645          foreach ($_types as $ug_type)
1646          {
1647              if (isset($data['address_list'][$ug_type]) && sizeof($data['address_list'][$ug_type]))
1648              {
1649                  foreach ($data['address_list'][$ug_type] as $id => $field)
1650                  {
1651                      $id = (int) $id;
1652  
1653                      // Do not rely on the address list being "valid"
1654                      if (!$id || ($ug_type == 'u' && $id == ANONYMOUS))
1655                      {
1656                          continue;
1657                      }
1658  
1659                      $field = ($field == 'to') ? 'to' : 'bcc';
1660                      if ($ug_type == 'u')
1661                      {
1662                          $recipients[$id] = $field;
1663                      }
1664                      ${$field}[] = $ug_type . '_' . $id;
1665                  }
1666              }
1667          }
1668  
1669          if (isset($data['address_list']['g']) && sizeof($data['address_list']['g']))
1670          {
1671              // We need to check the PM status of group members (do they want to receive PM's?)
1672              // Only check if not a moderator or admin, since they are allowed to override this user setting
1673              $sql_allow_pm = (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) ? ' AND u.user_allow_pm = 1' : '';
1674  
1675              $sql = 'SELECT u.user_type, ug.group_id, ug.user_id
1676                  FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . ' ug
1677                  WHERE ' . $db->sql_in_set('ug.group_id', array_keys($data['address_list']['g'])) . '
1678                      AND ug.user_pending = 0
1679                      AND u.user_id = ug.user_id
1680                      AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')' .
1681                      $sql_allow_pm;
1682              $result = $db->sql_query($sql);
1683  
1684              while ($row = $db->sql_fetchrow($result))
1685              {
1686                  $field = ($data['address_list']['g'][$row['group_id']] == 'to') ? 'to' : 'bcc';
1687                  $recipients[$row['user_id']] = $field;
1688              }
1689              $db->sql_freeresult($result);
1690          }
1691  
1692          if (!sizeof($recipients))
1693          {
1694              trigger_error('NO_RECIPIENT');
1695          }
1696      }
1697  
1698      // First of all make sure the subject are having the correct length.
1699      $subject = truncate_string($subject);
1700  
1701      $db->sql_transaction('begin');
1702  
1703      $sql = '';
1704  
1705      switch ($mode)
1706      {
1707          case 'reply':
1708          case 'quote':
1709              $root_level = ($data['reply_from_root_level']) ? $data['reply_from_root_level'] : $data['reply_from_msg_id'];
1710  
1711              // Set message_replied switch for this user
1712              $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
1713                  SET pm_replied = 1
1714                  WHERE user_id = ' . $data['from_user_id'] . '
1715                      AND msg_id = ' . $data['reply_from_msg_id'];
1716  
1717          // no break
1718  
1719          case 'forward':
1720          case 'post':
1721          case 'quotepost':
1722              $sql_data = array(
1723                  'root_level'        => $root_level,
1724                  'author_id'            => $data['from_user_id'],
1725                  'icon_id'            => $data['icon_id'],
1726                  'author_ip'            => $data['from_user_ip'],
1727                  'message_time'        => $current_time,
1728                  'enable_bbcode'        => $data['enable_bbcode'],
1729                  'enable_smilies'    => $data['enable_smilies'],
1730                  'enable_magic_url'    => $data['enable_urls'],
1731                  'enable_sig'        => $data['enable_sig'],
1732                  'message_subject'    => $subject,
1733                  'message_text'        => $data['message'],
1734                  'message_attachment'=> (!empty($data['attachment_data'])) ? 1 : 0,
1735                  'bbcode_bitfield'    => $data['bbcode_bitfield'],
1736                  'bbcode_uid'        => $data['bbcode_uid'],
1737                  'to_address'        => implode(':', $to),
1738                  'bcc_address'        => implode(':', $bcc),
1739                  'message_reported'    => 0,
1740              );
1741          break;
1742  
1743          case 'edit':
1744              $sql_data = array(
1745                  'icon_id'            => $data['icon_id'],
1746                  'message_edit_time'    => $current_time,
1747                  'enable_bbcode'        => $data['enable_bbcode'],
1748                  'enable_smilies'    => $data['enable_smilies'],
1749                  'enable_magic_url'    => $data['enable_urls'],
1750                  'enable_sig'        => $data['enable_sig'],
1751                  'message_subject'    => $subject,
1752                  'message_text'        => $data['message'],
1753                  'message_attachment'=> (!empty($data['attachment_data'])) ? 1 : 0,
1754                  'bbcode_bitfield'    => $data['bbcode_bitfield'],
1755                  'bbcode_uid'        => $data['bbcode_uid']
1756              );
1757          break;
1758      }
1759  
1760      if (sizeof($sql_data))
1761      {
1762          $query = '';
1763  
1764          if ($mode == 'post' || $mode == 'reply' || $mode == 'quote' || $mode == 'quotepost' || $mode == 'forward')
1765          {
1766              $db->sql_query('INSERT INTO ' . PRIVMSGS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_data));
1767              $data['msg_id'] = $db->sql_nextid();
1768          }
1769          else if ($mode == 'edit')
1770          {
1771              $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
1772                  SET message_edit_count = message_edit_count + 1, ' . $db->sql_build_array('UPDATE', $sql_data) . '
1773                  WHERE msg_id = ' . $data['msg_id'];
1774              $db->sql_query($sql);
1775          }
1776      }
1777  
1778      if ($mode != 'edit')
1779      {
1780          if ($sql)
1781          {
1782              $db->sql_query($sql);
1783          }
1784          unset($sql);
1785  
1786          $sql_ary = array();
1787          foreach ($recipients as $user_id => $type)
1788          {
1789              $sql_ary[] = array(
1790                  'msg_id'        => (int) $data['msg_id'],
1791                  'user_id'        => (int) $user_id,
1792                  'author_id'        => (int) $data['from_user_id'],
1793                  'folder_id'        => PRIVMSGS_NO_BOX,
1794                  'pm_new'        => 1,
1795                  'pm_unread'        => 1,
1796                  'pm_forwarded'    => ($mode == 'forward') ? 1 : 0
1797              );
1798          }
1799  
1800          $db->sql_multi_insert(PRIVMSGS_TO_TABLE, $sql_ary);
1801  
1802          $sql = 'UPDATE ' . USERS_TABLE . '
1803              SET user_new_privmsg = user_new_privmsg + 1, user_unread_privmsg = user_unread_privmsg + 1, user_last_privmsg = ' . time() . '
1804              WHERE ' . $db->sql_in_set('user_id', array_keys($recipients));
1805          $db->sql_query($sql);
1806  
1807          // Put PM into outbox
1808          if ($put_in_outbox)
1809          {
1810              $db->sql_query('INSERT INTO ' . PRIVMSGS_TO_TABLE . ' ' . $db->sql_build_array('INSERT', array(
1811                  'msg_id'        => (int) $data['msg_id'],
1812                  'user_id'        => (int) $data['from_user_id'],
1813                  'author_id'        => (int) $data['from_user_id'],
1814                  'folder_id'        => PRIVMSGS_OUTBOX,
1815                  'pm_new'        => 0,
1816                  'pm_unread'        => 0,
1817                  'pm_forwarded'    => ($mode == 'forward') ? 1 : 0))
1818              );
1819          }
1820      }
1821  
1822      // Set user last post time
1823      if ($mode == 'reply' || $mode == 'quote' || $mode == 'quotepost' || $mode == 'forward' || $mode == 'post')
1824      {
1825          $sql = 'UPDATE ' . USERS_TABLE . "
1826              SET user_lastpost_time = $current_time
1827              WHERE user_id = " . $data['from_user_id'];
1828          $db->sql_query($sql);
1829      }
1830  
1831      // Submit Attachments
1832      if (!empty($data['attachment_data']) && $data['msg_id'] && in_array($mode, array('post', 'reply', 'quote', 'quotepost', 'edit', 'forward')))
1833      {
1834          $space_taken = $files_added = 0;
1835          $orphan_rows = array();
1836  
1837          foreach ($data['attachment_data'] as $pos => $attach_row)
1838          {
1839              $orphan_rows[(int) $attach_row['attach_id']] = array();
1840          }
1841  
1842          if (sizeof($orphan_rows))
1843          {
1844              $sql = 'SELECT attach_id, filesize, physical_filename
1845                  FROM ' . ATTACHMENTS_TABLE . '
1846                  WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan_rows)) . '
1847                      AND in_message = 1
1848                      AND is_orphan = 1
1849                      AND poster_id = ' . $user->data['user_id'];
1850              $result = $db->sql_query($sql);
1851  
1852              $orphan_rows = array();
1853              while ($row = $db->sql_fetchrow($result))
1854              {
1855                  $orphan_rows[$row['attach_id']] = $row;
1856              }
1857              $db->sql_freeresult($result);
1858          }
1859  
1860          foreach ($data['attachment_data'] as $pos => $attach_row)
1861          {
1862              if ($attach_row['is_orphan'] && !isset($orphan_rows[$attach_row['attach_id']]))
1863              {
1864                  continue;
1865              }
1866  
1867              if (!$attach_row['is_orphan'])
1868              {
1869                  // update entry in db if attachment already stored in db and filespace
1870                  $sql = 'UPDATE ' . ATTACHMENTS_TABLE . "
1871                      SET attach_comment = '" . $db->sql_escape($attach_row['attach_comment']) . "'
1872                      WHERE attach_id = " . (int) $attach_row['attach_id'] . '
1873                          AND is_orphan = 0';
1874                  $db->sql_query($sql);
1875              }
1876              else
1877              {
1878                  // insert attachment into db
1879                  if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . utf8_basename($orphan_rows[$attach_row['attach_id']]['physical_filename'])))
1880                  {
1881                      continue;
1882                  }
1883  
1884                  $space_taken += $orphan_rows[$attach_row['attach_id']]['filesize'];
1885                  $files_added++;
1886  
1887                  $attach_sql = array(
1888                      'post_msg_id'        => $data['msg_id'],
1889                      'topic_id'            => 0,
1890                      'is_orphan'            => 0,
1891                      'poster_id'            => $data['from_user_id'],
1892                      'attach_comment'    => $attach_row['attach_comment'],
1893                  );
1894  
1895                  $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $attach_sql) . '
1896                      WHERE attach_id = ' . $attach_row['attach_id'] . '
1897                          AND is_orphan = 1
1898                          AND poster_id = ' . $user->data['user_id'];
1899                  $db->sql_query($sql);
1900              }
1901          }
1902  
1903          if ($space_taken && $files_added)
1904          {
1905              set_config_count('upload_dir_size', $space_taken, true);
1906              set_config_count('num_files', $files_added, true);
1907          }
1908      }
1909  
1910      // Delete draft if post was loaded...
1911      $draft_id = request_var('draft_loaded', 0);
1912      if ($draft_id)
1913      {
1914          $sql = 'DELETE FROM ' . DRAFTS_TABLE . "
1915              WHERE draft_id = $draft_id
1916                  AND user_id = " . $data['from_user_id'];
1917          $db->sql_query($sql);
1918      }
1919  
1920      $db->sql_transaction('commit');
1921  
1922      // Send Notifications
1923      $pm_data = array_merge($data, array(
1924          'message_subject'        => $subject,
1925          'recipients'            => $recipients,
1926      ));
1927  
1928      $phpbb_notifications = $phpbb_container->get('notification_manager');
1929  
1930      if ($mode == 'edit')
1931      {
1932          $phpbb_notifications->update_notifications('notification.type.pm', $pm_data);
1933      }
1934      else
1935      {
1936          $phpbb_notifications->add_notifications('notification.type.pm', $pm_data);
1937      }
1938  
1939      /**
1940      * Get PM message ID after submission to DB
1941      *
1942      * @event core.submit_pm_after
1943      * @var    string    mode    PM Post mode - post|reply|quote|quotepost|forward|edit
1944      * @var    string    subject    Subject of the private message
1945      * @var    array    data    The whole row data of the PM.
1946      * @var    array    pm_data    The data sent to notification class
1947      * @since 3.1.0-b5
1948      */
1949      $vars = array('mode', 'subject', 'data', 'pm_data');
1950      extract($phpbb_dispatcher->trigger_event('core.submit_pm_after', compact($vars)));
1951  
1952      return $data['msg_id'];
1953  }
1954  
1955  /**
1956  * Display Message History
1957  */
1958  function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode = false)
1959  {
1960      global $db, $user, $config, $template, $phpbb_root_path, $phpEx, $auth;
1961  
1962      // Select all receipts and the author from the pm we currently view, to only display their pm-history
1963      $sql = 'SELECT author_id, user_id
1964          FROM ' . PRIVMSGS_TO_TABLE . "
1965          WHERE msg_id = $msg_id
1966              AND folder_id <> " . PRIVMSGS_HOLD_BOX;
1967      $result = $db->sql_query($sql);
1968  
1969      $recipients = array();
1970      while ($row = $db->sql_fetchrow($result))
1971      {
1972          $recipients[] = (int) $row['user_id'];
1973          $recipients[] = (int) $row['author_id'];
1974      }
1975      $db->sql_freeresult($result);
1976      $recipients = array_unique($recipients);
1977  
1978      // Get History Messages (could be newer)
1979      $sql = 'SELECT t.*, p.*, u.*
1980          FROM ' . PRIVMSGS_TABLE . ' p, ' . PRIVMSGS_TO_TABLE . ' t, ' . USERS_TABLE . ' u
1981          WHERE t.msg_id = p.msg_id
1982              AND p.author_id = u.user_id
1983              AND t.folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
1984              AND ' . $db->sql_in_set('t.author_id', $recipients, false, true) . "
1985              AND t.user_id = $user_id";
1986  
1987      // We no longer need those.
1988      unset($recipients);
1989  
1990      if (!$message_row['root_level'])
1991      {
1992          $sql .= " AND (p.root_level = $msg_id OR (p.root_level = 0 AND p.msg_id = $msg_id))";
1993      }
1994      else
1995      {
1996          $sql .= " AND (p.root_level = " . $message_row['root_level'] . ' OR p.msg_id = ' . $message_row['root_level'] . ')';
1997      }
1998      $sql .= ' ORDER BY p.message_time DESC';
1999  
2000      $result = $db->sql_query($sql);
2001      $row = $db->sql_fetchrow($result);
2002  
2003      if (!$row)
2004      {
2005          $db->sql_freeresult($result);
2006          return false;
2007      }
2008  
2009      $title = $row['message_subject'];
2010  
2011      $rowset = array();
2012      $folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm') . '&amp;folder=';
2013  
2014      do
2015      {
2016          $folder_id = (int) $row['folder_id'];
2017  
2018          $row['folder'][] = (isset($folder[$folder_id])) ? '<a href="' . $folder_url . $folder_id . '">' . $folder[$folder_id]['folder_name'] . '</a>' : $user->lang['UNKNOWN_FOLDER'];
2019  
2020          if (isset($rowset[$row['msg_id']]))
2021          {
2022              $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'];
2023          }
2024          else
2025          {
2026              $rowset[$row['msg_id']] = $row;
2027          }
2028      }
2029      while ($row = $db->sql_fetchrow($result));
2030      $db->sql_freeresult($result);
2031  
2032      if (sizeof($rowset) == 1 && !$in_post_mode)
2033      {
2034          return false;
2035      }
2036  
2037      $title = censor_text($title);
2038  
2039      $url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm');
2040      $next_history_pm = $previous_history_pm = $prev_id = 0;
2041  
2042      // Re-order rowset to be able to get the next/prev message rows...
2043      $rowset = array_values($rowset);
2044  
2045      for ($i = 0, $size = sizeof($rowset); $i < $size; $i++)
2046      {
2047          $row = &$rowset[$i];
2048          $id = (int) $row['msg_id'];
2049  
2050          $author_id    = $row['author_id'];
2051          $folder_id    = (int) $row['folder_id'];
2052  
2053          $subject    = $row['message_subject'];
2054          $message    = $row['message_text'];
2055  
2056          $message = censor_text($message);
2057  
2058          $decoded_message = false;
2059  
2060          if ($in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS)
2061          {
2062              $decoded_message = $message;
2063              decode_message($decoded_message, $row['bbcode_uid']);
2064  
2065              $decoded_message = bbcode_nl2br($decoded_message);
2066          }
2067  
2068          $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0);
2069          $parse_flags |= ($row['enable_smilies'] ? OPTION_FLAG_SMILIES : 0);
2070  
2071          $message = generate_text_for_display($message, $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false);
2072  
2073          $subject = censor_text($subject);
2074  
2075          if ($id == $msg_id)
2076          {
2077              $next_history_pm = (isset($rowset[$i + 1])) ? (int) $rowset[$i + 1]['msg_id'] : 0;
2078              $previous_history_pm = $prev_id;
2079          }
2080  
2081          $template->assign_block_vars('history_row', array(
2082              'MESSAGE_AUTHOR_QUOTE'        => (($decoded_message) ? addslashes(get_username_string('username', $author_id, $row['username'], $row['user_colour'], $row['username'])) : ''),
2083              'MESSAGE_AUTHOR_FULL'        => get_username_string('full', $author_id, $row['username'], $row['user_colour'], $row['username']),
2084              'MESSAGE_AUTHOR_COLOUR'        => get_username_string('colour', $author_id, $row['username'], $row['user_colour'], $row['username']),
2085              'MESSAGE_AUTHOR'            => get_username_string('username', $author_id, $row['username'], $row['user_colour'], $row['username']),
2086              'U_MESSAGE_AUTHOR'            => get_username_string('profile', $author_id, $row['username'], $row['user_colour'], $row['username']),
2087  
2088              'SUBJECT'            => $subject,
2089              'SENT_DATE'            => $user->format_date($row['message_time']),
2090              'MESSAGE'            => $message,
2091              'FOLDER'            => implode($user->lang['COMMA_SEPARATOR'], $row['folder']),
2092              'DECODED_MESSAGE'    => $decoded_message,
2093  
2094              'S_CURRENT_MSG'        => ($row['msg_id'] == $msg_id),
2095              'S_AUTHOR_DELETED'    => ($author_id == ANONYMOUS) ? true : false,
2096              'S_IN_POST_MODE'    => $in_post_mode,
2097  
2098              'MSG_ID'            => $row['msg_id'],
2099              'U_VIEW_MESSAGE'    => "$url&amp;f=$folder_id&amp;p=" . $row['msg_id'],
2100              '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'] : '',
2101              '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'] : '')
2102          );
2103          unset($rowset[$i]);
2104          $prev_id = $id;
2105      }
2106  
2107      $template->assign_vars(array(
2108          'QUOTE_IMG'            => $user->img('icon_post_quote', $user->lang['REPLY_WITH_QUOTE']),
2109          'HISTORY_TITLE'        => $title,
2110  
2111          'U_VIEW_NEXT_HISTORY'        => ($next_history_pm) ? "$url&amp;p=" . $next_history_pm : '',
2112          'U_VIEW_PREVIOUS_HISTORY'    => ($previous_history_pm) ? "$url&amp;p=" . $previous_history_pm : '',
2113      ));
2114  
2115      return true;
2116  }
2117  
2118  /**
2119  * Set correct users max messages in PM folder.
2120  * If several group memberships define different amount of messages, the highest will be chosen.
2121  */
2122  function set_user_message_limit()
2123  {
2124      global $user, $db, $config;
2125  
2126      // Get maximum about from user memberships - if it is 0, there is no limit set and we use the maximum value within the config.
2127      $sql = 'SELECT MAX(g.group_message_limit) as max_message_limit
2128          FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug
2129          WHERE ug.user_id = ' . $user->data['user_id'] . '
2130              AND ug.user_pending = 0
2131              AND ug.group_id = g.group_id';
2132      $result = $db->sql_query($sql);
2133      $message_limit = (int) $db->sql_fetchfield('max_message_limit');
2134      $db->sql_freeresult($result);
2135  
2136      $user->data['message_limit'] = (!$message_limit) ? $config['pm_max_msgs'] : $message_limit;
2137  }
2138  
2139  /**
2140  * Generates an array of coloured recipient names from a list of PMs - (groups & users)
2141  *
2142  * @param    array    $pm_by_id    An array of rows from PRIVMSGS_TABLE, keys are the msg_ids.
2143  *
2144  * @return    array                2D Array: array(msg_id => array('username or group string', ...), ...)
2145  *                                Usernames are generated with {@link get_username_string get_username_string}
2146  *                                Groups are coloured and have a link to the membership page
2147  */
2148  function get_recipient_strings($pm_by_id)
2149  {
2150      global $db, $phpbb_root_path, $phpEx, $user;
2151  
2152      $address_list = $recipient_list = $address = array();
2153  
2154      $_types = array('u', 'g');
2155  
2156      foreach ($pm_by_id as $message_id => $row)
2157      {
2158          $address[$message_id] = rebuild_header(array('to' => $row['to_address'], 'bcc' => $row['bcc_address']));
2159  
2160          foreach ($_types as $ug_type)
2161          {
2162              if (isset($address[$message_id][$ug_type]) && sizeof($address[$message_id][$ug_type]))
2163              {
2164                  foreach ($address[$message_id][$ug_type] as $ug_id => $in_to)
2165                  {
2166                      $recipient_list[$ug_type][$ug_id] = array('name' => $user->lang['NA'], 'colour' => '');
2167                  }
2168              }
2169          }
2170      }
2171  
2172      foreach ($_types as $ug_type)
2173      {
2174          if (!empty($recipient_list[$ug_type]))
2175          {
2176              if ($ug_type == 'u')
2177              {
2178                  $sql = 'SELECT user_id as id, username as name, user_colour as colour
2179                      FROM ' . USERS_TABLE . '
2180                      WHERE ';
2181              }
2182              else
2183              {
2184                  $sql = 'SELECT group_id as id, group_name as name, group_colour as colour, group_type
2185                      FROM ' . GROUPS_TABLE . '
2186                      WHERE ';
2187              }
2188              $sql .= $db->sql_in_set(($ug_type == 'u') ? 'user_id' : 'group_id', array_map('intval', array_keys($recipient_list[$ug_type])));
2189  
2190              $result = $db->sql_query($sql);
2191  
2192              while ($row = $db->sql_fetchrow($result))
2193              {
2194                  if ($ug_type == 'g')
2195                  {
2196                      $row['name'] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['name']] : $row['name'];
2197                  }
2198  
2199                  $recipient_list[$ug_type][$row['id']] = array('name' => $row['name'], 'colour' => $row['colour']);
2200              }
2201              $db->sql_freeresult($result);
2202          }
2203      }
2204  
2205      foreach ($address as $message_id => $adr_ary)
2206      {
2207          foreach ($adr_ary as $type => $id_ary)
2208          {
2209              foreach ($id_ary as $ug_id => $_id)
2210              {
2211                  if ($type == 'u')
2212                  {
2213                      $address_list[$message_id][] = get_username_string('full', $ug_id, $recipient_list[$type][$ug_id]['name'], $recipient_list[$type][$ug_id]['colour']);
2214                  }
2215                  else
2216                  {
2217                      $user_colour = ($recipient_list[$type][$ug_id]['colour']) ? ' style="font-weight: bold; color:#' . $recipient_list[$type][$ug_id]['colour'] . '"' : '';
2218                      $link = '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&amp;g=' . $ug_id) . '"' . $user_colour . '>';
2219                      $address_list[$message_id][] = $link . $recipient_list[$type][$ug_id]['name'] . (($link) ? '</a>' : '');
2220                  }
2221              }
2222          }
2223      }
2224  
2225      return $address_list;
2226  }


Generated: Sun Feb 19 19:52:41 2017 Cross-referenced by PHPXref 0.7.1