[ Index ]

PHP Cross Reference of MyBB

title

Body

[close]

/inc/datahandlers/ -> pm.php (source)

   1  <?php
   2  /**
   3   * MyBB 1.6
   4   * Copyright 2010 MyBB Group, All Rights Reserved
   5   *
   6   * Website: http://mybb.com
   7   * License: http://mybb.com/about/license
   8   *
   9   * $Id$
  10   */
  11  
  12  // Disallow direct access to this file for security reasons
  13  if(!defined("IN_MYBB"))
  14  {
  15      die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
  16  }
  17  
  18  /**
  19   * PM handling class, provides common structure to handle private messaging data.
  20   *
  21   */
  22  class PMDataHandler extends DataHandler
  23  {
  24      /**
  25      * The language file used in the data handler.
  26      *
  27      * @var string
  28      */
  29      public $language_file = 'datahandler_pm';
  30  
  31      /**
  32      * The prefix for the language variables used in the data handler.
  33      *
  34      * @var string
  35      */
  36      public $language_prefix = 'pmdata';
  37  
  38      /**
  39       * Array of data inserted in to a private message.
  40       *
  41       * @var array
  42       */
  43      public $pm_insert_data = array();
  44  
  45      /**
  46       * Array of data used to update a private message.
  47       *
  48       * @var array
  49       */
  50      public $pm_update_data = array();
  51  
  52      /**
  53       * PM ID currently being manipulated by the datahandlers.
  54       */
  55      public $pmid = 0;
  56  
  57      /**
  58       * Verifies a private message subject.
  59       *
  60       * @return boolean True when valid, false when invalid.
  61       */
  62  	function verify_subject()
  63      {
  64          $subject = &$this->data['subject'];
  65  
  66          $subject = utf8_handle_4byte_string($subject);
  67  
  68          // Subject is over 85 characters, too long.
  69          if(my_strlen($subject) > 85)
  70          {
  71              $this->set_error("too_long_subject");
  72              return false;
  73          }
  74          // No subject, apply the default [no subject]
  75          if(!trim_blank_chrs($subject))
  76          {
  77              $this->set_error("missing_subject");
  78              return false;
  79          }
  80          return true;
  81      }
  82  
  83      /**
  84       * Verifies if a message for a PM is valid.
  85       *
  86       * @return boolean True when valid, false when invalid.
  87       */
  88  	function verify_message()
  89      {
  90          $message = &$this->data['message'];
  91  
  92          $message = utf8_handle_4byte_string($message);
  93  
  94          // No message, return an error.
  95          if(trim_blank_chrs($message) == '')
  96          {
  97              $this->set_error("missing_message");
  98              return false;
  99          }
 100          return true;
 101      }
 102  
 103      /**
 104       * Verifies if the specified sender is valid or not.
 105       *
 106       * @return boolean True when valid, false when invalid.
 107       */
 108  	function verify_sender()
 109      {
 110          global $db, $mybb, $lang;
 111  
 112          $pm = &$this->data;
 113  
 114          // Return if we've already validated
 115          if($pm['sender']) return true;
 116  
 117          // Fetch the senders profile data.
 118          $sender = get_user($pm['fromid']);
 119  
 120          // Collect user permissions for the sender.
 121          $sender_permissions = user_permissions($pm['fromid']);
 122  
 123          // Check if the sender is over their quota or not - if they are, disable draft sending
 124          if($pm['options']['savecopy'] != 0 && !$pm['saveasdraft'])
 125          {
 126              if($sender_permissions['pmquota'] != "0" && $sender['totalpms'] >= $sender_permissions['pmquota'] && $this->admin_override != true)
 127              {
 128                  $pm['options']['savecopy'] = 0;
 129              }
 130          }
 131  
 132          // Assign the sender information to the data.
 133          $pm['sender'] = array(
 134              "uid" => $sender['uid'],
 135              "username" => $sender['username']
 136          );
 137  
 138          return true;
 139      }
 140  
 141      /**
 142       * Verifies if an array of recipients for a private message are valid
 143       *
 144       * @return boolean True when valid, false when invalid.
 145       */
 146  	function verify_recipient()
 147      {
 148          global $cache, $db, $mybb, $lang;
 149  
 150          $pm = &$this->data;
 151  
 152          $recipients = array();
 153  
 154          $invalid_recipients = array();
 155          // We have our recipient usernames but need to fetch user IDs
 156          if(array_key_exists("to", $pm))
 157          {
 158              if((count($pm['to']) <= 0 || trim(implode("", $pm['to'])) == "") && !$pm['saveasdraft'])
 159              {
 160                  $this->set_error("no_recipients");
 161                  return false;
 162              }
 163  
 164              foreach(array("to", "bcc") as $recipient_type)
 165              {
 166                  if(!is_array($pm[$recipient_type]))
 167                  {
 168                      $pm[$recipient_type] = array($pm[$recipient_type]);
 169                  }
 170  
 171                  $recipientUsernames = array_map('trim', $pm[$recipient_type]);
 172                  $recipientUsernames = array_filter($recipientUsernames);
 173                  $recipientUsernames = array_map(array($db, 'escape_string'), $recipientUsernames);
 174                  $recipientUsernames = "'".implode("','", $recipientUsernames)."'";
 175  
 176                  $query = $db->simple_select('users', '*', 'username IN('.$recipientUsernames.')');
 177  
 178                  $validUsernames = array();
 179  
 180                  while ($user = $db->fetch_array($query)) {
 181                      if ($recipient_type == "bcc") {
 182                          $user['bcc'] = 1;
 183                      }
 184  
 185                      $recipients[] = $user;
 186                      $validUsernames[] = $user['username'];
 187                  }
 188  
 189                  foreach ($pm[$recipient_type] as $username) {
 190                      if (!in_array($username, $validUsernames) AND trim($username)) {
 191                          $invalid_recipients[] = $username;
 192                      }
 193                  }
 194              }
 195          }
 196          // We have recipient IDs
 197          else
 198          {
 199              foreach(array("toid", "bccid") as $recipient_type)
 200              {
 201                  if(count($pm['toid']) <= 0)
 202                  {
 203                      $this->set_error("no_recipients");
 204                      return false;
 205                  }
 206                  if(is_array($pm[$recipient_type]))
 207                  {
 208                      $recipientUids = array_map('intval', $pm[$recipient_type]);
 209                      $recipientUids = array_filter($recipientUids);
 210                      $recipientUids = "'".implode("','", $recipientUids)."'";
 211  
 212                      $query = $db->simple_select('users', '*', 'uid IN('.$recipientUids.')');
 213  
 214                      $validUids = array();
 215  
 216                      while ($user = $db->fetch_array($query)) {
 217                          if ($recipient_type == "bcc") {
 218                              $user['bcc'] = 1;
 219                          }
 220  
 221                          $recipients[] = $user;
 222                          $validUids[] = $user['uid'];
 223                      }
 224  
 225                      foreach ($pm[$recipient_type] as $uid) {
 226                          if (!in_array($uid, $validUids) AND trim($uid)) {
 227                              $invalid_recipients[] = $uid;
 228                          }
 229                      }
 230                  }
 231              }
 232          }
 233  
 234          // If we have one or more invalid recipients and we're not saving a draft, error
 235          if(count($invalid_recipients) > 0)
 236          {
 237              $invalid_recipients = implode(", ", array_map("htmlspecialchars_uni", $invalid_recipients));
 238              $this->set_error("invalid_recipients", array($invalid_recipients));
 239              return false;
 240          }
 241  
 242          $sender_permissions = user_permissions($pm['fromid']);
 243  
 244          // Are we trying to send this message to more users than the permissions allow?
 245          if($sender_permissions['maxpmrecipients'] > 0 && count($recipients) > $sender_permissions['maxpmrecipients'] && $this->admin_override != true)
 246          {
 247              $this->set_error("too_many_recipients", array($sender_permissions['maxpmrecipients']));
 248          }
 249  
 250          // Now we're done with that we loop through each recipient
 251          foreach($recipients as $user)
 252          {
 253              // Collect group permissions for this recipient.
 254              $recipient_permissions = user_permissions($user['uid']);
 255  
 256              // See if the sender is on the recipients ignore list and that either
 257              // - admin_override is set or
 258              // - sender is an administrator
 259              if(($this->admin_override != true && $sender_permissions['cancp'] != 1) && $sender_permissions['canoverridepm'] != 1)
 260              {
 261                  $ignorelist = explode(",", $user['ignorelist']);
 262                  if(!empty($ignorelist) && in_array($pm['fromid'], $ignorelist))
 263                  {
 264                      $this->set_error("recipient_is_ignoring", array($user['username']));
 265                  }
 266  
 267                  // Is the recipient only allowing private messages from their buddy list?
 268                  if($mybb->settings['allowbuddyonly'] == 1 && $user['receivefrombuddy'] == 1)
 269                  {
 270                      $buddylist = explode(",", $user['buddylist']);
 271                      if(!empty($buddylist) && !in_array($pm['fromid'], $buddylist))
 272                      {
 273                          $this->set_error("recipient_has_buddy_only", array(htmlspecialchars_uni($user['username'])));
 274                      }
 275                  }
 276  
 277                  // Can the recipient actually receive private messages based on their permissions or user setting?
 278                  if(($user['receivepms'] == 0 || $recipient_permissions['canusepms'] == 0) && !$pm['saveasdraft'])
 279                  {
 280                      $this->set_error("recipient_pms_disabled", array($user['username']));
 281                      return false;
 282                  }
 283              }
 284  
 285              // Check to see if the user has reached their private message quota - if they have, email them.
 286              if($recipient_permissions['pmquota'] != "0" && $user['totalpms'] >= $recipient_permissions['pmquota'] && $recipient_permissions['cancp'] != 1 && $sender_permissions['cancp'] != 1 && !$pm['saveasdraft'] && !$this->admin_override)
 287              {
 288                  if(trim($user['language']) != '' && $lang->language_exists($user['language']))
 289                  {
 290                      $uselang = trim($user['language']);
 291                  }
 292                  elseif($mybb->settings['bblanguage'])
 293                  {
 294                      $uselang = $mybb->settings['bblanguage'];
 295                  }
 296                  else
 297                  {
 298                      $uselang = "english";
 299                  }
 300                  if($uselang == $mybb->settings['bblanguage'] || !$uselang)
 301                  {
 302                      $emailsubject = $lang->emailsubject_reachedpmquota;
 303                      $emailmessage = $lang->email_reachedpmquota;
 304                  }
 305                  else
 306                  {
 307                      $userlang = new MyLanguage;
 308                      $userlang->set_path(MYBB_ROOT."inc/languages");
 309                      $userlang->set_language($uselang);
 310                      $userlang->load("messages");
 311                      $emailsubject = $userlang->emailsubject_reachedpmquota;
 312                      $emailmessage = $userlang->email_reachedpmquota;
 313                  }
 314                  $emailmessage = $lang->sprintf($emailmessage, $user['username'], $mybb->settings['bbname'], $mybb->settings['bburl']);
 315                  $emailsubject = $lang->sprintf($emailsubject, $mybb->settings['bbname']);
 316  
 317                  $new_email = array(
 318                      "mailto" => $db->escape_string($user['email']),
 319                      "mailfrom" => '',
 320                      "subject" => $db->escape_string($emailsubject),
 321                      "message" => $db->escape_string($emailmessage),
 322                      "headers" => ''
 323                  );
 324  
 325                  $db->insert_query("mailqueue", $new_email);
 326                  $cache->update_mailqueue();
 327  
 328                  if($this->admin_override != true)
 329                  {
 330                      $this->set_error("recipient_reached_quota", array($user['username']));
 331                  }
 332              }
 333  
 334              // Everything looks good, assign some specifics about the recipient
 335              $pm['recipients'][$user['uid']] = array(
 336                  "uid" => $user['uid'],
 337                  "username" => $user['username'],
 338                  "email" => $user['email'],
 339                  "lastactive" => $user['lastactive'],
 340                  "pmnotice" => $user['pmnotice'],
 341                  "pmnotify" => $user['pmnotify'],
 342                  "language" => $user['language']
 343              );
 344  
 345              // If this recipient is defined as a BCC recipient, save it
 346              if($user['bcc'] == 1)
 347              {
 348                  $pm['recipients'][$user['uid']]['bcc'] = 1;
 349              }
 350          }
 351          return true;
 352      }
 353  
 354      /**
 355      * Verify that the user is not flooding the system.
 356      *
 357      * @return boolean True
 358      */
 359  	function verify_pm_flooding()
 360      {
 361          global $mybb, $db;
 362  
 363          $pm = &$this->data;
 364  
 365          // Check if post flooding is enabled within MyBB or if the admin override option is specified.
 366          if($mybb->settings['pmfloodsecs'] > 0 && $pm['fromid'] != 0 && $this->admin_override == false)
 367          {
 368              // Fetch the senders profile data.
 369              $sender = get_user($pm['fromid']);
 370  
 371              // Calculate last post
 372              $query = $db->simple_select("privatemessages", "dateline", "fromid='".$db->escape_string($pm['fromid'])."' AND toid != '0'", array('order_by' => 'dateline', 'order_dir' => 'desc', 'limit' => 1));
 373              $sender['lastpm'] = $db->fetch_field($query, "dateline");
 374  
 375              // A little bit of calculation magic and moderator status checking.
 376              if(TIME_NOW-$sender['lastpm'] <= $mybb->settings['pmfloodsecs'] && !is_moderator("", "", $pm['fromid']))
 377              {
 378                  // Oops, user has been flooding - throw back error message.
 379                  $time_to_wait = ($mybb->settings['pmfloodsecs'] - (TIME_NOW-$sender['lastpm'])) + 1;
 380                  if($time_to_wait == 1)
 381                  {
 382                      $this->set_error("pm_flooding_one_second");
 383                  }
 384                  else
 385                  {
 386                      $this->set_error("pm_flooding", array($time_to_wait));
 387                  }
 388                  return false;
 389              }
 390          }
 391          // All is well that ends well - return true.
 392          return true;
 393      }
 394  
 395      /**
 396       * Verifies if the various 'options' for sending PMs are valid.
 397       *
 398       * @return boolean True when valid, false when invalid.
 399       */
 400  	function verify_options()
 401      {
 402          $options = &$this->data['options'];
 403  
 404          $this->verify_yesno_option($options, 'signature', 1);
 405          $this->verify_yesno_option($options, 'savecopy', 1);
 406          $this->verify_yesno_option($options, 'disablesmilies', 0);
 407  
 408          // Requesting a read receipt?
 409          if(isset($options['readreceipt']) && $options['readreceipt'] == 1)
 410          {
 411              $options['readreceipt'] = 1;
 412          }
 413          else
 414          {
 415              $options['readreceipt'] = 0;
 416          }
 417          return true;
 418      }
 419  
 420      /**
 421       * Validate an entire private message.
 422       *
 423       * @return boolean True when valid, false when invalid.
 424       */
 425  	function validate_pm()
 426      {
 427          global $plugins;
 428  
 429          $pm = &$this->data;
 430  
 431          if(!$pm['savedraft'])
 432          {
 433              $this->verify_pm_flooding();
 434          }
 435  
 436          // Verify all PM assets.
 437          $this->verify_subject();
 438  
 439          $this->verify_sender();
 440  
 441          $this->verify_recipient();
 442  
 443          $this->verify_message();
 444  
 445          $this->verify_options();
 446  
 447          $plugins->run_hooks("datahandler_pm_validate", $this);
 448  
 449          // Choose the appropriate folder to save in.
 450          if($pm['saveasdraft'])
 451          {
 452              $pm['folder'] = 3;
 453          }
 454          else
 455          {
 456              $pm['folder'] = 1;
 457          }
 458  
 459          // We are done validating, return.
 460          $this->set_validated(true);
 461          if(count($this->get_errors()) > 0)
 462          {
 463              return false;
 464          }
 465          else
 466          {
 467              return true;
 468          }
 469      }
 470  
 471      /**
 472       * Insert a new private message.
 473       *
 474       * @return array Array of PM useful data.
 475       */
 476  	function insert_pm()
 477      {
 478          global $cache, $db, $mybb, $plugins, $lang;
 479  
 480          // Yes, validating is required.
 481          if(!$this->get_validated())
 482          {
 483              die("The PM needs to be validated before inserting it into the DB.");
 484          }
 485          if(count($this->get_errors()) > 0)
 486          {
 487              die("The PM is not valid.");
 488          }
 489  
 490          // Assign data to common variable
 491          $pm = &$this->data;
 492  
 493          $pm['pmid'] = intval($pm['pmid']);
 494  
 495          if(!$pm['icon'] || $pm['icon'] < 0)
 496          {
 497              $pm['icon'] = 0;
 498          }
 499  
 500          $uid = 0;
 501  
 502          if(!is_array($pm['recipients']))
 503          {
 504              $recipient_list = array();
 505          }
 506          else
 507          {
 508              // Build recipient list
 509              foreach($pm['recipients'] as $recipient)
 510              {
 511                  if($recipient['bcc'])
 512                  {
 513                      $recipient_list['bcc'][] = $recipient['uid'];
 514                  }
 515                  else
 516                  {
 517                      $recipient_list['to'][] = $recipient['uid'];
 518                      $uid = $recipient['uid'];
 519                  }
 520              }
 521          }
 522  
 523          $this->pm_insert_data = array(
 524              'fromid' => intval($pm['sender']['uid']),
 525              'folder' => $pm['folder'],
 526              'subject' => $db->escape_string($pm['subject']),
 527              'icon' => intval($pm['icon']),
 528              'message' => $db->escape_string($pm['message']),
 529              'dateline' => TIME_NOW,
 530              'status' => 0,
 531              'includesig' => $pm['options']['signature'],
 532              'smilieoff' => $pm['options']['disablesmilies'],
 533              'receipt' => intval($pm['options']['readreceipt']),
 534              'readtime' => 0,
 535              'recipients' => $db->escape_string(serialize($recipient_list))
 536          );
 537  
 538          // Check if we're updating a draft or not.
 539          $query = $db->simple_select("privatemessages", "pmid, deletetime", "folder='3' AND uid='".intval($pm['sender']['uid'])."' AND pmid='{$pm['pmid']}'");
 540          $draftcheck = $db->fetch_array($query);
 541  
 542          // This PM was previously a draft
 543          if($draftcheck['pmid'])
 544          {
 545              if($draftcheck['deletetime'])
 546              {
 547                  // This draft was a reply to a PM
 548                  $pm['pmid'] = $draftcheck['deletetime'];
 549                  $pm['do'] = "reply";
 550              }
 551  
 552              // Delete the old draft as we no longer need it
 553              $db->delete_query("privatemessages", "pmid='{$draftcheck['pmid']}'");
 554          }
 555  
 556          // Saving this message as a draft
 557          if($pm['saveasdraft'])
 558          {
 559              $this->pm_insert_data['uid'] = $pm['sender']['uid'];
 560  
 561              // If this is a reply, then piggyback into the deletetime to let us know in the future
 562              if($pm['do'] == "reply" || $pm['do'] == "replyall")
 563              {
 564                  $this->pm_insert_data['deletetime'] = $pm['pmid'];
 565              }
 566  
 567              $plugins->run_hooks("datahandler_pm_insert_updatedraft", $this);
 568              $db->insert_query("privatemessages", $this->pm_insert_data);
 569  
 570              // If this is a draft, end it here - below deals with complete messages
 571              return array(
 572                  "draftsaved" => 1
 573              );
 574          }
 575  
 576          // Save a copy of the PM for each of our recipients
 577          foreach($pm['recipients'] as $recipient)
 578          {
 579              // Send email notification of new PM if it is enabled for the recipient
 580              $query = $db->simple_select("privatemessages", "dateline", "uid='".$recipient['uid']."' AND folder='1'", array('order_by' => 'dateline', 'order_dir' => 'desc', 'limit' => 1));
 581              $lastpm = $db->fetch_array($query);
 582              if($recipient['pmnotify'] == 1 && $recipient['lastactive'] > $lastpm['dateline'])
 583              {
 584                  if($recipient['language'] != "" && $lang->language_exists($recipient['language']))
 585                  {
 586                      $uselang = $recipient['language'];
 587                  }
 588                  elseif($mybb->settings['bblanguage'])
 589                  {
 590                      $uselang = $mybb->settings['bblanguage'];
 591                  }
 592                  else
 593                  {
 594                      $uselang = "english";
 595                  }
 596                  if($uselang == $mybb->settings['bblanguage'] && !empty($lang->emailsubject_newpm))
 597                  {
 598                      $emailsubject = $lang->emailsubject_newpm;
 599                      $emailmessage = $lang->email_newpm;
 600                  }
 601                  else
 602                  {
 603                      $userlang = new MyLanguage;
 604                      $userlang->set_path(MYBB_ROOT."inc/languages");
 605                      $userlang->set_language($uselang);
 606                      $userlang->load("messages");
 607                      $emailsubject = $userlang->emailsubject_newpm;
 608                      $emailmessage = $userlang->email_newpm;
 609                  }
 610  
 611                  if(!$pm['sender']['username'])
 612                  {
 613                      $pm['sender']['username'] = $lang->mybb_engine;
 614                  }
 615  
 616                  $emailmessage = $lang->sprintf($emailmessage, $recipient['username'], $pm['sender']['username'], $mybb->settings['bbname'], $mybb->settings['bburl']);
 617                  $emailsubject = $lang->sprintf($emailsubject, $mybb->settings['bbname']);
 618  
 619                  $new_email = array(
 620                      "mailto" => $db->escape_string($recipient['email']),
 621                      "mailfrom" => '',
 622                      "subject" => $db->escape_string($emailsubject),
 623                      "message" => $db->escape_string($emailmessage),
 624                      "headers" => ''
 625                  );
 626  
 627                  $db->insert_query("mailqueue", $new_email);
 628                  $cache->update_mailqueue();
 629              }
 630  
 631              $this->pm_insert_data['uid'] = $recipient['uid'];
 632              $this->pm_insert_data['toid'] = $recipient['uid'];
 633  
 634              $plugins->run_hooks("datahandler_pm_insert", $this);
 635              $this->pmid = $db->insert_query("privatemessages", $this->pm_insert_data);
 636  
 637              // If PM noices/alerts are on, show!
 638              if($recipient['pmnotice'] == 1)
 639              {
 640                  $updated_user = array(
 641                      "pmnotice" => 2
 642                  );
 643                  $db->update_query("users", $updated_user, "uid='{$recipient['uid']}'");
 644              }
 645  
 646              // Update private message count (total, new and unread) for recipient
 647              require_once  MYBB_ROOT."/inc/functions_user.php";
 648              update_pm_count($recipient['uid'], 7, $recipient['lastactive']);
 649          }
 650  
 651          // Are we replying or forwarding an existing PM?
 652          if($pm['pmid'])
 653          {
 654              if($pm['do'] == "reply" || $pm['do'] == "replyall")
 655              {
 656                  $sql_array = array(
 657                      'status' => 3,
 658                      'statustime' => TIME_NOW
 659                  );
 660                  $db->update_query("privatemessages", $sql_array, "pmid={$pm['pmid']} AND uid={$pm['sender']['uid']}");
 661              }
 662              elseif($pm['do'] == "forward")
 663              {
 664                  $sql_array = array(
 665                      'status' => 4,
 666                      'statustime' => TIME_NOW
 667                  );
 668                  $db->update_query("privatemessages", $sql_array, "pmid={$pm['pmid']} AND uid={$pm['sender']['uid']}");
 669              }
 670          }
 671  
 672          // If we're saving a copy
 673          if($pm['options']['savecopy'] != 0)
 674          {
 675              if(isset($recipient_list['to']) && count($recipient_list['to']) == 1)
 676              {
 677                  $this->pm_insert_data['toid'] = $uid;
 678              }
 679              else
 680              {
 681                  $this->pm_insert_data['toid'] = 0;
 682              }
 683              $this->pm_insert_data['uid'] = intval($pm['sender']['uid']);
 684              $this->pm_insert_data['folder'] = 2;
 685              $this->pm_insert_data['status'] = 1;
 686              $this->pm_insert_data['receipt'] = 0;
 687  
 688              $plugins->run_hooks("datahandler_pm_insert_savedcopy", $this);
 689              $db->insert_query("privatemessages", $this->pm_insert_data);
 690  
 691              // Because the sender saved a copy, update their total pm count
 692              require_once  MYBB_ROOT."/inc/functions_user.php";
 693              update_pm_count($pm['sender']['uid'], 1);
 694          }
 695  
 696          // Return back with appropriate data
 697          return array(
 698              "messagesent" => 1
 699          );
 700      }
 701  }
 702  ?>


Generated: Tue Oct 8 19:19:50 2013 Cross-referenced by PHPXref 0.7.1