[ Index ]

PHP Cross Reference of phpBB-3.1.12-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              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;
 948  
 949      $msg_ids        = request_var('marked_msg_id', array(0));
 950      $cur_folder_id    = request_var('cur_folder_id', PRIVMSGS_NO_BOX);
 951      $confirm        = (isset($_POST['confirm'])) ? true : false;
 952  
 953      if (!sizeof($msg_ids))
 954      {
 955          return false;
 956      }
 957  
 958      switch ($mark_action)
 959      {
 960          case 'mark_important':
 961  
 962              $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
 963                  SET pm_marked = 1 - pm_marked
 964                  WHERE folder_id = $cur_folder_id
 965                      AND user_id = $user_id
 966                      AND " . $db->sql_in_set('msg_id', $msg_ids);
 967              $db->sql_query($sql);
 968  
 969          break;
 970  
 971          case 'delete_marked':
 972  
 973              global $auth;
 974  
 975              if (!$auth->acl_get('u_pm_delete'))
 976              {
 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_root_path, $phpEx, $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      $phpbb_notifications = $phpbb_container->get('notification_manager');
1141  
1142      $phpbb_notifications->delete_notifications('notification.type.pm', array_keys($delete_rows));
1143  
1144      // Now we have to check which messages we can delete completely
1145      $sql = 'SELECT msg_id
1146          FROM ' . PRIVMSGS_TO_TABLE . '
1147          WHERE ' . $db->sql_in_set('msg_id', array_keys($delete_rows));
1148      $result = $db->sql_query($sql);
1149  
1150      while ($row = $db->sql_fetchrow($result))
1151      {
1152          unset($delete_rows[$row['msg_id']]);
1153      }
1154      $db->sql_freeresult($result);
1155  
1156      $delete_ids = array_keys($delete_rows);
1157  
1158      if (sizeof($delete_ids))
1159      {
1160          // Check if there are any attachments we need to remove
1161          if (!function_exists('delete_attachments'))
1162          {
1163              include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
1164          }
1165  
1166          delete_attachments('message', $delete_ids, false);
1167  
1168          $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
1169              WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
1170          $db->sql_query($sql);
1171      }
1172  
1173      $db->sql_transaction('commit');
1174  
1175      return true;
1176  }
1177  
1178  /**
1179  * Delete all PM(s) for a given user and delete the ones without references
1180  *
1181  * @param    int        $user_id    ID of the user whose private messages we want to delete
1182  *
1183  * @return    boolean        False if there were no pms found, true otherwise.
1184  */
1185  function phpbb_delete_user_pms($user_id)
1186  {
1187      global $db, $user, $phpbb_root_path, $phpEx;
1188  
1189      $user_id = (int) $user_id;
1190  
1191      if (!$user_id)
1192      {
1193          return false;
1194      }
1195  
1196      return phpbb_delete_users_pms(array($user_id));
1197  }
1198  
1199  /**
1200  * Delete all PM(s) for given users and delete the ones without references
1201  *
1202  * @param    array        $user_ids    IDs of the users whose private messages we want to delete
1203  *
1204  * @return    boolean        False if there were no pms found, true otherwise.
1205  */
1206  function phpbb_delete_users_pms($user_ids)
1207  {
1208      global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container;
1209  
1210      $user_id_sql = $db->sql_in_set('user_id', $user_ids);
1211      $author_id_sql = $db->sql_in_set('author_id', $user_ids);
1212  
1213      // Get PM Information for later deleting
1214      // The two queries where split, so we can use our indexes
1215      $undelivered_msg = $delete_ids = array();
1216  
1217      // Part 1: get PMs the user received
1218      $sql = 'SELECT msg_id
1219          FROM ' . PRIVMSGS_TO_TABLE . '
1220          WHERE ' . $user_id_sql;
1221      $result = $db->sql_query($sql);
1222  
1223      while ($row = $db->sql_fetchrow($result))
1224      {
1225          $msg_id = (int) $row['msg_id'];
1226          $delete_ids[$msg_id] = $msg_id;
1227      }
1228      $db->sql_freeresult($result);
1229  
1230      // Part 2: get PMs the users sent, but are yet to be received.
1231      // We cannot simply delete them. First we have to check
1232      // whether another user already received and read the message.
1233      $sql = 'SELECT msg_id
1234          FROM ' . PRIVMSGS_TO_TABLE . '
1235          WHERE ' . $author_id_sql . '
1236              AND folder_id = ' . PRIVMSGS_NO_BOX;
1237      $result = $db->sql_query($sql);
1238  
1239      while ($row = $db->sql_fetchrow($result))
1240      {
1241          $msg_id = (int) $row['msg_id'];
1242          $undelivered_msg[$msg_id] = $msg_id;
1243      }
1244      $db->sql_freeresult($result);
1245  
1246      if (empty($delete_ids) && empty($undelivered_msg))
1247      {
1248          return false;
1249      }
1250  
1251      $db->sql_transaction('begin');
1252  
1253      $phpbb_notifications = $phpbb_container->get('notification_manager');
1254  
1255      if (!empty($undelivered_msg))
1256      {
1257          // A pm is delivered, if for any recipient the message was moved
1258          // from their NO_BOX to another folder. We do not delete such
1259          // messages, but only delete them for users, who have not yet
1260          // received them.
1261          $sql = 'SELECT msg_id
1262              FROM ' . PRIVMSGS_TO_TABLE . '
1263              WHERE ' . $author_id_sql . '
1264                  AND folder_id <> ' . PRIVMSGS_NO_BOX . '
1265                  AND folder_id <> ' . PRIVMSGS_OUTBOX . '
1266                  AND folder_id <> ' . PRIVMSGS_SENTBOX;
1267          $result = $db->sql_query($sql);
1268  
1269          $delivered_msg = array();
1270          while ($row = $db->sql_fetchrow($result))
1271          {
1272              $msg_id = (int) $row['msg_id'];
1273              $delivered_msg[$msg_id] = $msg_id;
1274              unset($undelivered_msg[$msg_id]);
1275          }
1276          $db->sql_freeresult($result);
1277  
1278          $undelivered_user = array();
1279  
1280          // Count the messages we delete, so we can correct the user pm data
1281          $sql = 'SELECT user_id, COUNT(msg_id) as num_undelivered_privmsgs
1282              FROM ' . PRIVMSGS_TO_TABLE . '
1283              WHERE ' . $author_id_sql . '
1284                  AND folder_id = ' . PRIVMSGS_NO_BOX . '
1285                      AND ' . $db->sql_in_set('msg_id', array_merge($undelivered_msg, $delivered_msg)) . '
1286              GROUP BY user_id';
1287          $result = $db->sql_query($sql);
1288  
1289          while ($row = $db->sql_fetchrow($result))
1290          {
1291              $num_pms = (int) $row['num_undelivered_privmsgs'];
1292              $undelivered_user[$num_pms][] = (int) $row['user_id'];
1293  
1294              if (sizeof($undelivered_user[$num_pms]) > 50)
1295              {
1296                  // If there are too many users affected the query might get
1297                  // too long, so we update the value for the first bunch here.
1298                  $sql = 'UPDATE ' . USERS_TABLE . '
1299                      SET user_new_privmsg = user_new_privmsg - ' . $num_pms . ',
1300                          user_unread_privmsg = user_unread_privmsg - ' . $num_pms . '
1301                      WHERE ' . $db->sql_in_set('user_id', $undelivered_user[$num_pms]);
1302                  $db->sql_query($sql);
1303                  unset($undelivered_user[$num_pms]);
1304              }
1305          }
1306          $db->sql_freeresult($result);
1307  
1308          foreach ($undelivered_user as $num_pms => $undelivered_user_set)
1309          {
1310              $sql = 'UPDATE ' . USERS_TABLE . '
1311                  SET user_new_privmsg = user_new_privmsg - ' . $num_pms . ',
1312                      user_unread_privmsg = user_unread_privmsg - ' . $num_pms . '
1313                  WHERE ' . $db->sql_in_set('user_id', $undelivered_user_set);
1314              $db->sql_query($sql);
1315          }
1316  
1317          if (!empty($delivered_msg))
1318          {
1319              $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . '
1320                  WHERE folder_id = ' . PRIVMSGS_NO_BOX . '
1321                      AND ' . $db->sql_in_set('msg_id', $delivered_msg);
1322              $db->sql_query($sql);
1323  
1324              $phpbb_notifications->delete_notifications('notification.type.pm', $delivered_msg);
1325          }
1326  
1327          if (!empty($undelivered_msg))
1328          {
1329              $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . '
1330                  WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg);
1331              $db->sql_query($sql);
1332  
1333              $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
1334                  WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg);
1335              $db->sql_query($sql);
1336  
1337              $phpbb_notifications->delete_notifications('notification.type.pm', $undelivered_msg);
1338          }
1339      }
1340  
1341      // Reset the user's pm count to 0
1342      $sql = 'UPDATE ' . USERS_TABLE . '
1343          SET user_new_privmsg = 0,
1344              user_unread_privmsg = 0
1345          WHERE ' . $user_id_sql;
1346      $db->sql_query($sql);
1347  
1348      // Delete private message data of the user
1349      $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . '
1350          WHERE ' . $user_id_sql;
1351      $db->sql_query($sql);
1352  
1353      if (!empty($delete_ids))
1354      {
1355          // Now we have to check which messages we can delete completely
1356          $sql = 'SELECT msg_id
1357              FROM ' . PRIVMSGS_TO_TABLE . '
1358              WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
1359          $result = $db->sql_query($sql);
1360  
1361          while ($row = $db->sql_fetchrow($result))
1362          {
1363              unset($delete_ids[$row['msg_id']]);
1364          }
1365          $db->sql_freeresult($result);
1366  
1367          if (!empty($delete_ids))
1368          {
1369              // Check if there are any attachments we need to remove
1370              if (!function_exists('delete_attachments'))
1371              {
1372                  include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
1373              }
1374  
1375              delete_attachments('message', $delete_ids, false);
1376  
1377              $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
1378                  WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
1379              $db->sql_query($sql);
1380  
1381              $phpbb_notifications->delete_notifications('notification.type.pm', $delete_ids);
1382          }
1383      }
1384  
1385      // Set the remaining author id to anonymous
1386      // This way users are still able to read messages from users being removed
1387      $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
1388          SET author_id = ' . ANONYMOUS . '
1389          WHERE ' . $author_id_sql;
1390      $db->sql_query($sql);
1391  
1392      $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
1393          SET author_id = ' . ANONYMOUS . '
1394          WHERE ' . $author_id_sql;
1395      $db->sql_query($sql);
1396  
1397      $db->sql_transaction('commit');
1398  
1399      return true;
1400  }
1401  
1402  /**
1403  * Rebuild message header
1404  */
1405  function rebuild_header($check_ary)
1406  {
1407      global $db;
1408  
1409      $address = array();
1410  
1411      foreach ($check_ary as $check_type => $address_field)
1412      {
1413          // Split Addresses into users and groups
1414          preg_match_all('/:?(u|g)_([0-9]+):?/', $address_field, $match);
1415  
1416          $u = $g = array();
1417          foreach ($match[1] as $id => $type)
1418          {
1419              ${$type}[] = (int) $match[2][$id];
1420          }
1421  
1422          $_types = array('u', 'g');
1423          foreach ($_types as $type)
1424          {
1425              if (sizeof(${$type}))
1426              {
1427                  foreach (${$type} as $id)
1428                  {
1429                      $address[$type][$id] = $check_type;
1430                  }
1431              }
1432          }
1433      }
1434  
1435      return $address;
1436  }
1437  
1438  /**
1439  * Print out/assign recipient information
1440  */
1441  function write_pm_addresses($check_ary, $author_id, $plaintext = false)
1442  {
1443      global $db, $user, $template, $phpbb_root_path, $phpEx;
1444  
1445      $addresses = array();
1446  
1447      foreach ($check_ary as $check_type => $address_field)
1448      {
1449          if (!is_array($address_field))
1450          {
1451              // Split Addresses into users and groups
1452              preg_match_all('/:?(u|g)_([0-9]+):?/', $address_field, $match);
1453  
1454              $u = $g = array();
1455              foreach ($match[1] as $id => $type)
1456              {
1457                  ${$type}[] = (int) $match[2][$id];
1458              }
1459          }
1460          else
1461          {
1462              $u = $address_field['u'];
1463              $g = $address_field['g'];
1464          }
1465  
1466          $address = array();
1467          if (sizeof($u))
1468          {
1469              $sql = 'SELECT user_id, username, user_colour
1470                  FROM ' . USERS_TABLE . '
1471                  WHERE ' . $db->sql_in_set('user_id', $u);
1472              $result = $db->sql_query($sql);
1473  
1474              while ($row = $db->sql_fetchrow($result))
1475              {
1476                  if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
1477                  {
1478                      if ($plaintext)
1479                      {
1480                          $address[] = $row['username'];
1481                      }
1482                      else
1483                      {
1484                          $address['user'][$row['user_id']] = array('name' => $row['username'], 'colour' => $row['user_colour']);
1485                      }
1486                  }
1487              }
1488              $db->sql_freeresult($result);
1489          }
1490  
1491          if (sizeof($g))
1492          {
1493              if ($plaintext)
1494              {
1495                  $sql = 'SELECT group_name, group_type
1496                      FROM ' . GROUPS_TABLE . '
1497                          WHERE ' . $db->sql_in_set('group_id', $g);
1498                  $result = $db->sql_query($sql);
1499  
1500                  while ($row = $db->sql_fetchrow($result))
1501                  {
1502                      if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
1503                      {
1504                          $address[] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
1505                      }
1506                  }
1507                  $db->sql_freeresult($result);
1508              }
1509              else
1510              {
1511                  $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_type, ug.user_id
1512                      FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug
1513                          WHERE ' . $db->sql_in_set('g.group_id', $g) . '
1514                          AND g.group_id = ug.group_id
1515                          AND ug.user_pending = 0';
1516                  $result = $db->sql_query($sql);
1517  
1518                  while ($row = $db->sql_fetchrow($result))
1519                  {
1520                      if (!isset($address['group'][$row['group_id']]))
1521                      {
1522                          if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
1523                          {
1524                              $row['group_name'] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
1525                              $address['group'][$row['group_id']] = array('name' => $row['group_name'], 'colour' => $row['group_colour']);
1526                          }
1527                      }
1528  
1529                      if (isset($address['user'][$row['user_id']]))
1530                      {
1531                          $address['user'][$row['user_id']]['in_group'] = $row['group_id'];
1532                      }
1533                  }
1534                  $db->sql_freeresult($result);
1535              }
1536          }
1537  
1538          if (sizeof($address) && !$plaintext)
1539          {
1540              $template->assign_var('S_' . strtoupper($check_type) . '_RECIPIENT', true);
1541  
1542              foreach ($address as $type => $adr_ary)
1543              {
1544                  foreach ($adr_ary as $id => $row)
1545                  {
1546                      $tpl_ary = array(
1547                          'IS_GROUP'    => ($type == 'group') ? true : false,
1548                          'IS_USER'    => ($type == 'user') ? true : false,
1549                          'UG_ID'        => $id,
1550                          'NAME'        => $row['name'],
1551                          'COLOUR'    => ($row['colour']) ? '#' . $row['colour'] : '',
1552                          'TYPE'        => $type,
1553                      );
1554  
1555                      if ($type == 'user')
1556                      {
1557                          $tpl_ary = array_merge($tpl_ary, array(
1558                              'U_VIEW'        => get_username_string('profile', $id, $row['name'], $row['colour']),
1559                              'NAME_FULL'        => get_username_string('full', $id, $row['name'], $row['colour']),
1560                          ));
1561                      }
1562                      else
1563                      {
1564                          $tpl_ary = array_merge($tpl_ary, array(
1565                              'U_VIEW'        => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&amp;g=' . $id),
1566                          ));
1567                      }
1568  
1569                      $template->assign_block_vars($check_type . '_recipient', $tpl_ary);
1570                  }
1571              }
1572          }
1573  
1574          $addresses[$check_type] = $address;
1575      }
1576  
1577      return $addresses;
1578  }
1579  
1580  /**
1581  * Get folder status
1582  */
1583  function get_folder_status($folder_id, $folder)
1584  {
1585      global $db, $user, $config;
1586  
1587      if (isset($folder[$folder_id]))
1588      {
1589          $folder = $folder[$folder_id];
1590      }
1591      else
1592      {
1593          return false;
1594      }
1595  
1596      $return = array(
1597          'folder_name'    => $folder['folder_name'],
1598          'cur'            => $folder['num_messages'],
1599          'remaining'        => ($user->data['message_limit']) ? $user->data['message_limit'] - $folder['num_messages'] : 0,
1600          'max'            => $user->data['message_limit'],
1601          'percent'        => ($user->data['message_limit']) ? (($user->data['message_limit'] > 0) ? floor(($folder['num_messages'] / $user->data['message_limit']) * 100) : 100) : 0,
1602      );
1603  
1604      $return['message']    = $user->lang('FOLDER_STATUS_MSG', $user->lang('MESSAGES_COUNT', (int) $return['max']), (int) $return['cur'], $return['percent']);
1605  
1606      return $return;
1607  }
1608  
1609  //
1610  // COMPOSE MESSAGES
1611  //
1612  
1613  /**
1614  * Submit PM
1615  */
1616  function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
1617  {
1618      global $db, $auth, $config, $phpEx, $template, $user, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher;
1619  
1620      // We do not handle erasing pms here
1621      if ($mode == 'delete')
1622      {
1623          return false;
1624      }
1625  
1626      $current_time = time();
1627  
1628      /**
1629      * Get all parts of the PM that are to be submited to the DB.
1630      *
1631      * @event core.submit_pm_before
1632      * @var    string    mode    PM Post mode - post|reply|quote|quotepost|forward|edit
1633      * @var    string    subject    Subject of the private message
1634      * @var    array    data    The whole row data of the PM.
1635      * @since 3.1.0-b3
1636      */
1637      $vars = array('mode', 'subject', 'data');
1638      extract($phpbb_dispatcher->trigger_event('core.submit_pm_before', compact($vars)));
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['address_list'][$ug_type]) && sizeof($data['address_list'][$ug_type]))
1655              {
1656                  foreach ($data['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['address_list']['g']) && sizeof($data['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['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['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['reply_from_root_level']) ? $data['reply_from_root_level'] : $data['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['from_user_id'] . '
1722                      AND msg_id = ' . $data['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['from_user_id'],
1732                  'icon_id'            => $data['icon_id'],
1733                  'author_ip'            => $data['from_user_ip'],
1734                  'message_time'        => $current_time,
1735                  'enable_bbcode'        => $data['enable_bbcode'],
1736                  'enable_smilies'    => $data['enable_smilies'],
1737                  'enable_magic_url'    => $data['enable_urls'],
1738                  'enable_sig'        => $data['enable_sig'],
1739                  'message_subject'    => $subject,
1740                  'message_text'        => $data['message'],
1741                  'message_attachment'=> (!empty($data['attachment_data'])) ? 1 : 0,
1742                  'bbcode_bitfield'    => $data['bbcode_bitfield'],
1743                  'bbcode_uid'        => $data['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['icon_id'],
1753                  'message_edit_time'    => $current_time,
1754                  'enable_bbcode'        => $data['enable_bbcode'],
1755                  'enable_smilies'    => $data['enable_smilies'],
1756                  'enable_magic_url'    => $data['enable_urls'],
1757                  'enable_sig'        => $data['enable_sig'],
1758                  'message_subject'    => $subject,
1759                  'message_text'        => $data['message'],
1760                  'message_attachment'=> (!empty($data['attachment_data'])) ? 1 : 0,
1761                  'bbcode_bitfield'    => $data['bbcode_bitfield'],
1762                  'bbcode_uid'        => $data['bbcode_uid']
1763              );
1764          break;
1765      }
1766  
1767      if (sizeof($sql_data))
1768      {
1769          $query = '';
1770  
1771          if ($mode == 'post' || $mode == 'reply' || $mode == 'quote' || $mode == 'quotepost' || $mode == 'forward')
1772          {
1773              $db->sql_query('INSERT INTO ' . PRIVMSGS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_data));
1774              $data['msg_id'] = $db->sql_nextid();
1775          }
1776          else if ($mode == 'edit')
1777          {
1778              $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
1779                  SET message_edit_count = message_edit_count + 1, ' . $db->sql_build_array('UPDATE', $sql_data) . '
1780                  WHERE msg_id = ' . $data['msg_id'];
1781              $db->sql_query($sql);
1782          }
1783      }
1784  
1785      if ($mode != 'edit')
1786      {
1787          if ($sql)
1788          {
1789              $db->sql_query($sql);
1790          }
1791          unset($sql);
1792  
1793          $sql_ary = array();
1794          foreach ($recipients as $user_id => $type)
1795          {
1796              $sql_ary[] = array(
1797                  'msg_id'        => (int) $data['msg_id'],
1798                  'user_id'        => (int) $user_id,
1799                  'author_id'        => (int) $data['from_user_id'],
1800                  'folder_id'        => PRIVMSGS_NO_BOX,
1801                  'pm_new'        => 1,
1802                  'pm_unread'        => 1,
1803                  'pm_forwarded'    => ($mode == 'forward') ? 1 : 0
1804              );
1805          }
1806  
1807          $db->sql_multi_insert(PRIVMSGS_TO_TABLE, $sql_ary);
1808  
1809          $sql = 'UPDATE ' . USERS_TABLE . '
1810              SET user_new_privmsg = user_new_privmsg + 1, user_unread_privmsg = user_unread_privmsg + 1, user_last_privmsg = ' . time() . '
1811              WHERE ' . $db->sql_in_set('user_id', array_keys($recipients));
1812          $db->sql_query($sql);
1813  
1814          // Put PM into outbox
1815          if ($put_in_outbox)
1816          {
1817              $db->sql_query('INSERT INTO ' . PRIVMSGS_TO_TABLE . ' ' . $db->sql_build_array('INSERT', array(
1818                  'msg_id'        => (int) $data['msg_id'],
1819                  'user_id'        => (int) $data['from_user_id'],
1820                  'author_id'        => (int) $data['from_user_id'],
1821                  'folder_id'        => PRIVMSGS_OUTBOX,
1822                  'pm_new'        => 0,
1823                  'pm_unread'        => 0,
1824                  'pm_forwarded'    => ($mode == 'forward') ? 1 : 0))
1825              );
1826          }
1827      }
1828  
1829      // Set user last post time
1830      if ($mode == 'reply' || $mode == 'quote' || $mode == 'quotepost' || $mode == 'forward' || $mode == 'post')
1831      {
1832          $sql = 'UPDATE ' . USERS_TABLE . "
1833              SET user_lastpost_time = $current_time
1834              WHERE user_id = " . $data['from_user_id'];
1835          $db->sql_query($sql);
1836      }
1837  
1838      // Submit Attachments
1839      if (!empty($data['attachment_data']) && $data['msg_id'] && in_array($mode, array('post', 'reply', 'quote', 'quotepost', 'edit', 'forward')))
1840      {
1841          $space_taken = $files_added = 0;
1842          $orphan_rows = array();
1843  
1844          foreach ($data['attachment_data'] as $pos => $attach_row)
1845          {
1846              $orphan_rows[(int) $attach_row['attach_id']] = array();
1847          }
1848  
1849          if (sizeof($orphan_rows))
1850          {
1851              $sql = 'SELECT attach_id, filesize, physical_filename
1852                  FROM ' . ATTACHMENTS_TABLE . '
1853                  WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan_rows)) . '
1854                      AND in_message = 1
1855                      AND is_orphan = 1
1856                      AND poster_id = ' . $user->data['user_id'];
1857              $result = $db->sql_query($sql);
1858  
1859              $orphan_rows = array();
1860              while ($row = $db->sql_fetchrow($result))
1861              {
1862                  $orphan_rows[$row['attach_id']] = $row;
1863              }
1864              $db->sql_freeresult($result);
1865          }
1866  
1867          foreach ($data['attachment_data'] as $pos => $attach_row)
1868          {
1869              if ($attach_row['is_orphan'] && !isset($orphan_rows[$attach_row['attach_id']]))
1870              {
1871                  continue;
1872              }
1873  
1874              if (!$attach_row['is_orphan'])
1875              {
1876                  // update entry in db if attachment already stored in db and filespace
1877                  $sql = 'UPDATE ' . ATTACHMENTS_TABLE . "
1878                      SET attach_comment = '" . $db->sql_escape($attach_row['attach_comment']) . "'
1879                      WHERE attach_id = " . (int) $attach_row['attach_id'] . '
1880                          AND is_orphan = 0';
1881                  $db->sql_query($sql);
1882              }
1883              else
1884              {
1885                  // insert attachment into db
1886                  if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . utf8_basename($orphan_rows[$attach_row['attach_id']]['physical_filename'])))
1887                  {
1888                      continue;
1889                  }
1890  
1891                  $space_taken += $orphan_rows[$attach_row['attach_id']]['filesize'];
1892                  $files_added++;
1893  
1894                  $attach_sql = array(
1895                      'post_msg_id'        => $data['msg_id'],
1896                      'topic_id'            => 0,
1897                      'is_orphan'            => 0,
1898                      'poster_id'            => $data['from_user_id'],
1899                      'attach_comment'    => $attach_row['attach_comment'],
1900                  );
1901  
1902                  $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $attach_sql) . '
1903                      WHERE attach_id = ' . $attach_row['attach_id'] . '
1904                          AND is_orphan = 1
1905                          AND poster_id = ' . $user->data['user_id'];
1906                  $db->sql_query($sql);
1907              }
1908          }
1909  
1910          if ($space_taken && $files_added)
1911          {
1912              set_config_count('upload_dir_size', $space_taken, true);
1913              set_config_count('num_files', $files_added, true);
1914          }
1915      }
1916  
1917      // Delete draft if post was loaded...
1918      $draft_id = request_var('draft_loaded', 0);
1919      if ($draft_id)
1920      {
1921          $sql = 'DELETE FROM ' . DRAFTS_TABLE . "
1922              WHERE draft_id = $draft_id
1923                  AND user_id = " . $data['from_user_id'];
1924          $db->sql_query($sql);
1925      }
1926  
1927      $db->sql_transaction('commit');
1928  
1929      // Send Notifications
1930      $pm_data = array_merge($data, array(
1931          'message_subject'        => $subject,
1932          'recipients'            => $recipients,
1933      ));
1934  
1935      $phpbb_notifications = $phpbb_container->get('notification_manager');
1936  
1937      if ($mode == 'edit')
1938      {
1939          $phpbb_notifications->update_notifications('notification.type.pm', $pm_data);
1940      }
1941      else
1942      {
1943          $phpbb_notifications->add_notifications('notification.type.pm', $pm_data);
1944      }
1945  
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  
1959      return $data['msg_id'];
1960  }
1961  
1962  /**
1963  * Display Message History
1964  */
1965  function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode = false)
1966  {
1967      global $db, $user, $config, $template, $phpbb_root_path, $phpEx, $auth;
1968  
1969      // Select all receipts and the author from the pm we currently view, to only display their pm-history
1970      $sql = 'SELECT author_id, user_id
1971          FROM ' . PRIVMSGS_TO_TABLE . "
1972          WHERE msg_id = $msg_id
1973              AND folder_id <> " . PRIVMSGS_HOLD_BOX;
1974      $result = $db->sql_query($sql);
1975  
1976      $recipients = array();
1977      while ($row = $db->sql_fetchrow($result))
1978      {
1979          $recipients[] = (int) $row['user_id'];
1980          $recipients[] = (int) $row['author_id'];
1981      }
1982      $db->sql_freeresult($result);
1983      $recipients = array_unique($recipients);
1984  
1985      // Get History Messages (could be newer)
1986      $sql = 'SELECT t.*, p.*, u.*
1987          FROM ' . PRIVMSGS_TABLE . ' p, ' . PRIVMSGS_TO_TABLE . ' t, ' . USERS_TABLE . ' u
1988          WHERE t.msg_id = p.msg_id
1989              AND p.author_id = u.user_id
1990              AND t.folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
1991              AND ' . $db->sql_in_set('t.author_id', $recipients, false, true) . "
1992              AND t.user_id = $user_id";
1993  
1994      // We no longer need those.
1995      unset($recipients);
1996  
1997      if (!$message_row['root_level'])
1998      {
1999          $sql .= " AND (p.root_level = $msg_id OR (p.root_level = 0 AND p.msg_id = $msg_id))";
2000      }
2001      else
2002      {
2003          $sql .= " AND (p.root_level = " . $message_row['root_level'] . ' OR p.msg_id = ' . $message_row['root_level'] . ')';
2004      }
2005      $sql .= ' ORDER BY p.message_time DESC';
2006  
2007      $result = $db->sql_query($sql);
2008      $row = $db->sql_fetchrow($result);
2009  
2010      if (!$row)
2011      {
2012          $db->sql_freeresult($result);
2013          return false;
2014      }
2015  
2016      $title = $row['message_subject'];
2017  
2018      $rowset = array();
2019      $folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm') . '&amp;folder=';
2020  
2021      do
2022      {
2023          $folder_id = (int) $row['folder_id'];
2024  
2025          $row['folder'][] = (isset($folder[$folder_id])) ? '<a href="' . $folder_url . $folder_id . '">' . $folder[$folder_id]['folder_name'] . '</a>' : $user->lang['UNKNOWN_FOLDER'];
2026  
2027          if (isset($rowset[$row['msg_id']]))
2028          {
2029              $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'];
2030          }
2031          else
2032          {
2033              $rowset[$row['msg_id']] = $row;
2034          }
2035      }
2036      while ($row = $db->sql_fetchrow($result));
2037      $db->sql_freeresult($result);
2038  
2039      if (sizeof($rowset) == 1 && !$in_post_mode)
2040      {
2041          return false;
2042      }
2043  
2044      $title = censor_text($title);
2045  
2046      $url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm');
2047      $next_history_pm = $previous_history_pm = $prev_id = 0;
2048  
2049      // Re-order rowset to be able to get the next/prev message rows...
2050      $rowset = array_values($rowset);
2051  
2052      for ($i = 0, $size = sizeof($rowset); $i < $size; $i++)
2053      {
2054          $row = &$rowset[$i];
2055          $id = (int) $row['msg_id'];
2056  
2057          $author_id    = $row['author_id'];
2058          $folder_id    = (int) $row['folder_id'];
2059  
2060          $subject    = $row['message_subject'];
2061          $message    = $row['message_text'];
2062  
2063          $message = censor_text($message);
2064  
2065          $decoded_message = false;
2066  
2067          if ($in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS)
2068          {
2069              $decoded_message = $message;
2070              decode_message($decoded_message, $row['bbcode_uid']);
2071  
2072              $decoded_message = bbcode_nl2br($decoded_message);
2073          }
2074  
2075          $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0);
2076          $parse_flags |= ($row['enable_smilies'] ? OPTION_FLAG_SMILIES : 0);
2077  
2078          $message = generate_text_for_display($message, $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false);
2079  
2080          $subject = censor_text($subject);
2081  
2082          if ($id == $msg_id)
2083          {
2084              $next_history_pm = (isset($rowset[$i + 1])) ? (int) $rowset[$i + 1]['msg_id'] : 0;
2085              $previous_history_pm = $prev_id;
2086          }
2087  
2088          $template->assign_block_vars('history_row', array(
2089              'MESSAGE_AUTHOR_QUOTE'        => (($decoded_message) ? addslashes(get_username_string('username', $author_id, $row['username'], $row['user_colour'], $row['username'])) : ''),
2090              'MESSAGE_AUTHOR_FULL'        => get_username_string('full', $author_id, $row['username'], $row['user_colour'], $row['username']),
2091              'MESSAGE_AUTHOR_COLOUR'        => get_username_string('colour', $author_id, $row['username'], $row['user_colour'], $row['username']),
2092              'MESSAGE_AUTHOR'            => get_username_string('username', $author_id, $row['username'], $row['user_colour'], $row['username']),
2093              'U_MESSAGE_AUTHOR'            => get_username_string('profile', $author_id, $row['username'], $row['user_colour'], $row['username']),
2094  
2095              'SUBJECT'            => $subject,
2096              'SENT_DATE'            => $user->format_date($row['message_time']),
2097              'MESSAGE'            => $message,
2098              'FOLDER'            => implode($user->lang['COMMA_SEPARATOR'], $row['folder']),
2099              'DECODED_MESSAGE'    => $decoded_message,
2100  
2101              'S_CURRENT_MSG'        => ($row['msg_id'] == $msg_id),
2102              'S_AUTHOR_DELETED'    => ($author_id == ANONYMOUS) ? true : false,
2103              'S_IN_POST_MODE'    => $in_post_mode,
2104  
2105              'MSG_ID'            => $row['msg_id'],
2106              'U_VIEW_MESSAGE'    => "$url&amp;f=$folder_id&amp;p=" . $row['msg_id'],
2107              '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'] : '',
2108              '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'] : '')
2109          );
2110          unset($rowset[$i]);
2111          $prev_id = $id;
2112      }
2113  
2114      $template->assign_vars(array(
2115          'QUOTE_IMG'            => $user->img('icon_post_quote', $user->lang['REPLY_WITH_QUOTE']),
2116          'HISTORY_TITLE'        => $title,
2117  
2118          'U_VIEW_NEXT_HISTORY'        => ($next_history_pm) ? "$url&amp;p=" . $next_history_pm : '',
2119          'U_VIEW_PREVIOUS_HISTORY'    => ($previous_history_pm) ? "$url&amp;p=" . $previous_history_pm : '',
2120      ));
2121  
2122      return true;
2123  }
2124  
2125  /**
2126  * Set correct users max messages in PM folder.
2127  * If several group memberships define different amount of messages, the highest will be chosen.
2128  */
2129  function set_user_message_limit()
2130  {
2131      global $user, $db, $config;
2132  
2133      // Get maximum about from user memberships - if it is 0, there is no limit set and we use the maximum value within the config.
2134      $sql = 'SELECT MAX(g.group_message_limit) as max_message_limit
2135          FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug
2136          WHERE ug.user_id = ' . $user->data['user_id'] . '
2137              AND ug.user_pending = 0
2138              AND ug.group_id = g.group_id';
2139      $result = $db->sql_query($sql);
2140      $message_limit = (int) $db->sql_fetchfield('max_message_limit');
2141      $db->sql_freeresult($result);
2142  
2143      $user->data['message_limit'] = (!$message_limit) ? $config['pm_max_msgs'] : $message_limit;
2144  }
2145  
2146  /**
2147  * Generates an array of coloured recipient names from a list of PMs - (groups & users)
2148  *
2149  * @param    array    $pm_by_id    An array of rows from PRIVMSGS_TABLE, keys are the msg_ids.
2150  *
2151  * @return    array                2D Array: array(msg_id => array('username or group string', ...), ...)
2152  *                                Usernames are generated with {@link get_username_string get_username_string}
2153  *                                Groups are coloured and have a link to the membership page
2154  */
2155  function get_recipient_strings($pm_by_id)
2156  {
2157      global $db, $phpbb_root_path, $phpEx, $user;
2158  
2159      $address_list = $recipient_list = $address = array();
2160  
2161      $_types = array('u', 'g');
2162  
2163      foreach ($pm_by_id as $message_id => $row)
2164      {
2165          $address[$message_id] = rebuild_header(array('to' => $row['to_address'], 'bcc' => $row['bcc_address']));
2166  
2167          foreach ($_types as $ug_type)
2168          {
2169              if (isset($address[$message_id][$ug_type]) && sizeof($address[$message_id][$ug_type]))
2170              {
2171                  foreach ($address[$message_id][$ug_type] as $ug_id => $in_to)
2172                  {
2173                      $recipient_list[$ug_type][$ug_id] = array('name' => $user->lang['NA'], 'colour' => '');
2174                  }
2175              }
2176          }
2177      }
2178  
2179      foreach ($_types as $ug_type)
2180      {
2181          if (!empty($recipient_list[$ug_type]))
2182          {
2183              if ($ug_type == 'u')
2184              {
2185                  $sql = 'SELECT user_id as id, username as name, user_colour as colour
2186                      FROM ' . USERS_TABLE . '
2187                      WHERE ';
2188              }
2189              else
2190              {
2191                  $sql = 'SELECT group_id as id, group_name as name, group_colour as colour, group_type
2192                      FROM ' . GROUPS_TABLE . '
2193                      WHERE ';
2194              }
2195              $sql .= $db->sql_in_set(($ug_type == 'u') ? 'user_id' : 'group_id', array_map('intval', array_keys($recipient_list[$ug_type])));
2196  
2197              $result = $db->sql_query($sql);
2198  
2199              while ($row = $db->sql_fetchrow($result))
2200              {
2201                  if ($ug_type == 'g')
2202                  {
2203                      $row['name'] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['name']] : $row['name'];
2204                  }
2205  
2206                  $recipient_list[$ug_type][$row['id']] = array('name' => $row['name'], 'colour' => $row['colour']);
2207              }
2208              $db->sql_freeresult($result);
2209          }
2210      }
2211  
2212      foreach ($address as $message_id => $adr_ary)
2213      {
2214          foreach ($adr_ary as $type => $id_ary)
2215          {
2216              foreach ($id_ary as $ug_id => $_id)
2217              {
2218                  if ($type == 'u')
2219                  {
2220                      $address_list[$message_id][] = get_username_string('full', $ug_id, $recipient_list[$type][$ug_id]['name'], $recipient_list[$type][$ug_id]['colour']);
2221                  }
2222                  else
2223                  {
2224                      $user_colour = ($recipient_list[$type][$ug_id]['colour']) ? ' style="font-weight: bold; color:#' . $recipient_list[$type][$ug_id]['colour'] . '"' : '';
2225                      $link = '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&amp;g=' . $ug_id) . '"' . $user_colour . '>';
2226                      $address_list[$message_id][] = $link . $recipient_list[$type][$ug_id]['name'] . (($link) ? '</a>' : '');
2227                  }
2228              }
2229          }
2230      }
2231  
2232      return $address_list;
2233  }


Generated: Thu Jan 11 00:25:41 2018 Cross-referenced by PHPXref 0.7.1