Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

functions_privmsgs.php

Zuletzt modifiziert: 09.10.2024, 12:51 - Dateigröße: 63.71 KiB


 0001  <?php
 0002  /**
 0003  *
 0004  * This file is part of the phpBB Forum Software package.
 0005  *
 0006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
 0007  * @license GNU General Public License, version 2 (GPL-2.0)
 0008  *
 0009  * For full copyright and license information, please see
 0010  * the docs/CREDITS.txt file.
 0011  *
 0012  */
 0013   
 0014  /**
 0015  */
 0016  if (!defined('IN_PHPBB'))
 0017  {
 0018      exit;
 0019  }
 0020   
 0021  /*
 0022      Ability to simply add own rules by doing three things:
 0023          1) Add an appropriate constant
 0024          2) Add a new check array to the global_privmsgs_rules variable and the condition array (if one is required)
 0025          3) Implement the rule logic in the check_rule() function
 0026          4) Add a new language variable to ucp.php
 0027   
 0028          The user is then able to select the new rule. It will be checked against and handled as specified.
 0029          To add new actions (yes, checks can be added here too) to the rule management, the core code has to be modified.
 0030  */
 0031   
 0032  define('RULE_IS_LIKE', 1);        // Is Like
 0033  define('RULE_IS_NOT_LIKE', 2);    // Is Not Like
 0034  define('RULE_IS', 3);            // Is
 0035  define('RULE_IS_NOT', 4);        // Is Not
 0036  define('RULE_BEGINS_WITH', 5);    // Begins with
 0037  define('RULE_ENDS_WITH', 6);    // Ends with
 0038  define('RULE_IS_FRIEND', 7);    // Is Friend
 0039  define('RULE_IS_FOE', 8);        // Is Foe
 0040  define('RULE_IS_USER', 9);        // Is User
 0041  define('RULE_IS_GROUP', 10);    // Is In Usergroup
 0042  define('RULE_ANSWERED', 11);    // Answered
 0043  define('RULE_FORWARDED', 12);    // Forwarded
 0044  define('RULE_TO_GROUP', 14);    // Usergroup
 0045  define('RULE_TO_ME', 15);        // Me
 0046   
 0047  define('ACTION_PLACE_INTO_FOLDER', 1);
 0048  define('ACTION_MARK_AS_READ', 2);
 0049  define('ACTION_MARK_AS_IMPORTANT', 3);
 0050  define('ACTION_DELETE_MESSAGE', 4);
 0051   
 0052  define('CHECK_SUBJECT', 1);
 0053  define('CHECK_SENDER', 2);
 0054  define('CHECK_MESSAGE', 3);
 0055  define('CHECK_STATUS', 4);
 0056  define('CHECK_TO', 5);
 0057   
 0058  /**
 0059  * Global private message rules
 0060  * These rules define what to do if a rule is hit
 0061  */
 0062  $global_privmsgs_rules = array(
 0063      CHECK_SUBJECT    => array(
 0064          RULE_IS_LIKE        => array('check0' => 'message_subject'),
 0065          RULE_IS_NOT_LIKE    => array('check0' => 'message_subject'),
 0066          RULE_IS                => array('check0' => 'message_subject'),
 0067          RULE_IS_NOT            => array('check0' => 'message_subject'),
 0068          RULE_BEGINS_WITH    => array('check0' => 'message_subject'),
 0069          RULE_ENDS_WITH        => array('check0' => 'message_subject'),
 0070      ),
 0071   
 0072      CHECK_SENDER    => array(
 0073          RULE_IS_LIKE        => array('check0' => 'username'),
 0074          RULE_IS_NOT_LIKE    => array('check0' => 'username'),
 0075          RULE_IS                => array('check0' => 'username'),
 0076          RULE_IS_NOT            => array('check0' => 'username'),
 0077          RULE_BEGINS_WITH    => array('check0' => 'username'),
 0078          RULE_ENDS_WITH        => array('check0' => 'username'),
 0079          RULE_IS_FRIEND        => array('check0' => 'friend'),
 0080          RULE_IS_FOE            => array('check0' => 'foe'),
 0081          RULE_IS_USER        => array('check0' => 'author_id'),
 0082          RULE_IS_GROUP        => array('check0' => 'author_in_group'),
 0083      ),
 0084   
 0085      CHECK_MESSAGE    => array(
 0086          RULE_IS_LIKE        => array('check0' => 'message_text'),
 0087          RULE_IS_NOT_LIKE    => array('check0' => 'message_text'),
 0088          RULE_IS                => array('check0' => 'message_text'),
 0089          RULE_IS_NOT            => array('check0' => 'message_text'),
 0090      ),
 0091   
 0092      CHECK_STATUS    => array(
 0093          RULE_ANSWERED        => array('check0' => 'pm_replied'),
 0094          RULE_FORWARDED        => array('check0' => 'pm_forwarded'),
 0095      ),
 0096   
 0097      CHECK_TO        => array(
 0098          RULE_TO_GROUP        => array('check0' => 'to', 'check1' => 'bcc', 'check2' => 'user_in_group'),
 0099          RULE_TO_ME            => array('check0' => 'to', 'check1' => 'bcc'),
 0100      )
 0101  );
 0102   
 0103  /**
 0104  * This is for defining which condition fields to show for which Rule
 0105  */
 0106  $global_rule_conditions = array(
 0107      RULE_IS_LIKE        => 'text',
 0108      RULE_IS_NOT_LIKE    => 'text',
 0109      RULE_IS                => 'text',
 0110      RULE_IS_NOT            => 'text',
 0111      RULE_BEGINS_WITH    => 'text',
 0112      RULE_ENDS_WITH        => 'text',
 0113      RULE_IS_USER        => 'user',
 0114      RULE_IS_GROUP        => 'group'
 0115  );
 0116   
 0117  /**
 0118  * Get all folder
 0119  */
 0120  function get_folder($user_id, $folder_id = false)
 0121  {
 0122      global $db, $user, $template;
 0123      global $phpbb_root_path, $phpEx;
 0124   
 0125      $folder = array();
 0126   
 0127      // Get folder information
 0128      $sql = 'SELECT folder_id, COUNT(msg_id) as num_messages, SUM(pm_unread) as num_unread
 0129          FROM ' . PRIVMSGS_TO_TABLE . "
 0130          WHERE user_id = $user_id
 0131              AND folder_id <> " . PRIVMSGS_NO_BOX . '
 0132          GROUP BY folder_id';
 0133      $result = $db->sql_query($sql);
 0134   
 0135      $num_messages = $num_unread = array();
 0136      while ($row = $db->sql_fetchrow($result))
 0137      {
 0138          $num_messages[(int) $row['folder_id']] = $row['num_messages'];
 0139          $num_unread[(int) $row['folder_id']] = $row['num_unread'];
 0140      }
 0141      $db->sql_freeresult($result);
 0142   
 0143      // Make sure the default boxes are defined
 0144      $available_folder = array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX);
 0145   
 0146      foreach ($available_folder as $default_folder)
 0147      {
 0148          if (!isset($num_messages[$default_folder]))
 0149          {
 0150              $num_messages[$default_folder] = 0;
 0151          }
 0152   
 0153          if (!isset($num_unread[$default_folder]))
 0154          {
 0155              $num_unread[$default_folder] = 0;
 0156          }
 0157      }
 0158   
 0159      // Adjust unread status for outbox
 0160      $num_unread[PRIVMSGS_OUTBOX] = $num_messages[PRIVMSGS_OUTBOX];
 0161   
 0162      $folder[PRIVMSGS_INBOX] = array(
 0163          'folder_name'        => $user->lang['PM_INBOX'],
 0164          'num_messages'        => $num_messages[PRIVMSGS_INBOX],
 0165          'unread_messages'    => $num_unread[PRIVMSGS_INBOX]
 0166      );
 0167   
 0168      // Custom Folder
 0169      $sql = 'SELECT folder_id, folder_name, pm_count
 0170          FROM ' . PRIVMSGS_FOLDER_TABLE . "
 0171              WHERE user_id = $user_id";
 0172      $result = $db->sql_query($sql);
 0173   
 0174      while ($row = $db->sql_fetchrow($result))
 0175      {
 0176          $folder[$row['folder_id']] = array(
 0177              'folder_name'        => $row['folder_name'],
 0178              'num_messages'        => $row['pm_count'],
 0179              'unread_messages'    => ((isset($num_unread[$row['folder_id']])) ? $num_unread[$row['folder_id']] : 0)
 0180          );
 0181      }
 0182      $db->sql_freeresult($result);
 0183   
 0184      $folder[PRIVMSGS_OUTBOX] = array(
 0185          'folder_name'        => $user->lang['PM_OUTBOX'],
 0186          'num_messages'        => $num_messages[PRIVMSGS_OUTBOX],
 0187          'unread_messages'    => $num_unread[PRIVMSGS_OUTBOX]
 0188      );
 0189   
 0190      $folder[PRIVMSGS_SENTBOX] = array(
 0191          'folder_name'        => $user->lang['PM_SENTBOX'],
 0192          'num_messages'        => $num_messages[PRIVMSGS_SENTBOX],
 0193          'unread_messages'    => $num_unread[PRIVMSGS_SENTBOX]
 0194      );
 0195   
 0196      // Define Folder Array for template designers (and for making custom folders usable by the template too)
 0197      foreach ($folder as $f_id => $folder_ary)
 0198      {
 0199          $folder_id_name = ($f_id == PRIVMSGS_INBOX) ? 'inbox' : (($f_id == PRIVMSGS_OUTBOX) ? 'outbox' : 'sentbox');
 0200   
 0201          $template->assign_block_vars('folder', array(
 0202              'FOLDER_ID'            => $f_id,
 0203              'FOLDER_NAME'        => $folder_ary['folder_name'],
 0204              'NUM_MESSAGES'        => $folder_ary['num_messages'],
 0205              'UNREAD_MESSAGES'    => $folder_ary['unread_messages'],
 0206   
 0207              '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),
 0208   
 0209              'S_CUR_FOLDER'        => ($f_id === $folder_id) ? true : false,
 0210              'S_UNREAD_MESSAGES'    => ($folder_ary['unread_messages']) ? true : false,
 0211              'S_CUSTOM_FOLDER'    => ($f_id > 0) ? true : false)
 0212          );
 0213      }
 0214   
 0215      if ($folder_id !== false && $folder_id !== PRIVMSGS_HOLD_BOX && !isset($folder[$folder_id]))
 0216      {
 0217          trigger_error('UNKNOWN_FOLDER');
 0218      }
 0219   
 0220      return $folder;
 0221  }
 0222   
 0223  /**
 0224  * Delete Messages From Sentbox
 0225  * we are doing this here because this saves us a bunch of checks and queries
 0226  */
 0227  function clean_sentbox($num_sentbox_messages)
 0228  {
 0229      global $db, $user, $config;
 0230   
 0231      // Check Message Limit
 0232      if ($user->data['message_limit'] && $num_sentbox_messages > $user->data['message_limit'])
 0233      {
 0234          // Delete old messages
 0235          $sql = 'SELECT t.msg_id
 0236              FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p
 0237              WHERE t.msg_id = p.msg_id
 0238                  AND t.user_id = ' . $user->data['user_id'] . '
 0239                  AND t.folder_id = ' . PRIVMSGS_SENTBOX . '
 0240              ORDER BY p.message_time ASC';
 0241          $result = $db->sql_query_limit($sql, ($num_sentbox_messages - $user->data['message_limit']));
 0242   
 0243          $delete_ids = array();
 0244          while ($row = $db->sql_fetchrow($result))
 0245          {
 0246              $delete_ids[] = $row['msg_id'];
 0247          }
 0248          $db->sql_freeresult($result);
 0249          delete_pm($user->data['user_id'], $delete_ids, PRIVMSGS_SENTBOX);
 0250      }
 0251  }
 0252   
 0253  /**
 0254  * Check Rule against Message Information
 0255  */
 0256  function check_rule(&$rules, &$rule_row, &$message_row, $user_id)
 0257  {
 0258      global $user, $config;
 0259   
 0260      if (!isset($rules[$rule_row['rule_check']][$rule_row['rule_connection']]))
 0261      {
 0262          return false;
 0263      }
 0264   
 0265      $check_ary = $rules[$rule_row['rule_check']][$rule_row['rule_connection']];
 0266   
 0267      $result = false;
 0268   
 0269      $check0 = $message_row[$check_ary['check0']];
 0270   
 0271      switch ($rule_row['rule_connection'])
 0272      {
 0273          case RULE_IS_LIKE:
 0274              $result = preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0);
 0275          break;
 0276   
 0277          case RULE_IS_NOT_LIKE:
 0278              $result = !preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0);
 0279          break;
 0280   
 0281          case RULE_IS:
 0282              $result = ($check0 == $rule_row['rule_string']);
 0283          break;
 0284   
 0285          case RULE_IS_NOT:
 0286              $result = ($check0 != $rule_row['rule_string']);
 0287          break;
 0288   
 0289          case RULE_BEGINS_WITH:
 0290              $result = preg_match("/^" . preg_quote($rule_row['rule_string'], '/') . '/i', $check0);
 0291          break;
 0292   
 0293          case RULE_ENDS_WITH:
 0294              $result = preg_match("/" . preg_quote($rule_row['rule_string'], '/') . '$/i', $check0);
 0295          break;
 0296   
 0297          case RULE_IS_FRIEND:
 0298          case RULE_IS_FOE:
 0299          case RULE_ANSWERED:
 0300          case RULE_FORWARDED:
 0301              $result = ($check0 == 1);
 0302          break;
 0303   
 0304          case RULE_IS_USER:
 0305              $result = ($check0 == $rule_row['rule_user_id']);
 0306          break;
 0307   
 0308          case RULE_IS_GROUP:
 0309              $result = in_array($rule_row['rule_group_id'], $check0);
 0310          break;
 0311   
 0312          case RULE_TO_GROUP:
 0313              $result = (in_array('g_' . $message_row[$check_ary['check2']], $check0) || in_array('g_' . $message_row[$check_ary['check2']], $message_row[$check_ary['check1']]));
 0314          break;
 0315   
 0316          case RULE_TO_ME:
 0317              $result = (in_array('u_' . $user_id, $check0) || in_array('u_' . $user_id, $message_row[$check_ary['check1']]));
 0318          break;
 0319      }
 0320   
 0321      if (!$result)
 0322      {
 0323          return false;
 0324      }
 0325   
 0326      switch ($rule_row['rule_action'])
 0327      {
 0328          case ACTION_PLACE_INTO_FOLDER:
 0329              return array('action' => $rule_row['rule_action'], 'folder_id' => $rule_row['rule_folder_id']);
 0330          break;
 0331   
 0332          case ACTION_MARK_AS_READ:
 0333          case ACTION_MARK_AS_IMPORTANT:
 0334              return array('action' => $rule_row['rule_action'], 'pm_unread' => $message_row['pm_unread'], 'pm_marked' => $message_row['pm_marked']);
 0335          break;
 0336   
 0337          case ACTION_DELETE_MESSAGE:
 0338              global $db, $auth;
 0339   
 0340              // Check for admins/mods - users are not allowed to remove those messages...
 0341              // We do the check here to make sure the data we use is consistent
 0342              $sql = 'SELECT user_id, user_type, user_permissions
 0343                  FROM ' . USERS_TABLE . '
 0344                  WHERE user_id = ' . (int) $message_row['author_id'];
 0345              $result = $db->sql_query($sql);
 0346              $userdata = $db->sql_fetchrow($result);
 0347              $db->sql_freeresult($result);
 0348   
 0349              $auth2 = new \phpbb\auth\auth();
 0350              $auth2->acl($userdata);
 0351   
 0352              if (!$auth2->acl_get('a_') && !$auth2->acl_get('m_') && !$auth2->acl_getf_global('m_'))
 0353              {
 0354                  return array('action' => $rule_row['rule_action'], 'pm_unread' => $message_row['pm_unread'], 'pm_marked' => $message_row['pm_marked']);
 0355              }
 0356   
 0357              return false;
 0358          break;
 0359   
 0360          default:
 0361              return false;
 0362      }
 0363   
 0364      return false;
 0365  }
 0366   
 0367  /**
 0368  * Update user PM count
 0369  */
 0370  function update_pm_counts()
 0371  {
 0372      global $user, $db;
 0373   
 0374      // Update unread count
 0375      $sql = 'SELECT COUNT(msg_id) as num_messages
 0376          FROM ' . PRIVMSGS_TO_TABLE . '
 0377          WHERE pm_unread = 1
 0378              AND folder_id <> ' . PRIVMSGS_OUTBOX . '
 0379              AND user_id = ' . $user->data['user_id'];
 0380      $result = $db->sql_query($sql);
 0381      $user->data['user_unread_privmsg'] = (int) $db->sql_fetchfield('num_messages');
 0382      $db->sql_freeresult($result);
 0383   
 0384      // Update new pm count
 0385      $sql = 'SELECT COUNT(msg_id) as num_messages
 0386          FROM ' . PRIVMSGS_TO_TABLE . '
 0387          WHERE pm_new = 1
 0388              AND folder_id IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
 0389              AND user_id = ' . $user->data['user_id'];
 0390      $result = $db->sql_query($sql);
 0391      $user->data['user_new_privmsg'] = (int) $db->sql_fetchfield('num_messages');
 0392      $db->sql_freeresult($result);
 0393   
 0394      $db->sql_query('UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array(
 0395          'user_unread_privmsg'    => (int) $user->data['user_unread_privmsg'],
 0396          'user_new_privmsg'        => (int) $user->data['user_new_privmsg'],
 0397      )) . ' WHERE user_id = ' . $user->data['user_id']);
 0398   
 0399      // Ok, here we need to repair something, other boxes than privmsgs_no_box and privmsgs_hold_box should not carry the pm_new flag.
 0400      if (!$user->data['user_new_privmsg'])
 0401      {
 0402          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 0403              SET pm_new = 0
 0404              WHERE pm_new = 1
 0405                  AND folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
 0406                  AND user_id = ' . $user->data['user_id'];
 0407          $db->sql_query($sql);
 0408      }
 0409  }
 0410   
 0411  /**
 0412  * Place new messages into appropriate folder
 0413  */
 0414  function place_pm_into_folder(&$global_privmsgs_rules, $release = false)
 0415  {
 0416      global $db, $user, $config;
 0417   
 0418      if (!$user->data['user_new_privmsg'])
 0419      {
 0420          return array('not_moved' => 0, 'removed' => 0);
 0421      }
 0422   
 0423      $user_message_rules = (int) $user->data['user_message_rules'];
 0424      $user_id = (int) $user->data['user_id'];
 0425   
 0426      $action_ary = $move_into_folder = array();
 0427      $num_removed = 0;
 0428   
 0429      // Newly processing on-hold messages
 0430      if ($release)
 0431      {
 0432          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 0433              SET folder_id = ' . PRIVMSGS_NO_BOX . '
 0434              WHERE folder_id = ' . PRIVMSGS_HOLD_BOX . "
 0435                  AND user_id = $user_id";
 0436          $db->sql_query($sql);
 0437      }
 0438   
 0439      // Get those messages not yet placed into any box
 0440      $retrieve_sql = 'SELECT t.*, p.*, u.username, u.user_id, u.group_id
 0441          FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p, ' . USERS_TABLE . " u
 0442          WHERE t.user_id = $user_id
 0443              AND p.author_id = u.user_id
 0444              AND t.folder_id = " . PRIVMSGS_NO_BOX . '
 0445              AND t.msg_id = p.msg_id';
 0446   
 0447      // Just place into the appropriate arrays if no rules need to be checked
 0448      if (!$user_message_rules)
 0449      {
 0450          $result = $db->sql_query($retrieve_sql);
 0451   
 0452          while ($row = $db->sql_fetchrow($result))
 0453          {
 0454              $action_ary[$row['msg_id']][] = array('action' => false);
 0455          }
 0456          $db->sql_freeresult($result);
 0457      }
 0458      else
 0459      {
 0460          $user_rules = $zebra = $check_rows = array();
 0461          $user_ids = $memberships = array();
 0462   
 0463          // First of all, grab all rules and retrieve friends/foes
 0464          $sql = 'SELECT *
 0465              FROM ' . PRIVMSGS_RULES_TABLE . "
 0466              WHERE user_id = $user_id";
 0467          $result = $db->sql_query($sql);
 0468          $user_rules = $db->sql_fetchrowset($result);
 0469          $db->sql_freeresult($result);
 0470   
 0471          if (sizeof($user_rules))
 0472          {
 0473              $sql = 'SELECT zebra_id, friend, foe
 0474                  FROM ' . ZEBRA_TABLE . "
 0475                  WHERE user_id = $user_id";
 0476              $result = $db->sql_query($sql);
 0477   
 0478              while ($row = $db->sql_fetchrow($result))
 0479              {
 0480                  $zebra[$row['zebra_id']] = $row;
 0481              }
 0482              $db->sql_freeresult($result);
 0483          }
 0484   
 0485          // Now build a bare-bone check_row array
 0486          $result = $db->sql_query($retrieve_sql);
 0487   
 0488          while ($row = $db->sql_fetchrow($result))
 0489          {
 0490              $check_rows[] = array_merge($row, array(
 0491                  'to'                => explode(':', $row['to_address']),
 0492                  'bcc'                => explode(':', $row['bcc_address']),
 0493                  'friend'            => (isset($zebra[$row['author_id']])) ? $zebra[$row['author_id']]['friend'] : 0,
 0494                  'foe'                => (isset($zebra[$row['author_id']])) ? $zebra[$row['author_id']]['foe'] : 0,
 0495                  'user_in_group'        => array($user->data['group_id']),
 0496                  'author_in_group'    => array())
 0497              );
 0498   
 0499              $user_ids[] = $row['user_id'];
 0500          }
 0501          $db->sql_freeresult($result);
 0502   
 0503          // Retrieve user memberships
 0504          if (sizeof($user_ids))
 0505          {
 0506              $sql = 'SELECT *
 0507                  FROM ' . USER_GROUP_TABLE . '
 0508                  WHERE ' . $db->sql_in_set('user_id', $user_ids) . '
 0509                      AND user_pending = 0';
 0510              $result = $db->sql_query($sql);
 0511   
 0512              while ($row = $db->sql_fetchrow($result))
 0513              {
 0514                  $memberships[$row['user_id']][] = $row['group_id'];
 0515              }
 0516              $db->sql_freeresult($result);
 0517          }
 0518   
 0519          // Now place into the appropriate folder
 0520          foreach ($check_rows as $row)
 0521          {
 0522              // Add membership if set
 0523              if (isset($memberships[$row['author_id']]))
 0524              {
 0525                  $row['author_in_group'] = $memberships[$row['user_id']];
 0526              }
 0527   
 0528              // Check Rule - this should be very quick since we have all information we need
 0529              $is_match = false;
 0530              foreach ($user_rules as $rule_row)
 0531              {
 0532                  if (($action = check_rule($global_privmsgs_rules, $rule_row, $row, $user_id)) !== false)
 0533                  {
 0534                      $is_match = true;
 0535                      $action_ary[$row['msg_id']][] = $action;
 0536                  }
 0537              }
 0538   
 0539              if (!$is_match)
 0540              {
 0541                  $action_ary[$row['msg_id']][] = array('action' => false);
 0542              }
 0543          }
 0544   
 0545          unset($user_rules, $zebra, $check_rows, $user_ids, $memberships);
 0546      }
 0547   
 0548      // We place actions into arrays, to save queries.
 0549      $sql = $unread_ids = $delete_ids = $important_ids = array();
 0550   
 0551      foreach ($action_ary as $msg_id => $msg_ary)
 0552      {
 0553          // It is allowed to execute actions more than once, except placing messages into folder
 0554          $folder_action = $message_removed = false;
 0555   
 0556          foreach ($msg_ary as $pos => $rule_ary)
 0557          {
 0558              if ($folder_action && $rule_ary['action'] == ACTION_PLACE_INTO_FOLDER)
 0559              {
 0560                  continue;
 0561              }
 0562   
 0563              switch ($rule_ary['action'])
 0564              {
 0565                  case ACTION_PLACE_INTO_FOLDER:
 0566                      // Folder actions have precedence, so we will remove any other ones
 0567                      $folder_action = true;
 0568                      $move_into_folder[(int) $rule_ary['folder_id']][] = $msg_id;
 0569                  break;
 0570   
 0571                  case ACTION_MARK_AS_READ:
 0572                      if ($rule_ary['pm_unread'])
 0573                      {
 0574                          $unread_ids[] = $msg_id;
 0575                      }
 0576                  break;
 0577   
 0578                  case ACTION_DELETE_MESSAGE:
 0579                      $delete_ids[] = $msg_id;
 0580                      $message_removed = true;
 0581                  break;
 0582   
 0583                  case ACTION_MARK_AS_IMPORTANT:
 0584                      if (!$rule_ary['pm_marked'])
 0585                      {
 0586                          $important_ids[] = $msg_id;
 0587                      }
 0588                  break;
 0589              }
 0590          }
 0591   
 0592          // 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
 0593          // folder. Here we simply move the message into the INBOX if it gets not removed and also not put into a custom folder.
 0594          if (!$folder_action && !$message_removed)
 0595          {
 0596              $move_into_folder[PRIVMSGS_INBOX][] = $msg_id;
 0597          }
 0598      }
 0599   
 0600      // Do not change the order of processing
 0601      // The number of queries needed to be executed here highly depends on the defined rules and are
 0602      // only gone through if new messages arrive.
 0603   
 0604      // Delete messages
 0605      if (sizeof($delete_ids))
 0606      {
 0607          $num_removed += sizeof($delete_ids);
 0608          delete_pm($user_id, $delete_ids, PRIVMSGS_NO_BOX);
 0609      }
 0610   
 0611      // Set messages to Unread
 0612      if (sizeof($unread_ids))
 0613      {
 0614          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 0615              SET pm_unread = 0
 0616              WHERE ' . $db->sql_in_set('msg_id', $unread_ids) . "
 0617                  AND user_id = $user_id
 0618                  AND folder_id = " . PRIVMSGS_NO_BOX;
 0619          $db->sql_query($sql);
 0620      }
 0621   
 0622      // mark messages as important
 0623      if (sizeof($important_ids))
 0624      {
 0625          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 0626              SET pm_marked = 1 - pm_marked
 0627              WHERE folder_id = ' . PRIVMSGS_NO_BOX . "
 0628                  AND user_id = $user_id
 0629                  AND " . $db->sql_in_set('msg_id', $important_ids);
 0630          $db->sql_query($sql);
 0631      }
 0632   
 0633      // Move into folder
 0634      $folder = array();
 0635   
 0636      if (sizeof($move_into_folder))
 0637      {
 0638          // Determine Full Folder Action - we need the move to folder id later eventually
 0639          $full_folder_action = ($user->data['user_full_folder'] == FULL_FOLDER_NONE) ? ($config['full_folder_action'] - (FULL_FOLDER_NONE*(-1))) : $user->data['user_full_folder'];
 0640   
 0641          $sql_folder = array_keys($move_into_folder);
 0642          if ($full_folder_action >= 0)
 0643          {
 0644              $sql_folder[] = $full_folder_action;
 0645          }
 0646   
 0647          $sql = 'SELECT folder_id, pm_count
 0648              FROM ' . PRIVMSGS_FOLDER_TABLE . '
 0649              WHERE ' . $db->sql_in_set('folder_id', $sql_folder) . "
 0650                  AND user_id = $user_id";
 0651          $result = $db->sql_query($sql);
 0652   
 0653          while ($row = $db->sql_fetchrow($result))
 0654          {
 0655              $folder[(int) $row['folder_id']] = (int) $row['pm_count'];
 0656          }
 0657          $db->sql_freeresult($result);
 0658   
 0659          unset($sql_folder);
 0660   
 0661          if (isset($move_into_folder[PRIVMSGS_INBOX]))
 0662          {
 0663              $sql = 'SELECT COUNT(msg_id) as num_messages
 0664                  FROM ' . PRIVMSGS_TO_TABLE . "
 0665                  WHERE user_id = $user_id
 0666                      AND folder_id = " . PRIVMSGS_INBOX;
 0667              $result = $db->sql_query($sql);
 0668              $folder[PRIVMSGS_INBOX] = (int) $db->sql_fetchfield('num_messages');
 0669              $db->sql_freeresult($result);
 0670          }
 0671      }
 0672   
 0673      // Here we have ideally only one folder to move into
 0674      foreach ($move_into_folder as $folder_id => $msg_ary)
 0675      {
 0676          $dest_folder = $folder_id;
 0677          $full_folder_action = FULL_FOLDER_NONE;
 0678   
 0679          // Check Message Limit - we calculate with the complete array, most of the time it is one message
 0680          // But we are making sure that the other way around works too (more messages in queue than allowed to be stored)
 0681          if ($user->data['message_limit'] && $folder[$folder_id] && ($folder[$folder_id] + sizeof($msg_ary)) > $user->data['message_limit'])
 0682          {
 0683              $full_folder_action = ($user->data['user_full_folder'] == FULL_FOLDER_NONE) ? ($config['full_folder_action'] - (FULL_FOLDER_NONE*(-1))) : $user->data['user_full_folder'];
 0684   
 0685              // If destination folder itself is full...
 0686              if ($full_folder_action >= 0 && ($folder[$full_folder_action] + sizeof($msg_ary)) > $user->data['message_limit'])
 0687              {
 0688                  $full_folder_action = $config['full_folder_action'] - (FULL_FOLDER_NONE*(-1));
 0689              }
 0690   
 0691              // If Full Folder Action is to move to another folder, we simply adjust the destination folder
 0692              if ($full_folder_action >= 0)
 0693              {
 0694                  $dest_folder = $full_folder_action;
 0695              }
 0696              else if ($full_folder_action == FULL_FOLDER_DELETE)
 0697              {
 0698                  // Delete some messages. NOTE: Ordered by msg_id here instead of message_time!
 0699                  $sql = 'SELECT msg_id
 0700                      FROM ' . PRIVMSGS_TO_TABLE . "
 0701                      WHERE user_id = $user_id
 0702                          AND folder_id = $dest_folder
 0703                      ORDER BY msg_id ASC";
 0704                  $result = $db->sql_query_limit($sql, (($folder[$dest_folder] + sizeof($msg_ary)) - $user->data['message_limit']));
 0705   
 0706                  $delete_ids = array();
 0707                  while ($row = $db->sql_fetchrow($result))
 0708                  {
 0709                      $delete_ids[] = $row['msg_id'];
 0710                  }
 0711                  $db->sql_freeresult($result);
 0712   
 0713                  $num_removed += sizeof($delete_ids);
 0714                  delete_pm($user_id, $delete_ids, $dest_folder);
 0715              }
 0716          }
 0717   
 0718          //
 0719          if ($full_folder_action == FULL_FOLDER_HOLD)
 0720          {
 0721              $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 0722                  SET folder_id = ' . PRIVMSGS_HOLD_BOX . '
 0723                  WHERE folder_id = ' . PRIVMSGS_NO_BOX . "
 0724                      AND user_id = $user_id
 0725                      AND " . $db->sql_in_set('msg_id', $msg_ary);
 0726              $db->sql_query($sql);
 0727          }
 0728          else
 0729          {
 0730              $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
 0731                  SET folder_id = $dest_folder, pm_new = 0
 0732                  WHERE folder_id = " . PRIVMSGS_NO_BOX . "
 0733                      AND user_id = $user_id
 0734                      AND pm_new = 1
 0735                      AND " . $db->sql_in_set('msg_id', $msg_ary);
 0736              $db->sql_query($sql);
 0737   
 0738              if ($dest_folder != PRIVMSGS_INBOX)
 0739              {
 0740                  $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . '
 0741                      SET pm_count = pm_count + ' . (int) $db->sql_affectedrows() . "
 0742                      WHERE folder_id = $dest_folder
 0743                          AND user_id = $user_id";
 0744                  $db->sql_query($sql);
 0745              }
 0746          }
 0747      }
 0748   
 0749      if (sizeof($action_ary))
 0750      {
 0751          // Move from OUTBOX to SENTBOX
 0752          // We are not checking any full folder status here... SENTBOX is a special treatment (old messages get deleted)
 0753          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 0754              SET folder_id = ' . PRIVMSGS_SENTBOX . '
 0755              WHERE folder_id = ' . PRIVMSGS_OUTBOX . '
 0756                  AND ' . $db->sql_in_set('msg_id', array_keys($action_ary));
 0757          $db->sql_query($sql);
 0758      }
 0759   
 0760      // Update new/unread count
 0761      update_pm_counts();
 0762   
 0763      // Now check how many messages got not moved...
 0764      $sql = 'SELECT COUNT(msg_id) as num_messages
 0765          FROM ' . PRIVMSGS_TO_TABLE . "
 0766          WHERE user_id = $user_id
 0767              AND folder_id = " . PRIVMSGS_HOLD_BOX;
 0768      $result = $db->sql_query($sql);
 0769      $num_not_moved = (int) $db->sql_fetchfield('num_messages');
 0770      $db->sql_freeresult($result);
 0771   
 0772      return array('not_moved' => $num_not_moved, 'removed' => $num_removed);
 0773  }
 0774   
 0775  /**
 0776  * Move PM from one to another folder
 0777  */
 0778  function move_pm($user_id, $message_limit, $move_msg_ids, $dest_folder, $cur_folder_id)
 0779  {
 0780      global $db, $user;
 0781      global $phpbb_root_path, $phpEx;
 0782   
 0783      $num_moved = 0;
 0784   
 0785      if (!is_array($move_msg_ids))
 0786      {
 0787          $move_msg_ids = array($move_msg_ids);
 0788      }
 0789   
 0790      if (sizeof($move_msg_ids) && !in_array($dest_folder, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX)) &&
 0791          !in_array($cur_folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)) && $cur_folder_id != $dest_folder)
 0792      {
 0793          // We have to check the destination folder ;)
 0794          if ($dest_folder != PRIVMSGS_INBOX)
 0795          {
 0796              $sql = 'SELECT folder_id, folder_name, pm_count
 0797                  FROM ' . PRIVMSGS_FOLDER_TABLE . "
 0798                  WHERE folder_id = $dest_folder
 0799                      AND user_id = $user_id";
 0800              $result = $db->sql_query($sql);
 0801              $row = $db->sql_fetchrow($result);
 0802              $db->sql_freeresult($result);
 0803   
 0804              if (!$row)
 0805              {
 0806                  trigger_error('NOT_AUTHORISED');
 0807              }
 0808   
 0809              if ($message_limit && $row['pm_count'] + sizeof($move_msg_ids) > $message_limit)
 0810              {
 0811                  $message = sprintf($user->lang['NOT_ENOUGH_SPACE_FOLDER'], $row['folder_name']) . '<br /><br />';
 0812                  $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']);
 0813                  trigger_error($message);
 0814              }
 0815          }
 0816          else
 0817          {
 0818              $sql = 'SELECT COUNT(msg_id) as num_messages
 0819                  FROM ' . PRIVMSGS_TO_TABLE . '
 0820                  WHERE folder_id = ' . PRIVMSGS_INBOX . "
 0821                      AND user_id = $user_id";
 0822              $result = $db->sql_query($sql);
 0823              $num_messages = (int) $db->sql_fetchfield('num_messages');
 0824              $db->sql_freeresult($result);
 0825   
 0826              if ($message_limit && $num_messages + sizeof($move_msg_ids) > $message_limit)
 0827              {
 0828                  $message = sprintf($user->lang['NOT_ENOUGH_SPACE_FOLDER'], $user->lang['PM_INBOX']) . '<br /><br />';
 0829                  $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']);
 0830                  trigger_error($message);
 0831              }
 0832          }
 0833   
 0834          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
 0835              SET folder_id = $dest_folder
 0836              WHERE folder_id = $cur_folder_id
 0837                  AND user_id = $user_id
 0838                  AND " . $db->sql_in_set('msg_id', $move_msg_ids);
 0839          $db->sql_query($sql);
 0840          $num_moved = $db->sql_affectedrows();
 0841   
 0842          // Update pm counts
 0843          if ($num_moved)
 0844          {
 0845              if (!in_array($cur_folder_id, array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX)))
 0846              {
 0847                  $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . "
 0848                      SET pm_count = pm_count - $num_moved
 0849                      WHERE folder_id = $cur_folder_id
 0850                          AND user_id = $user_id";
 0851                  $db->sql_query($sql);
 0852              }
 0853   
 0854              if ($dest_folder != PRIVMSGS_INBOX)
 0855              {
 0856                  $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . "
 0857                      SET pm_count = pm_count + $num_moved
 0858                      WHERE folder_id = $dest_folder
 0859                          AND user_id = $user_id";
 0860                  $db->sql_query($sql);
 0861              }
 0862          }
 0863      }
 0864      else if (in_array($cur_folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)))
 0865      {
 0866          trigger_error('CANNOT_MOVE_SPECIAL');
 0867      }
 0868   
 0869      return $num_moved;
 0870  }
 0871   
 0872  /**
 0873  * Update unread message status
 0874  */
 0875  function update_unread_status($unread, $msg_id, $user_id, $folder_id)
 0876  {
 0877      if (!$unread)
 0878      {
 0879          return;
 0880      }
 0881   
 0882      global $db, $user, $phpbb_container;
 0883   
 0884      $phpbb_notifications = $phpbb_container->get('notification_manager');
 0885   
 0886      $phpbb_notifications->mark_notifications_read('notification.type.pm', $msg_id, $user_id);
 0887   
 0888      $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
 0889          SET pm_unread = 0
 0890          WHERE msg_id = $msg_id
 0891              AND user_id = $user_id
 0892              AND folder_id = $folder_id";
 0893      $db->sql_query($sql);
 0894   
 0895      $sql = 'UPDATE ' . USERS_TABLE . "
 0896          SET user_unread_privmsg = user_unread_privmsg - 1
 0897          WHERE user_id = $user_id";
 0898      $db->sql_query($sql);
 0899   
 0900      if ($user->data['user_id'] == $user_id)
 0901      {
 0902          $user->data['user_unread_privmsg']--;
 0903   
 0904          // Try to cope with previous wrong conversions...
 0905          if ($user->data['user_unread_privmsg'] < 0)
 0906          {
 0907              $sql = 'UPDATE ' . USERS_TABLE . "
 0908                  SET user_unread_privmsg = 0
 0909                  WHERE user_id = $user_id";
 0910              $db->sql_query($sql);
 0911   
 0912              $user->data['user_unread_privmsg'] = 0;
 0913          }
 0914      }
 0915  }
 0916   
 0917  function mark_folder_read($user_id, $folder_id)
 0918  {
 0919      global $db;
 0920   
 0921      $sql = 'SELECT msg_id
 0922          FROM ' . PRIVMSGS_TO_TABLE . '
 0923          WHERE folder_id = ' . ((int) $folder_id) . '
 0924              AND user_id = ' . ((int) $user_id) . '
 0925              AND pm_unread = 1';
 0926      $result = $db->sql_query($sql);
 0927   
 0928      while ($row = $db->sql_fetchrow($result))
 0929      {
 0930          update_unread_status(true, $row['msg_id'], $user_id, $folder_id);
 0931      }
 0932      $db->sql_freeresult($result);
 0933  }
 0934   
 0935  /**
 0936  * Handle all actions possible with marked messages
 0937  */
 0938  function handle_mark_actions($user_id, $mark_action)
 0939  {
 0940      global $db, $user, $phpbb_root_path, $phpEx;
 0941   
 0942      $msg_ids        = request_var('marked_msg_id', array(0));
 0943      $cur_folder_id    = request_var('cur_folder_id', PRIVMSGS_NO_BOX);
 0944      $confirm        = (isset($_POST['confirm'])) ? true : false;
 0945   
 0946      if (!sizeof($msg_ids))
 0947      {
 0948          return false;
 0949      }
 0950   
 0951      switch ($mark_action)
 0952      {
 0953          case 'mark_important':
 0954   
 0955              $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
 0956                  SET pm_marked = 1 - pm_marked
 0957                  WHERE folder_id = $cur_folder_id
 0958                      AND user_id = $user_id
 0959                      AND " . $db->sql_in_set('msg_id', $msg_ids);
 0960              $db->sql_query($sql);
 0961   
 0962          break;
 0963   
 0964          case 'delete_marked':
 0965   
 0966              global $auth;
 0967   
 0968              if (!$auth->acl_get('u_pm_delete'))
 0969              {
 0970                  trigger_error('NO_AUTH_DELETE_MESSAGE');
 0971              }
 0972   
 0973              if (confirm_box(true))
 0974              {
 0975                  delete_pm($user_id, $msg_ids, $cur_folder_id);
 0976   
 0977                  $success_msg = (sizeof($msg_ids) == 1) ? 'MESSAGE_DELETED' : 'MESSAGES_DELETED';
 0978                  $redirect = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=' . $cur_folder_id);
 0979   
 0980                  meta_refresh(3, $redirect);
 0981                  trigger_error($user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_FOLDER'], '<a href="' . $redirect . '">', '</a>'));
 0982              }
 0983              else
 0984              {
 0985                  $s_hidden_fields = array(
 0986                      'cur_folder_id'    => $cur_folder_id,
 0987                      'mark_option'    => 'delete_marked',
 0988                      'submit_mark'    => true,
 0989                      'marked_msg_id'    => $msg_ids
 0990                  );
 0991   
 0992                  confirm_box(false, 'DELETE_MARKED_PM', build_hidden_fields($s_hidden_fields));
 0993              }
 0994   
 0995          break;
 0996   
 0997          default:
 0998              return false;
 0999      }
 1000   
 1001      return true;
 1002  }
 1003   
 1004  /**
 1005  * Delete PM(s)
 1006  */
 1007  function delete_pm($user_id, $msg_ids, $folder_id)
 1008  {
 1009      global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_dispatcher;
 1010   
 1011      $user_id    = (int) $user_id;
 1012      $folder_id    = (int) $folder_id;
 1013   
 1014      if (!$user_id)
 1015      {
 1016          return false;
 1017      }
 1018   
 1019      if (!is_array($msg_ids))
 1020      {
 1021          if (!$msg_ids)
 1022          {
 1023              return false;
 1024          }
 1025          $msg_ids = array($msg_ids);
 1026      }
 1027   
 1028      if (!sizeof($msg_ids))
 1029      {
 1030          return false;
 1031      }
 1032   
 1033      /**
 1034      * Get all info for PM(s) before they are deleted
 1035      *
 1036      * @event core.delete_pm_before
 1037      * @var    int    user_id     ID of the user requested the message delete
 1038      * @var    array    msg_ids    array of all messages to be deleted
 1039      * @var    int    folder_id    ID of the user folder where the messages are stored
 1040      * @since 3.1.0-b5
 1041      */
 1042      $vars = array('user_id', 'msg_ids', 'folder_id');
 1043      extract($phpbb_dispatcher->trigger_event('core.delete_pm_before', compact($vars)));
 1044   
 1045      // Get PM Information for later deleting
 1046      $sql = 'SELECT msg_id, pm_unread, pm_new
 1047          FROM ' . PRIVMSGS_TO_TABLE . '
 1048          WHERE ' . $db->sql_in_set('msg_id', array_map('intval', $msg_ids)) . "
 1049              AND folder_id = $folder_id
 1050              AND user_id = $user_id";
 1051      $result = $db->sql_query($sql);
 1052   
 1053      $delete_rows = array();
 1054      $num_unread = $num_new = $num_deleted = 0;
 1055      while ($row = $db->sql_fetchrow($result))
 1056      {
 1057          $num_unread += (int) $row['pm_unread'];
 1058          $num_new += (int) $row['pm_new'];
 1059   
 1060          $delete_rows[$row['msg_id']] = 1;
 1061      }
 1062      $db->sql_freeresult($result);
 1063      unset($msg_ids);
 1064   
 1065      if (!sizeof($delete_rows))
 1066      {
 1067          return false;
 1068      }
 1069   
 1070      $db->sql_transaction('begin');
 1071   
 1072      // if no one has read the message yet (meaning it is in users outbox)
 1073      // then mark the message as deleted...
 1074      if ($folder_id == PRIVMSGS_OUTBOX)
 1075      {
 1076          // Remove PM from Outbox
 1077          $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . "
 1078              WHERE user_id = $user_id AND folder_id = " . PRIVMSGS_OUTBOX . '
 1079                  AND ' . $db->sql_in_set('msg_id', array_keys($delete_rows));
 1080          $db->sql_query($sql);
 1081   
 1082          // Update PM Information for safety
 1083          $sql = 'UPDATE ' . PRIVMSGS_TABLE . " SET message_text = ''
 1084              WHERE " . $db->sql_in_set('msg_id', array_keys($delete_rows));
 1085          $db->sql_query($sql);
 1086   
 1087          // Set delete flag for those intended to receive the PM
 1088          // We do not remove the message actually, to retain some basic information (sent time for example)
 1089          $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 1090              SET pm_deleted = 1
 1091              WHERE ' . $db->sql_in_set('msg_id', array_keys($delete_rows));
 1092          $db->sql_query($sql);
 1093   
 1094          $num_deleted = $db->sql_affectedrows();
 1095      }
 1096      else
 1097      {
 1098          // Delete private message data
 1099          $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . "
 1100              WHERE user_id = $user_id
 1101                  AND folder_id = $folder_id
 1102                  AND " . $db->sql_in_set('msg_id', array_keys($delete_rows));
 1103          $db->sql_query($sql);
 1104          $num_deleted = $db->sql_affectedrows();
 1105      }
 1106   
 1107      // if folder id is user defined folder then decrease pm_count
 1108      if (!in_array($folder_id, array(PRIVMSGS_INBOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX, PRIVMSGS_NO_BOX)))
 1109      {
 1110          $sql = 'UPDATE ' . PRIVMSGS_FOLDER_TABLE . "
 1111              SET pm_count = pm_count - $num_deleted
 1112              WHERE folder_id = $folder_id";
 1113          $db->sql_query($sql);
 1114      }
 1115   
 1116      // Update unread and new status field
 1117      if ($num_unread || $num_new)
 1118      {
 1119          $set_sql = ($num_unread) ? 'user_unread_privmsg = user_unread_privmsg - ' . $num_unread : '';
 1120   
 1121          if ($num_new)
 1122          {
 1123              $set_sql .= ($set_sql != '') ? ', ' : '';
 1124              $set_sql .= 'user_new_privmsg = user_new_privmsg - ' . $num_new;
 1125          }
 1126   
 1127          $db->sql_query('UPDATE ' . USERS_TABLE . " SET $set_sql WHERE user_id = $user_id");
 1128   
 1129          $user->data['user_new_privmsg'] -= $num_new;
 1130          $user->data['user_unread_privmsg'] -= $num_unread;
 1131      }
 1132   
 1133      $phpbb_notifications = $phpbb_container->get('notification_manager');
 1134   
 1135      $phpbb_notifications->delete_notifications('notification.type.pm', array_keys($delete_rows));
 1136   
 1137      // Now we have to check which messages we can delete completely
 1138      $sql = 'SELECT msg_id
 1139          FROM ' . PRIVMSGS_TO_TABLE . '
 1140          WHERE ' . $db->sql_in_set('msg_id', array_keys($delete_rows));
 1141      $result = $db->sql_query($sql);
 1142   
 1143      while ($row = $db->sql_fetchrow($result))
 1144      {
 1145          unset($delete_rows[$row['msg_id']]);
 1146      }
 1147      $db->sql_freeresult($result);
 1148   
 1149      $delete_ids = array_keys($delete_rows);
 1150   
 1151      if (sizeof($delete_ids))
 1152      {
 1153          // Check if there are any attachments we need to remove
 1154          if (!function_exists('delete_attachments'))
 1155          {
 1156              include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
 1157          }
 1158   
 1159          delete_attachments('message', $delete_ids, false);
 1160   
 1161          $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
 1162              WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
 1163          $db->sql_query($sql);
 1164      }
 1165   
 1166      $db->sql_transaction('commit');
 1167   
 1168      return true;
 1169  }
 1170   
 1171  /**
 1172  * Delete all PM(s) for a given user and delete the ones without references
 1173  *
 1174  * @param    int        $user_id    ID of the user whose private messages we want to delete
 1175  *
 1176  * @return    boolean        False if there were no pms found, true otherwise.
 1177  */
 1178  function phpbb_delete_user_pms($user_id)
 1179  {
 1180      global $db, $user, $phpbb_root_path, $phpEx;
 1181   
 1182      $user_id = (int) $user_id;
 1183   
 1184      if (!$user_id)
 1185      {
 1186          return false;
 1187      }
 1188   
 1189      return phpbb_delete_users_pms(array($user_id));
 1190  }
 1191   
 1192  /**
 1193  * Delete all PM(s) for given users and delete the ones without references
 1194  *
 1195  * @param    array        $user_ids    IDs of the users whose private messages we want to delete
 1196  *
 1197  * @return    boolean        False if there were no pms found, true otherwise.
 1198  */
 1199  function phpbb_delete_users_pms($user_ids)
 1200  {
 1201      global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container;
 1202   
 1203      $user_id_sql = $db->sql_in_set('user_id', $user_ids);
 1204      $author_id_sql = $db->sql_in_set('author_id', $user_ids);
 1205   
 1206      // Get PM Information for later deleting
 1207      // The two queries where split, so we can use our indexes
 1208      $undelivered_msg = $delete_ids = array();
 1209   
 1210      // Part 1: get PMs the user received
 1211      $sql = 'SELECT msg_id
 1212          FROM ' . PRIVMSGS_TO_TABLE . '
 1213          WHERE ' . $user_id_sql;
 1214      $result = $db->sql_query($sql);
 1215   
 1216      while ($row = $db->sql_fetchrow($result))
 1217      {
 1218          $msg_id = (int) $row['msg_id'];
 1219          $delete_ids[$msg_id] = $msg_id;
 1220      }
 1221      $db->sql_freeresult($result);
 1222   
 1223      // Part 2: get PMs the users sent, but are yet to be received.
 1224      // We cannot simply delete them. First we have to check
 1225      // whether another user already received and read the message.
 1226      $sql = 'SELECT msg_id
 1227          FROM ' . PRIVMSGS_TO_TABLE . '
 1228          WHERE ' . $author_id_sql . '
 1229              AND folder_id = ' . PRIVMSGS_NO_BOX;
 1230      $result = $db->sql_query($sql);
 1231   
 1232      while ($row = $db->sql_fetchrow($result))
 1233      {
 1234          $msg_id = (int) $row['msg_id'];
 1235          $undelivered_msg[$msg_id] = $msg_id;
 1236      }
 1237      $db->sql_freeresult($result);
 1238   
 1239      if (empty($delete_ids) && empty($undelivered_msg))
 1240      {
 1241          return false;
 1242      }
 1243   
 1244      $db->sql_transaction('begin');
 1245   
 1246      $phpbb_notifications = $phpbb_container->get('notification_manager');
 1247   
 1248      if (!empty($undelivered_msg))
 1249      {
 1250          // A pm is delivered, if for any recipient the message was moved
 1251          // from their NO_BOX to another folder. We do not delete such
 1252          // messages, but only delete them for users, who have not yet
 1253          // received them.
 1254          $sql = 'SELECT msg_id
 1255              FROM ' . PRIVMSGS_TO_TABLE . '
 1256              WHERE ' . $author_id_sql . '
 1257                  AND folder_id <> ' . PRIVMSGS_NO_BOX . '
 1258                  AND folder_id <> ' . PRIVMSGS_OUTBOX . '
 1259                  AND folder_id <> ' . PRIVMSGS_SENTBOX;
 1260          $result = $db->sql_query($sql);
 1261   
 1262          $delivered_msg = array();
 1263          while ($row = $db->sql_fetchrow($result))
 1264          {
 1265              $msg_id = (int) $row['msg_id'];
 1266              $delivered_msg[$msg_id] = $msg_id;
 1267              unset($undelivered_msg[$msg_id]);
 1268          }
 1269          $db->sql_freeresult($result);
 1270   
 1271          $undelivered_user = array();
 1272   
 1273          // Count the messages we delete, so we can correct the user pm data
 1274          $sql = 'SELECT user_id, COUNT(msg_id) as num_undelivered_privmsgs
 1275              FROM ' . PRIVMSGS_TO_TABLE . '
 1276              WHERE ' . $author_id_sql . '
 1277                  AND folder_id = ' . PRIVMSGS_NO_BOX . '
 1278                      AND ' . $db->sql_in_set('msg_id', array_merge($undelivered_msg, $delivered_msg)) . '
 1279              GROUP BY user_id';
 1280          $result = $db->sql_query($sql);
 1281   
 1282          while ($row = $db->sql_fetchrow($result))
 1283          {
 1284              $num_pms = (int) $row['num_undelivered_privmsgs'];
 1285              $undelivered_user[$num_pms][] = (int) $row['user_id'];
 1286   
 1287              if (sizeof($undelivered_user[$num_pms]) > 50)
 1288              {
 1289                  // If there are too many users affected the query might get
 1290                  // too long, so we update the value for the first bunch here.
 1291                  $sql = 'UPDATE ' . USERS_TABLE . '
 1292                      SET user_new_privmsg = user_new_privmsg - ' . $num_pms . ',
 1293                          user_unread_privmsg = user_unread_privmsg - ' . $num_pms . '
 1294                      WHERE ' . $db->sql_in_set('user_id', $undelivered_user[$num_pms]);
 1295                  $db->sql_query($sql);
 1296                  unset($undelivered_user[$num_pms]);
 1297              }
 1298          }
 1299          $db->sql_freeresult($result);
 1300   
 1301          foreach ($undelivered_user as $num_pms => $undelivered_user_set)
 1302          {
 1303              $sql = 'UPDATE ' . USERS_TABLE . '
 1304                  SET user_new_privmsg = user_new_privmsg - ' . $num_pms . ',
 1305                      user_unread_privmsg = user_unread_privmsg - ' . $num_pms . '
 1306                  WHERE ' . $db->sql_in_set('user_id', $undelivered_user_set);
 1307              $db->sql_query($sql);
 1308          }
 1309   
 1310          if (!empty($delivered_msg))
 1311          {
 1312              $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . '
 1313                  WHERE folder_id = ' . PRIVMSGS_NO_BOX . '
 1314                      AND ' . $db->sql_in_set('msg_id', $delivered_msg);
 1315              $db->sql_query($sql);
 1316   
 1317              $phpbb_notifications->delete_notifications('notification.type.pm', $delivered_msg);
 1318          }
 1319   
 1320          if (!empty($undelivered_msg))
 1321          {
 1322              $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . '
 1323                  WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg);
 1324              $db->sql_query($sql);
 1325   
 1326              $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
 1327                  WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg);
 1328              $db->sql_query($sql);
 1329   
 1330              $phpbb_notifications->delete_notifications('notification.type.pm', $undelivered_msg);
 1331          }
 1332      }
 1333   
 1334      // Reset the user's pm count to 0
 1335      $sql = 'UPDATE ' . USERS_TABLE . '
 1336          SET user_new_privmsg = 0,
 1337              user_unread_privmsg = 0
 1338          WHERE ' . $user_id_sql;
 1339      $db->sql_query($sql);
 1340   
 1341      // Delete private message data of the user
 1342      $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . '
 1343          WHERE ' . $user_id_sql;
 1344      $db->sql_query($sql);
 1345   
 1346      if (!empty($delete_ids))
 1347      {
 1348          // Now we have to check which messages we can delete completely
 1349          $sql = 'SELECT msg_id
 1350              FROM ' . PRIVMSGS_TO_TABLE . '
 1351              WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
 1352          $result = $db->sql_query($sql);
 1353   
 1354          while ($row = $db->sql_fetchrow($result))
 1355          {
 1356              unset($delete_ids[$row['msg_id']]);
 1357          }
 1358          $db->sql_freeresult($result);
 1359   
 1360          if (!empty($delete_ids))
 1361          {
 1362              // Check if there are any attachments we need to remove
 1363              if (!function_exists('delete_attachments'))
 1364              {
 1365                  include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
 1366              }
 1367   
 1368              delete_attachments('message', $delete_ids, false);
 1369   
 1370              $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
 1371                  WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
 1372              $db->sql_query($sql);
 1373   
 1374              $phpbb_notifications->delete_notifications('notification.type.pm', $delete_ids);
 1375          }
 1376      }
 1377   
 1378      // Set the remaining author id to anonymous
 1379      // This way users are still able to read messages from users being removed
 1380      $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 1381          SET author_id = ' . ANONYMOUS . '
 1382          WHERE ' . $author_id_sql;
 1383      $db->sql_query($sql);
 1384   
 1385      $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
 1386          SET author_id = ' . ANONYMOUS . '
 1387          WHERE ' . $author_id_sql;
 1388      $db->sql_query($sql);
 1389   
 1390      $db->sql_transaction('commit');
 1391   
 1392      return true;
 1393  }
 1394   
 1395  /**
 1396  * Rebuild message header
 1397  */
 1398  function rebuild_header($check_ary)
 1399  {
 1400      global $db;
 1401   
 1402      $address = array();
 1403   
 1404      foreach ($check_ary as $check_type => $address_field)
 1405      {
 1406          // Split Addresses into users and groups
 1407          preg_match_all('/:?(u|g)_([0-9]+):?/', $address_field, $match);
 1408   
 1409          $u = $g = array();
 1410          foreach ($match[1] as $id => $type)
 1411          {
 1412              ${$type}[] = (int) $match[2][$id];
 1413          }
 1414   
 1415          $_types = array('u', 'g');
 1416          foreach ($_types as $type)
 1417          {
 1418              if (sizeof($$type))
 1419              {
 1420                  foreach ($$type as $id)
 1421                  {
 1422                      $address[$type][$id] = $check_type;
 1423                  }
 1424              }
 1425          }
 1426      }
 1427   
 1428      return $address;
 1429  }
 1430   
 1431  /**
 1432  * Print out/assign recipient information
 1433  */
 1434  function write_pm_addresses($check_ary, $author_id, $plaintext = false)
 1435  {
 1436      global $db, $user, $template, $phpbb_root_path, $phpEx;
 1437   
 1438      $addresses = array();
 1439   
 1440      foreach ($check_ary as $check_type => $address_field)
 1441      {
 1442          if (!is_array($address_field))
 1443          {
 1444              // Split Addresses into users and groups
 1445              preg_match_all('/:?(u|g)_([0-9]+):?/', $address_field, $match);
 1446   
 1447              $u = $g = array();
 1448              foreach ($match[1] as $id => $type)
 1449              {
 1450                  ${$type}[] = (int) $match[2][$id];
 1451              }
 1452          }
 1453          else
 1454          {
 1455              $u = $address_field['u'];
 1456              $g = $address_field['g'];
 1457          }
 1458   
 1459          $address = array();
 1460          if (sizeof($u))
 1461          {
 1462              $sql = 'SELECT user_id, username, user_colour
 1463                  FROM ' . USERS_TABLE . '
 1464                  WHERE ' . $db->sql_in_set('user_id', $u);
 1465              $result = $db->sql_query($sql);
 1466   
 1467              while ($row = $db->sql_fetchrow($result))
 1468              {
 1469                  if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
 1470                  {
 1471                      if ($plaintext)
 1472                      {
 1473                          $address[] = $row['username'];
 1474                      }
 1475                      else
 1476                      {
 1477                          $address['user'][$row['user_id']] = array('name' => $row['username'], 'colour' => $row['user_colour']);
 1478                      }
 1479                  }
 1480              }
 1481              $db->sql_freeresult($result);
 1482          }
 1483   
 1484          if (sizeof($g))
 1485          {
 1486              if ($plaintext)
 1487              {
 1488                  $sql = 'SELECT group_name, group_type
 1489                      FROM ' . GROUPS_TABLE . '
 1490                          WHERE ' . $db->sql_in_set('group_id', $g);
 1491                  $result = $db->sql_query($sql);
 1492   
 1493                  while ($row = $db->sql_fetchrow($result))
 1494                  {
 1495                      if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
 1496                      {
 1497                          $address[] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
 1498                      }
 1499                  }
 1500                  $db->sql_freeresult($result);
 1501              }
 1502              else
 1503              {
 1504                  $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_type, ug.user_id
 1505                      FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug
 1506                          WHERE ' . $db->sql_in_set('g.group_id', $g) . '
 1507                          AND g.group_id = ug.group_id
 1508                          AND ug.user_pending = 0';
 1509                  $result = $db->sql_query($sql);
 1510   
 1511                  while ($row = $db->sql_fetchrow($result))
 1512                  {
 1513                      if (!isset($address['group'][$row['group_id']]))
 1514                      {
 1515                          if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
 1516                          {
 1517                              $row['group_name'] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
 1518                              $address['group'][$row['group_id']] = array('name' => $row['group_name'], 'colour' => $row['group_colour']);
 1519                          }
 1520                      }
 1521   
 1522                      if (isset($address['user'][$row['user_id']]))
 1523                      {
 1524                          $address['user'][$row['user_id']]['in_group'] = $row['group_id'];
 1525                      }
 1526                  }
 1527                  $db->sql_freeresult($result);
 1528              }
 1529          }
 1530   
 1531          if (sizeof($address) && !$plaintext)
 1532          {
 1533              $template->assign_var('S_' . strtoupper($check_type) . '_RECIPIENT', true);
 1534   
 1535              foreach ($address as $type => $adr_ary)
 1536              {
 1537                  foreach ($adr_ary as $id => $row)
 1538                  {
 1539                      $tpl_ary = array(
 1540                          'IS_GROUP'    => ($type == 'group') ? true : false,
 1541                          'IS_USER'    => ($type == 'user') ? true : false,
 1542                          'UG_ID'        => $id,
 1543                          'NAME'        => $row['name'],
 1544                          'COLOUR'    => ($row['colour']) ? '#' . $row['colour'] : '',
 1545                          'TYPE'        => $type,
 1546                      );
 1547   
 1548                      if ($type == 'user')
 1549                      {
 1550                          $tpl_ary = array_merge($tpl_ary, array(
 1551                              'U_VIEW'        => get_username_string('profile', $id, $row['name'], $row['colour']),
 1552                              'NAME_FULL'        => get_username_string('full', $id, $row['name'], $row['colour']),
 1553                          ));
 1554                      }
 1555                      else
 1556                      {
 1557                          $tpl_ary = array_merge($tpl_ary, array(
 1558                              'U_VIEW'        => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&amp;g=' . $id),
 1559                          ));
 1560                      }
 1561   
 1562                      $template->assign_block_vars($check_type . '_recipient', $tpl_ary);
 1563                  }
 1564              }
 1565          }
 1566   
 1567          $addresses[$check_type] = $address;
 1568      }
 1569   
 1570      return $addresses;
 1571  }
 1572   
 1573  /**
 1574  * Get folder status
 1575  */
 1576  function get_folder_status($folder_id, $folder)
 1577  {
 1578      global $db, $user, $config;
 1579   
 1580      if (isset($folder[$folder_id]))
 1581      {
 1582          $folder = $folder[$folder_id];
 1583      }
 1584      else
 1585      {
 1586          return false;
 1587      }
 1588   
 1589      $return = array(
 1590          'folder_name'    => $folder['folder_name'],
 1591          'cur'            => $folder['num_messages'],
 1592          'remaining'        => ($user->data['message_limit']) ? $user->data['message_limit'] - $folder['num_messages'] : 0,
 1593          'max'            => $user->data['message_limit'],
 1594          'percent'        => ($user->data['message_limit']) ? (($user->data['message_limit'] > 0) ? floor(($folder['num_messages'] / $user->data['message_limit']) * 100) : 100) : 0,
 1595      );
 1596   
 1597      $return['message']    = $user->lang('FOLDER_STATUS_MSG', $user->lang('MESSAGES_COUNT', (int) $return['max']), $return['cur'], $return['percent']);
 1598   
 1599      return $return;
 1600  }
 1601   
 1602  //
 1603  // COMPOSE MESSAGES
 1604  //
 1605   
 1606  /**
 1607  * Submit PM
 1608  */
 1609  function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
 1610  {
 1611      global $db, $auth, $config, $phpEx, $template, $user, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher;
 1612   
 1613      // We do not handle erasing pms here
 1614      if ($mode == 'delete')
 1615      {
 1616          return false;
 1617      }
 1618   
 1619      $current_time = time();
 1620   
 1621      /**
 1622      * Get all parts of the PM that are to be submited to the DB.
 1623      *
 1624      * @event core.submit_pm_before
 1625      * @var    string    mode    PM Post mode - post|reply|quote|quotepost|forward|edit
 1626      * @var    string    subject    Subject of the private message
 1627      * @var    array    data    The whole row data of the PM.
 1628      * @since 3.1.0-b3
 1629      */
 1630      $vars = array('mode', 'subject', 'data');
 1631      extract($phpbb_dispatcher->trigger_event('core.submit_pm_before', compact($vars)));
 1632   
 1633      // Collect some basic information about which tables and which rows to update/insert
 1634      $sql_data = array();
 1635      $root_level = 0;
 1636   
 1637      // Recipient Information
 1638      $recipients = $to = $bcc = array();
 1639   
 1640      if ($mode != 'edit')
 1641      {
 1642          // Build Recipient List
 1643          // u|g => array($user_id => 'to'|'bcc')
 1644          $_types = array('u', 'g');
 1645          foreach ($_types as $ug_type)
 1646          {
 1647              if (isset($data['address_list'][$ug_type]) && sizeof($data['address_list'][$ug_type]))
 1648              {
 1649                  foreach ($data['address_list'][$ug_type] as $id => $field)
 1650                  {
 1651                      $id = (int) $id;
 1652   
 1653                      // Do not rely on the address list being "valid"
 1654                      if (!$id || ($ug_type == 'u' && $id == ANONYMOUS))
 1655                      {
 1656                          continue;
 1657                      }
 1658   
 1659                      $field = ($field == 'to') ? 'to' : 'bcc';
 1660                      if ($ug_type == 'u')
 1661                      {
 1662                          $recipients[$id] = $field;
 1663                      }
 1664                      ${$field}[] = $ug_type . '_' . $id;
 1665                  }
 1666              }
 1667          }
 1668   
 1669          if (isset($data['address_list']['g']) && sizeof($data['address_list']['g']))
 1670          {
 1671              // We need to check the PM status of group members (do they want to receive PM's?)
 1672              // Only check if not a moderator or admin, since they are allowed to override this user setting
 1673              $sql_allow_pm = (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_')) ? ' AND u.user_allow_pm = 1' : '';
 1674   
 1675              $sql = 'SELECT u.user_type, ug.group_id, ug.user_id
 1676                  FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . ' ug
 1677                  WHERE ' . $db->sql_in_set('ug.group_id', array_keys($data['address_list']['g'])) . '
 1678                      AND ug.user_pending = 0
 1679                      AND u.user_id = ug.user_id
 1680                      AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')' .
 1681                      $sql_allow_pm;
 1682              $result = $db->sql_query($sql);
 1683   
 1684              while ($row = $db->sql_fetchrow($result))
 1685              {
 1686                  $field = ($data['address_list']['g'][$row['group_id']] == 'to') ? 'to' : 'bcc';
 1687                  $recipients[$row['user_id']] = $field;
 1688              }
 1689              $db->sql_freeresult($result);
 1690          }
 1691   
 1692          if (!sizeof($recipients))
 1693          {
 1694              trigger_error('NO_RECIPIENT');
 1695          }
 1696      }
 1697   
 1698      // First of all make sure the subject are having the correct length.
 1699      $subject = truncate_string($subject);
 1700   
 1701      $db->sql_transaction('begin');
 1702   
 1703      $sql = '';
 1704   
 1705      switch ($mode)
 1706      {
 1707          case 'reply':
 1708          case 'quote':
 1709              $root_level = ($data['reply_from_root_level']) ? $data['reply_from_root_level'] : $data['reply_from_msg_id'];
 1710   
 1711              // Set message_replied switch for this user
 1712              $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
 1713                  SET pm_replied = 1
 1714                  WHERE user_id = ' . $data['from_user_id'] . '
 1715                      AND msg_id = ' . $data['reply_from_msg_id'];
 1716   
 1717          // no break
 1718   
 1719          case 'forward':
 1720          case 'post':
 1721          case 'quotepost':
 1722              $sql_data = array(
 1723                  'root_level'        => $root_level,
 1724                  'author_id'            => $data['from_user_id'],
 1725                  'icon_id'            => $data['icon_id'],
 1726                  'author_ip'            => $data['from_user_ip'],
 1727                  'message_time'        => $current_time,
 1728                  'enable_bbcode'        => $data['enable_bbcode'],
 1729                  'enable_smilies'    => $data['enable_smilies'],
 1730                  'enable_magic_url'    => $data['enable_urls'],
 1731                  'enable_sig'        => $data['enable_sig'],
 1732                  'message_subject'    => $subject,
 1733                  'message_text'        => $data['message'],
 1734                  'message_attachment'=> (!empty($data['attachment_data'])) ? 1 : 0,
 1735                  'bbcode_bitfield'    => $data['bbcode_bitfield'],
 1736                  'bbcode_uid'        => $data['bbcode_uid'],
 1737                  'to_address'        => implode(':', $to),
 1738                  'bcc_address'        => implode(':', $bcc),
 1739                  'message_reported'    => 0,
 1740              );
 1741          break;
 1742   
 1743          case 'edit':
 1744              $sql_data = array(
 1745                  'icon_id'            => $data['icon_id'],
 1746                  'message_edit_time'    => $current_time,
 1747                  'enable_bbcode'        => $data['enable_bbcode'],
 1748                  'enable_smilies'    => $data['enable_smilies'],
 1749                  'enable_magic_url'    => $data['enable_urls'],
 1750                  'enable_sig'        => $data['enable_sig'],
 1751                  'message_subject'    => $subject,
 1752                  'message_text'        => $data['message'],
 1753                  'message_attachment'=> (!empty($data['attachment_data'])) ? 1 : 0,
 1754                  'bbcode_bitfield'    => $data['bbcode_bitfield'],
 1755                  'bbcode_uid'        => $data['bbcode_uid']
 1756              );
 1757          break;
 1758      }
 1759   
 1760      if (sizeof($sql_data))
 1761      {
 1762          $query = '';
 1763   
 1764          if ($mode == 'post' || $mode == 'reply' || $mode == 'quote' || $mode == 'quotepost' || $mode == 'forward')
 1765          {
 1766              $db->sql_query('INSERT INTO ' . PRIVMSGS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_data));
 1767              $data['msg_id'] = $db->sql_nextid();
 1768          }
 1769          else if ($mode == 'edit')
 1770          {
 1771              $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
 1772                  SET message_edit_count = message_edit_count + 1, ' . $db->sql_build_array('UPDATE', $sql_data) . '
 1773                  WHERE msg_id = ' . $data['msg_id'];
 1774              $db->sql_query($sql);
 1775          }
 1776      }
 1777   
 1778      if ($mode != 'edit')
 1779      {
 1780          if ($sql)
 1781          {
 1782              $db->sql_query($sql);
 1783          }
 1784          unset($sql);
 1785   
 1786          $sql_ary = array();
 1787          foreach ($recipients as $user_id => $type)
 1788          {
 1789              $sql_ary[] = array(
 1790                  'msg_id'        => (int) $data['msg_id'],
 1791                  'user_id'        => (int) $user_id,
 1792                  'author_id'        => (int) $data['from_user_id'],
 1793                  'folder_id'        => PRIVMSGS_NO_BOX,
 1794                  'pm_new'        => 1,
 1795                  'pm_unread'        => 1,
 1796                  'pm_forwarded'    => ($mode == 'forward') ? 1 : 0
 1797              );
 1798          }
 1799   
 1800          $db->sql_multi_insert(PRIVMSGS_TO_TABLE, $sql_ary);
 1801   
 1802          $sql = 'UPDATE ' . USERS_TABLE . '
 1803              SET user_new_privmsg = user_new_privmsg + 1, user_unread_privmsg = user_unread_privmsg + 1, user_last_privmsg = ' . time() . '
 1804              WHERE ' . $db->sql_in_set('user_id', array_keys($recipients));
 1805          $db->sql_query($sql);
 1806   
 1807          // Put PM into outbox
 1808          if ($put_in_outbox)
 1809          {
 1810              $db->sql_query('INSERT INTO ' . PRIVMSGS_TO_TABLE . ' ' . $db->sql_build_array('INSERT', array(
 1811                  'msg_id'        => (int) $data['msg_id'],
 1812                  'user_id'        => (int) $data['from_user_id'],
 1813                  'author_id'        => (int) $data['from_user_id'],
 1814                  'folder_id'        => PRIVMSGS_OUTBOX,
 1815                  'pm_new'        => 0,
 1816                  'pm_unread'        => 0,
 1817                  'pm_forwarded'    => ($mode == 'forward') ? 1 : 0))
 1818              );
 1819          }
 1820      }
 1821   
 1822      // Set user last post time
 1823      if ($mode == 'reply' || $mode == 'quote' || $mode == 'quotepost' || $mode == 'forward' || $mode == 'post')
 1824      {
 1825          $sql = 'UPDATE ' . USERS_TABLE . "
 1826              SET user_lastpost_time = $current_time
 1827              WHERE user_id = " . $data['from_user_id'];
 1828          $db->sql_query($sql);
 1829      }
 1830   
 1831      // Submit Attachments
 1832      if (!empty($data['attachment_data']) && $data['msg_id'] && in_array($mode, array('post', 'reply', 'quote', 'quotepost', 'edit', 'forward')))
 1833      {
 1834          $space_taken = $files_added = 0;
 1835          $orphan_rows = array();
 1836   
 1837          foreach ($data['attachment_data'] as $pos => $attach_row)
 1838          {
 1839              $orphan_rows[(int) $attach_row['attach_id']] = array();
 1840          }
 1841   
 1842          if (sizeof($orphan_rows))
 1843          {
 1844              $sql = 'SELECT attach_id, filesize, physical_filename
 1845                  FROM ' . ATTACHMENTS_TABLE . '
 1846                  WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan_rows)) . '
 1847                      AND in_message = 1
 1848                      AND is_orphan = 1
 1849                      AND poster_id = ' . $user->data['user_id'];
 1850              $result = $db->sql_query($sql);
 1851   
 1852              $orphan_rows = array();
 1853              while ($row = $db->sql_fetchrow($result))
 1854              {
 1855                  $orphan_rows[$row['attach_id']] = $row;
 1856              }
 1857              $db->sql_freeresult($result);
 1858          }
 1859   
 1860          foreach ($data['attachment_data'] as $pos => $attach_row)
 1861          {
 1862              if ($attach_row['is_orphan'] && !isset($orphan_rows[$attach_row['attach_id']]))
 1863              {
 1864                  continue;
 1865              }
 1866   
 1867              if (!$attach_row['is_orphan'])
 1868              {
 1869                  // update entry in db if attachment already stored in db and filespace
 1870                  $sql = 'UPDATE ' . ATTACHMENTS_TABLE . "
 1871                      SET attach_comment = '" . $db->sql_escape($attach_row['attach_comment']) . "'
 1872                      WHERE attach_id = " . (int) $attach_row['attach_id'] . '
 1873                          AND is_orphan = 0';
 1874                  $db->sql_query($sql);
 1875              }
 1876              else
 1877              {
 1878                  // insert attachment into db
 1879                  if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . utf8_basename($orphan_rows[$attach_row['attach_id']]['physical_filename'])))
 1880                  {
 1881                      continue;
 1882                  }
 1883   
 1884                  $space_taken += $orphan_rows[$attach_row['attach_id']]['filesize'];
 1885                  $files_added++;
 1886   
 1887                  $attach_sql = array(
 1888                      'post_msg_id'        => $data['msg_id'],
 1889                      'topic_id'            => 0,
 1890                      'is_orphan'            => 0,
 1891                      'poster_id'            => $data['from_user_id'],
 1892                      'attach_comment'    => $attach_row['attach_comment'],
 1893                  );
 1894   
 1895                  $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $attach_sql) . '
 1896                      WHERE attach_id = ' . $attach_row['attach_id'] . '
 1897                          AND is_orphan = 1
 1898                          AND poster_id = ' . $user->data['user_id'];
 1899                  $db->sql_query($sql);
 1900              }
 1901          }
 1902   
 1903          if ($space_taken && $files_added)
 1904          {
 1905              set_config_count('upload_dir_size', $space_taken, true);
 1906              set_config_count('num_files', $files_added, true);
 1907          }
 1908      }
 1909   
 1910      // Delete draft if post was loaded...
 1911      $draft_id = request_var('draft_loaded', 0);
 1912      if ($draft_id)
 1913      {
 1914          $sql = 'DELETE FROM ' . DRAFTS_TABLE . "
 1915              WHERE draft_id = $draft_id
 1916                  AND user_id = " . $data['from_user_id'];
 1917          $db->sql_query($sql);
 1918      }
 1919   
 1920      $db->sql_transaction('commit');
 1921   
 1922      // Send Notifications
 1923      $pm_data = array_merge($data, array(
 1924          'message_subject'        => $subject,
 1925          'recipients'            => $recipients,
 1926      ));
 1927   
 1928      $phpbb_notifications = $phpbb_container->get('notification_manager');
 1929   
 1930      if ($mode == 'edit')
 1931      {
 1932          $phpbb_notifications->update_notifications('notification.type.pm', $pm_data);
 1933      }
 1934      else
 1935      {
 1936          $phpbb_notifications->add_notifications('notification.type.pm', $pm_data);
 1937      }
 1938   
 1939      /**
 1940      * Get PM message ID after submission to DB
 1941      *
 1942      * @event core.submit_pm_after
 1943      * @var    string    mode    PM Post mode - post|reply|quote|quotepost|forward|edit
 1944      * @var    string    subject    Subject of the private message
 1945      * @var    array    data    The whole row data of the PM.
 1946      * @var    array    pm_data    The data sent to notification class
 1947      * @since 3.1.0-b5
 1948      */
 1949      $vars = array('mode', 'subject', 'data', 'pm_data');
 1950      extract($phpbb_dispatcher->trigger_event('core.submit_pm_after', compact($vars)));
 1951   
 1952      return $data['msg_id'];
 1953  }
 1954   
 1955  /**
 1956  * Display Message History
 1957  */
 1958  function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode = false)
 1959  {
 1960      global $db, $user, $config, $template, $phpbb_root_path, $phpEx, $auth, $bbcode;
 1961   
 1962      // Select all receipts and the author from the pm we currently view, to only display their pm-history
 1963      $sql = 'SELECT author_id, user_id
 1964          FROM ' . PRIVMSGS_TO_TABLE . "
 1965          WHERE msg_id = $msg_id
 1966              AND folder_id <> " . PRIVMSGS_HOLD_BOX;
 1967      $result = $db->sql_query($sql);
 1968   
 1969      $recipients = array();
 1970      while ($row = $db->sql_fetchrow($result))
 1971      {
 1972          $recipients[] = (int) $row['user_id'];
 1973          $recipients[] = (int) $row['author_id'];
 1974      }
 1975      $db->sql_freeresult($result);
 1976      $recipients = array_unique($recipients);
 1977   
 1978      // Get History Messages (could be newer)
 1979      $sql = 'SELECT t.*, p.*, u.*
 1980          FROM ' . PRIVMSGS_TABLE . ' p, ' . PRIVMSGS_TO_TABLE . ' t, ' . USERS_TABLE . ' u
 1981          WHERE t.msg_id = p.msg_id
 1982              AND p.author_id = u.user_id
 1983              AND t.folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
 1984              AND ' . $db->sql_in_set('t.author_id', $recipients, false, true) . "
 1985              AND t.user_id = $user_id";
 1986   
 1987      // We no longer need those.
 1988      unset($recipients);
 1989   
 1990      if (!$message_row['root_level'])
 1991      {
 1992          $sql .= " AND (p.root_level = $msg_id OR (p.root_level = 0 AND p.msg_id = $msg_id))";
 1993      }
 1994      else
 1995      {
 1996          $sql .= " AND (p.root_level = " . $message_row['root_level'] . ' OR p.msg_id = ' . $message_row['root_level'] . ')';
 1997      }
 1998      $sql .= ' ORDER BY p.message_time DESC';
 1999   
 2000      $result = $db->sql_query($sql);
 2001      $row = $db->sql_fetchrow($result);
 2002   
 2003      if (!$row)
 2004      {
 2005          $db->sql_freeresult($result);
 2006          return false;
 2007      }
 2008   
 2009      $title = $row['message_subject'];
 2010   
 2011      $rowset = array();
 2012      $bbcode_bitfield = '';
 2013      $folder_url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm') . '&amp;folder=';
 2014   
 2015      do
 2016      {
 2017          $folder_id = (int) $row['folder_id'];
 2018   
 2019          $row['folder'][] = (isset($folder[$folder_id])) ? '<a href="' . $folder_url . $folder_id . '">' . $folder[$folder_id]['folder_name'] . '</a>' : $user->lang['UNKNOWN_FOLDER'];
 2020   
 2021          if (isset($rowset[$row['msg_id']]))
 2022          {
 2023              $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'];
 2024          }
 2025          else
 2026          {
 2027              $rowset[$row['msg_id']] = $row;
 2028              $bbcode_bitfield = $bbcode_bitfield | base64_decode($row['bbcode_bitfield']);
 2029          }
 2030      }
 2031      while ($row = $db->sql_fetchrow($result));
 2032      $db->sql_freeresult($result);
 2033   
 2034      if (sizeof($rowset) == 1 && !$in_post_mode)
 2035      {
 2036          return false;
 2037      }
 2038   
 2039      // Instantiate BBCode class
 2040      if ((empty($bbcode) || $bbcode === false) && $bbcode_bitfield !== '')
 2041      {
 2042          if (!class_exists('bbcode'))
 2043          {
 2044              include($phpbb_root_path . 'includes/bbcode.' . $phpEx);
 2045          }
 2046          $bbcode = new bbcode(base64_encode($bbcode_bitfield));
 2047      }
 2048   
 2049      $title = censor_text($title);
 2050   
 2051      $url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm');
 2052      $next_history_pm = $previous_history_pm = $prev_id = 0;
 2053   
 2054      // Re-order rowset to be able to get the next/prev message rows...
 2055      $rowset = array_values($rowset);
 2056   
 2057      for ($i = 0, $size = sizeof($rowset); $i < $size; $i++)
 2058      {
 2059          $row = &$rowset[$i];
 2060          $id = (int) $row['msg_id'];
 2061   
 2062          $author_id    = $row['author_id'];
 2063          $folder_id    = (int) $row['folder_id'];
 2064   
 2065          $subject    = $row['message_subject'];
 2066          $message    = $row['message_text'];
 2067   
 2068          $message = censor_text($message);
 2069   
 2070          $decoded_message = false;
 2071   
 2072          if ($in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS)
 2073          {
 2074              $decoded_message = $message;
 2075              decode_message($decoded_message, $row['bbcode_uid']);
 2076   
 2077              $decoded_message = bbcode_nl2br($decoded_message);
 2078          }
 2079   
 2080          $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0);
 2081          $parse_flags |= ($row['enable_smilies'] ? OPTION_FLAG_SMILIES : 0);
 2082   
 2083          $message = generate_text_for_display($message, $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false);
 2084   
 2085          $subject = censor_text($subject);
 2086   
 2087          if ($id == $msg_id)
 2088          {
 2089              $next_history_pm = (isset($rowset[$i + 1])) ? (int) $rowset[$i + 1]['msg_id'] : 0;
 2090              $previous_history_pm = $prev_id;
 2091          }
 2092   
 2093          $template->assign_block_vars('history_row', array(
 2094              'MESSAGE_AUTHOR_QUOTE'        => (($decoded_message) ? addslashes(get_username_string('username', $author_id, $row['username'], $row['user_colour'], $row['username'])) : ''),
 2095              'MESSAGE_AUTHOR_FULL'        => get_username_string('full', $author_id, $row['username'], $row['user_colour'], $row['username']),
 2096              'MESSAGE_AUTHOR_COLOUR'        => get_username_string('colour', $author_id, $row['username'], $row['user_colour'], $row['username']),
 2097              'MESSAGE_AUTHOR'            => get_username_string('username', $author_id, $row['username'], $row['user_colour'], $row['username']),
 2098              'U_MESSAGE_AUTHOR'            => get_username_string('profile', $author_id, $row['username'], $row['user_colour'], $row['username']),
 2099   
 2100              'SUBJECT'            => $subject,
 2101              'SENT_DATE'            => $user->format_date($row['message_time']),
 2102              'MESSAGE'            => $message,
 2103              'FOLDER'            => implode($user->lang['COMMA_SEPARATOR'], $row['folder']),
 2104              'DECODED_MESSAGE'    => $decoded_message,
 2105   
 2106              'S_CURRENT_MSG'        => ($row['msg_id'] == $msg_id),
 2107              'S_AUTHOR_DELETED'    => ($author_id == ANONYMOUS) ? true : false,
 2108              'S_IN_POST_MODE'    => $in_post_mode,
 2109   
 2110              'MSG_ID'            => $row['msg_id'],
 2111              'U_VIEW_MESSAGE'    => "$url&amp;f=$folder_id&amp;p=" . $row['msg_id'],
 2112              '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'] : '',
 2113              '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'] : '')
 2114          );
 2115          unset($rowset[$i]);
 2116          $prev_id = $id;
 2117      }
 2118   
 2119      $template->assign_vars(array(
 2120          'QUOTE_IMG'            => $user->img('icon_post_quote', $user->lang['REPLY_WITH_QUOTE']),
 2121          'HISTORY_TITLE'        => $title,
 2122   
 2123          'U_VIEW_NEXT_HISTORY'        => ($next_history_pm) ? "$url&amp;p=" . $next_history_pm : '',
 2124          'U_VIEW_PREVIOUS_HISTORY'    => ($previous_history_pm) ? "$url&amp;p=" . $previous_history_pm : '',
 2125      ));
 2126   
 2127      return true;
 2128  }
 2129   
 2130  /**
 2131  * Set correct users max messages in PM folder.
 2132  * If several group memberships define different amount of messages, the highest will be chosen.
 2133  */
 2134  function set_user_message_limit()
 2135  {
 2136      global $user, $db, $config;
 2137   
 2138      // Get maximum about from user memberships - if it is 0, there is no limit set and we use the maximum value within the config.
 2139      $sql = 'SELECT MAX(g.group_message_limit) as max_message_limit
 2140          FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug
 2141          WHERE ug.user_id = ' . $user->data['user_id'] . '
 2142              AND ug.user_pending = 0
 2143              AND ug.group_id = g.group_id';
 2144      $result = $db->sql_query($sql);
 2145      $message_limit = (int) $db->sql_fetchfield('max_message_limit');
 2146      $db->sql_freeresult($result);
 2147   
 2148      $user->data['message_limit'] = (!$message_limit) ? $config['pm_max_msgs'] : $message_limit;
 2149  }
 2150   
 2151  /**
 2152  * Generates an array of coloured recipient names from a list of PMs - (groups & users)
 2153  *
 2154  * @param    array    $pm_by_id    An array of rows from PRIVMSGS_TABLE, keys are the msg_ids.
 2155  *
 2156  * @return    array                2D Array: array(msg_id => array('username or group string', ...), ...)
 2157  *                                Usernames are generated with {@link get_username_string get_username_string}
 2158  *                                Groups are coloured and have a link to the membership page
 2159  */
 2160  function get_recipient_strings($pm_by_id)
 2161  {
 2162      global $db, $phpbb_root_path, $phpEx, $user;
 2163   
 2164      $address_list = $recipient_list = $address = array();
 2165   
 2166      $_types = array('u', 'g');
 2167   
 2168      foreach ($pm_by_id as $message_id => $row)
 2169      {
 2170          $address[$message_id] = rebuild_header(array('to' => $row['to_address'], 'bcc' => $row['bcc_address']));
 2171   
 2172          foreach ($_types as $ug_type)
 2173          {
 2174              if (isset($address[$message_id][$ug_type]) && sizeof($address[$message_id][$ug_type]))
 2175              {
 2176                  foreach ($address[$message_id][$ug_type] as $ug_id => $in_to)
 2177                  {
 2178                      $recipient_list[$ug_type][$ug_id] = array('name' => $user->lang['NA'], 'colour' => '');
 2179                  }
 2180              }
 2181          }
 2182      }
 2183   
 2184      foreach ($_types as $ug_type)
 2185      {
 2186          if (!empty($recipient_list[$ug_type]))
 2187          {
 2188              if ($ug_type == 'u')
 2189              {
 2190                  $sql = 'SELECT user_id as id, username as name, user_colour as colour
 2191                      FROM ' . USERS_TABLE . '
 2192                      WHERE ';
 2193              }
 2194              else
 2195              {
 2196                  $sql = 'SELECT group_id as id, group_name as name, group_colour as colour, group_type
 2197                      FROM ' . GROUPS_TABLE . '
 2198                      WHERE ';
 2199              }
 2200              $sql .= $db->sql_in_set(($ug_type == 'u') ? 'user_id' : 'group_id', array_map('intval', array_keys($recipient_list[$ug_type])));
 2201   
 2202              $result = $db->sql_query($sql);
 2203   
 2204              while ($row = $db->sql_fetchrow($result))
 2205              {
 2206                  if ($ug_type == 'g')
 2207                  {
 2208                      $row['name'] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['name']] : $row['name'];
 2209                  }
 2210   
 2211                  $recipient_list[$ug_type][$row['id']] = array('name' => $row['name'], 'colour' => $row['colour']);
 2212              }
 2213              $db->sql_freeresult($result);
 2214          }
 2215      }
 2216   
 2217      foreach ($address as $message_id => $adr_ary)
 2218      {
 2219          foreach ($adr_ary as $type => $id_ary)
 2220          {
 2221              foreach ($id_ary as $ug_id => $_id)
 2222              {
 2223                  if ($type == 'u')
 2224                  {
 2225                      $address_list[$message_id][] = get_username_string('full', $ug_id, $recipient_list[$type][$ug_id]['name'], $recipient_list[$type][$ug_id]['colour']);
 2226                  }
 2227                  else
 2228                  {
 2229                      $user_colour = ($recipient_list[$type][$ug_id]['colour']) ? ' style="font-weight: bold; color:#' . $recipient_list[$type][$ug_id]['colour'] . '"' : '';
 2230                      $link = '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&amp;g=' . $ug_id) . '"' . $user_colour . '>';
 2231                      $address_list[$message_id][] = $link . $recipient_list[$type][$ug_id]['name'] . (($link) ? '</a>' : '');
 2232                  }
 2233              }
 2234          }
 2235      }
 2236   
 2237      return $address_list;
 2238  }
 2239