[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/includes/ -> functions_privmsgs.php (source)

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


Generated: Wed Oct 2 15:03:47 2013 Cross-referenced by PHPXref 0.7.1