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