[ Index ] |
PHP Cross Reference of MyBB |
[Summary view] [Print] [Text view]
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 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Oct 8 19:19:50 2013 | Cross-referenced by PHPXref 0.7.1 |