1<?php 2/* 3 * e107 website system 4 * 5 * Copyright (C) 2008-2014 e107 Inc (e107.org) 6 * Released under the terms and conditions of the 7 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) 8 * 9 * PM plugin - base class API 10 * 11 */ 12 13 14 15if (!defined('e107_INIT')) { exit; } 16 17class private_message 18{ 19 protected $e107; 20 protected $pmPrefs; 21 22 23 public function prefs() 24 { 25 return $this->pmPrefs; 26 } 27 28 29 /** 30 * Constructor 31 * 32 * @param array $prefs - pref settings for PM plugin 33 * @return none 34 */ 35 public function __construct($prefs=null) 36 { 37 $this->e107 = e107::getInstance(); 38 $this->pmPrefs = e107::pref('pm'); 39 } 40 41 42 /** 43 * Mark a PM as read 44 * If flag set, send read receipt to sender 45 * 46 * @param int $pm_id - ID of PM 47 * @param array $pm_info - PM details 48 * 49 * @return none 50 * 51 * @todo - 'read_delete' pref doesn't exist - remove code? Or support? 52 */ 53 function pm_mark_read($pm_id, $pm_info) 54 { 55 $now = time(); 56 if($this->pmPrefs['read_delete']) 57 { 58 $this->del($pm_id); 59 } 60 else 61 { 62 e107::getDb()->gen("UPDATE `#private_msg` SET `pm_read` = {$now} WHERE `pm_id`=".intval($pm_id)); // TODO does this work properly? 63 if(strpos($pm_info['pm_option'], '+rr') !== FALSE) 64 { 65 $this->pm_send_receipt($pm_info); 66 } 67 e107::getEvent()->trigger('user_pm_read', $pm_id); 68 } 69 } 70 71 72 /* 73 * Get an existing PM 74 * 75 * @param int $pmid - ID of PM in DB 76 * 77 * @return boolean|array - FALSE on error, array of PM info on success 78 */ 79 function pm_get($pmid) 80 { 81 $qry = " 82 SELECT pm.*, ut.user_image AS sent_image, ut.user_name AS sent_name, uf.user_image AS from_image, uf.user_name AS from_name, uf.user_email as from_email, ut.user_email as to_email FROM #private_msg AS pm 83 LEFT JOIN #user AS ut ON ut.user_id = pm.pm_to 84 LEFT JOIN #user AS uf ON uf.user_id = pm.pm_from 85 WHERE pm.pm_id='".intval($pmid)."' 86 "; 87 if (e107::getDb()->gen($qry)) 88 { 89 $row = e107::getDb()->fetch(); 90 return $row; 91 } 92 return FALSE; 93 } 94 95 96 /* 97 * Send a PM 98 * 99 * @param array $vars - PM information 100 * ['receipt'] - set TRUE if read receipt required 101 * ['uploaded'] - list of attachments (if any) - each is an array('size', 'name') 102 * ['to_userclass'] - set TRUE if sending to a user class 103 * ['to_array'] = array of recipients 104 * ['pm_userclass'] = target user class 105 * ['to_info'] = recipients array of array('user_id', 'user_class') 106 * 107 * May also be an array as received from the generic table, if sending via a cron job 108 * identified by the existence of $vars['pm_from'] 109 * 110 * @return string - text detailing result 111 */ 112 function add($vars) 113 { 114 $tp = e107::getParser(); 115 $sql = e107::getDb(); 116 $pmsize = 0; 117 $attachlist = ''; 118 $pm_options = ''; 119 $ret = ''; 120 $addOutbox = TRUE; 121 $timestamp = time(); 122 123 $maxSendNow = varset($this->pmPrefs['pm_max_send'],100); // Maximum number of PMs to send without queueing them 124 if (isset($vars['pm_from'])) 125 { // Doing bulk send off cron task 126 $info = array(); 127 foreach ($vars as $k => $v) 128 { 129 if (strpos($k, 'pm_') === 0) 130 { 131 $info[$k] = $v; 132 unset($vars[$k]); 133 } 134 } 135 $addOutbox = FALSE; // Don't add to outbox - was done earlier 136 } 137 else 138 { // Send triggered by user - may be immediate or bulk dependent on number of recipients 139 $vars['options'] = ''; 140 if(isset($vars['receipt']) && $vars['receipt']) {$pm_options .= '+rr+'; } 141 142 if(isset($vars['uploaded'])) 143 { 144 foreach($vars['uploaded'] as $u) 145 { 146 if (!isset($u['error']) || !$u['error']) 147 { 148 $pmsize += $u['size']; 149 $a_list[] = $u['name']; 150 } 151 } 152 $attachlist = implode(chr(0), $a_list); 153 } 154 $pmsize += strlen($vars['pm_message']); 155 156 $pm_subject = trim($tp->toDB($vars['pm_subject'])); 157 $pm_message = trim($tp->toDB($vars['pm_message'])); 158 159 if (!$pm_subject && !$pm_message && !$attachlist) 160 { // Error - no subject, no message body and no uploaded files 161 return LAN_PM_65; 162 } 163 164 // Most of the pm info is fixed - just need to set the 'to' user on each send 165 $info = array( 166 'pm_from' => $vars['from_id'], 167 'pm_sent' => $timestamp, /* Date sent */ 168 'pm_read' => 0, /* Date read */ 169 'pm_subject' => $pm_subject, 170 'pm_text' => $pm_message, 171 'pm_sent_del' => 0, /* Set when can delete */ 172 'pm_read_del' => 0, /* set when can delete */ 173 'pm_attachments' => $attachlist, 174 'pm_option' => $pm_options, /* Options associated with PM - '+rr' for read receipt */ 175 'pm_size' => $pmsize 176 ); 177 178 // print_a($info); 179 // print_a($vars); 180 } 181 182 if(!empty($vars['pm_userclass']) || isset($vars['to_array'])) 183 { 184 if(!empty($vars['pm_userclass'])) 185 { 186 $toclass = e107::getUserClass()->uc_get_classname($vars['pm_userclass']); 187 $tolist = $this->get_users_inclass($vars['pm_userclass']); 188 $ret .= LAN_PM_38.": {$toclass}<br />"; 189 $class = TRUE; 190 $info['pm_sent_del'] = 1; // keep the outbox clean and limited to 1 entry when sending to an entire class. 191 } 192 else 193 { 194 $tolist = $vars['to_array']; 195 $class = FALSE; 196 } 197 // Sending multiple PMs here. If more than some number ($maxSendNow), need to split into blocks. 198 if (count($tolist) > $maxSendNow) 199 { 200 $totalSend = count($tolist); 201 $targets = array_chunk($tolist, $maxSendNow); // Split into a number of lists, each with the maximum number of elements (apart from the last block, of course) 202 unset($tolist); 203 $array = new ArrayData; 204 $pmInfo = $info; 205 $genInfo = array( 206 'gen_type' => 'pm_bulk', 207 'gen_datestamp' => time(), 208 'gen_user_id' => USERID, 209 'gen_ip' => '' 210 ); 211 for ($i = 0; $i < count($targets) - 1; $i++) 212 { // Save the list in the 'generic' table 213 $pmInfo['to_array'] = $targets[$i]; // Should be in exactly the right format 214 $genInfo['gen_intdata'] = count($targets[$i]); 215 $genInfo['gen_chardata'] = $array->WriteArray($pmInfo,TRUE); 216 $sql->insert('generic', array('data' => $genInfo, '_FIELD_TYPES' => array('gen_chardata' => 'string'))); // Don't want any of the clever sanitising now 217 } 218 $toclass .= ' ['.$totalSend.']'; 219 $tolist = $targets[count($targets) - 1]; // Send the residue now (means user probably isn't kept hanging around too long if sending lots) 220 unset($targets); 221 } 222 foreach($tolist as $u) 223 { 224 set_time_limit(30); 225 $info['pm_to'] = intval($u['user_id']); // Sending to a single user now 226 227 if($pmid = $sql->insert('private_msg', $info)) 228 { 229 $info['pm_id'] = $pmid; 230 e107::getEvent()->trigger('user_pm_sent', $info); 231 232 unset($info['pm_id']); // prevent it from being used on the next record. 233 234 if($class == FALSE) 235 { 236 $toclass .= $u['user_name'].', '; 237 } 238 if(check_class($this->pmPrefs['notify_class'], null, $u['user_id'])) 239 { 240 $vars['to_info'] = $u; 241 $vars['pm_sent'] = $timestamp; 242 $this->pm_send_notify($u['user_id'], $vars, $pmid, count($a_list)); 243 } 244 } 245 else 246 { 247 $ret .= LAN_PM_39.": {$u['user_name']} <br />"; 248 e107::getMessage()->addDebug($sql->getLastErrorText()); 249 } 250 } 251 if ($addOutbox) 252 { 253 $info['pm_to'] = $toclass; // Class info to put into outbox 254 $info['pm_sent_del'] = 0; 255 $info['pm_read_del'] = 1; 256 if(!$pmid = $sql->insert('private_msg', $info)) 257 { 258 $ret .= LAN_PM_41.'<br />'; 259 } 260 } 261 262 } 263 else 264 { // Sending to a single person 265 $info['pm_to'] = intval($vars['to_info']['user_id']); // Sending to a single user now 266 267 268 269 270 if($pmid = $sql->insert('private_msg', $info)) 271 { 272 $info['pm_id'] = $pmid; 273 $info['pm_sent'] = $timestamp; 274 e107::getEvent()->trigger('user_pm_sent', $info); 275 276 277 if(check_class($this->pmPrefs['notify_class'], null, $vars['to_info']['user_id'])) 278 { 279 set_time_limit(20); 280 $vars['pm_sent'] = $timestamp; 281 $this->pm_send_notify($vars['to_info']['user_id'], $vars, $pmid, count($a_list)); 282 } 283 $ret .= LAN_PM_40.": {$vars['to_info']['user_name']}<br />"; 284 } 285 } 286 return $ret; 287 } 288 289 290 291 /** 292 * Delete a PM from a user's inbox/outbox. 293 * PM is only actually deleted from DB once both sender and recipient have marked it as deleted 294 * When physically deleted, any attachments are deleted as well 295 * 296 * @param integer $pmid - ID of the PM 297 * @param boolean $force - set to TRUE to force deletion of unread PMs 298 * @return boolean|string - FALSE if PM not found, or other DB error. String if successful 299 */ 300 function del($pmid, $force = FALSE) 301 { 302 $sql = e107::getDb(); 303 $pmid = (int)$pmid; 304 $ret = ''; 305 $newvals = ''; 306 if($sql->select('private_msg', '*', 'pm_id = '.$pmid.' AND (pm_from = '.USERID.' OR pm_to = '.USERID.')')) 307 { 308 $row = $sql->fetch(); 309 310 // if user is the receiver of the PM 311 if (!$force && ($row['pm_to'] == USERID)) 312 { 313 $newvals = 'pm_read_del = 1'; 314 $ret .= LAN_PM_42.'<br />'; 315 if($row['pm_sent_del'] == 1) { $force = TRUE; } // sender has deleted as well, set force to true so the DB record can be deleted 316 } 317 318 // if user is the sender of the PM 319 if (!$force && ($row['pm_from'] == USERID)) 320 { 321 if($newvals != '') { $force = TRUE; } 322 $newvals = 'pm_sent_del = 1'; 323 $ret .= LAN_PM_43."<br />"; 324 if($row['pm_read_del'] == 1) { $force = TRUE; } // receiver has deleted as well, set force to true so the DB record can be deleted 325 } 326 327 if($force == TRUE) 328 { 329 // Delete any attachments and remove PM from db 330 $attachments = explode(chr(0), $row['pm_attachments']); 331 $aCount = array(0,0); 332 foreach($attachments as $a) 333 { 334 $a = trim($a); 335 if ($a) 336 { 337 $filename = e_PLUGIN.'pm/attachments/'.$a; 338 if (unlink($filename)) $aCount[0]++; else $aCount[1]++; 339 } 340 } 341 if ($aCount[0] || $aCount[1]) 342 { 343 344 // $ret .= str_replace(array('--GOOD--', '--FAIL--'), $aCount, LAN_PM_71).'<br />'; 345 $ret .= e107::getParser()->lanVars(LAN_PM_71, $aCount); 346 } 347 $sql->delete('private_msg', 'pm_id = '.$pmid); 348 } 349 else 350 { 351 $sql->update('private_msg', $newvals.' WHERE pm_id = '.$pmid); 352 } 353 return $ret; 354 } 355 return FALSE; 356 } 357 358 /** 359 * Convinient url assembling shortcut 360 *//* 361 public function url($action, $params = array(), $options = array()) 362 { 363 if(strpos($action, '/') === false) $action = 'view/'.$action; 364 e107::getUrl()->create('pm/'.$action, $params, $options); 365 }*/ 366 367 /** 368 * Send an email to notify of a PM 369 * 370 * @param int $uid - not used 371 * @param array $pmInfo - PM details 372 * @param int $pmid - ID of PM in database 373 * @param int $attach_count - number of attachments 374 * 375 * @return none 376 */ 377 function pm_send_notify($uid, $pmInfo, $pmid, $attach_count = 0) 378 { 379 // require_once(e_HANDLER.'mail.php'); 380/* 381 $tpl_file = THEME.'pm_template.php'; 382 383 $PM_NOTIFY = null; // loaded in template below. 384 385 include(is_readable($tpl_file) ? $tpl_file : e_PLUGIN.'pm/pm_template.php'); 386 387 $template = $PM_NOTIFY; 388*/ 389 if(THEME_LEGACY){include_once(THEME.'pm_template.php');} 390 if (!$PM_NOTIFY){$PM_NOTIFY = e107::getTemplate('pm', 'pm', 'notify');} 391 392 if(empty($PM_NOTIFY)) // BC Fallback. 393 { 394 395 $PM_NOTIFY = 396 "<div> 397 <h4>".LAN_PM_101."{SITENAME}</h4> 398 <table class='table table-striped'> 399 <tr><td>".LAN_PM_102."</td><td>{USERNAME}</td></tr> 400 <tr><td>".LAN_PM_103."</td><td>{PM_SUBJECT}</td></tr> 401 <tr><td>".LAN_PM_108."</td><td>{PM_DATE}</td></tr> 402 <tr><td>".LAN_PM_104."</td><td>{PM_ATTACHMENTS}</td></tr> 403 404 </table><br /> 405 <div>".LAN_PM_105.": {PM_URL}</div> 406 </div> 407 "; 408 409 } 410 411 $url = e107::url('pm','index', null, array('mode'=>'full')).'?show.'.$pmid; 412 413 $data = array(); 414 $data['PM_SUBJECT'] = $pmInfo['pm_subject']; 415 $data['PM_ATTACHMENTS'] = intval($attach_count); 416 $data['PM_DATE'] = e107::getParser()->toDate($pmInfo['pm_sent'], 'long'); 417 $data['SITENAME'] = SITENAME; 418 $data['USERNAME'] = USERNAME; 419 $data['PM_URL'] = $url;// e107::url('pm','index', null, array('mode'=>'full')).'?show.'.$pmid; 420 $data['PM_BUTTON'] = "<a class='btn btn-primary' href='".$url."'>".LAN_PM_113."</a>";// e107::url('pm','index', null, array('mode'=>'full')).'?show.'.$pmid; 421 422 $text = e107::getParser()->simpleParse($PM_NOTIFY, $data); 423 424 $eml = array(); 425 $eml['email_subject'] = LAN_PM_100.USERNAME; 426 $eml['send_html'] = true; 427 $eml['email_body'] = $text; 428 $eml['template'] = 'default'; 429 $eml['e107_header'] = $pmInfo['to_info']['user_id']; 430 431 if(e107::getEmail()->sendEmail($pmInfo['to_info']['user_email'], $pmInfo['to_info']['user_name'], $eml)) 432 { 433 return true; 434 } 435 else 436 { 437 return false; 438 } 439 440 } 441 442 443 /** 444 * Send PM read receipt 445 * 446 * @param array $pmInfo - PM details 447 * @return boolean 448 */ 449 function pm_send_receipt($pmInfo) //TODO Add Template and combine with method above.. 450 { 451 require_once(e_HANDLER.'mail.php'); 452 $subject = LAN_PM_106.$pmInfo['sent_name']; 453 454 $pmlink = e107::url('pm','index', null, array('mode'=>'full')).'?show.'.$pmInfo['pm_id']; 455 456 $txt = str_replace("{UNAME}", $pmInfo['sent_name'], LAN_PM_107).date('l F dS Y h:i:s A')."\n\n"; 457 $txt .= LAN_PM_108.date('l F dS Y h:i:s A', $pmInfo['pm_sent'])."\n"; 458 $txt .= LAN_PM_103.$pmInfo['pm_subject']."\n"; 459 $txt .= LAN_PM_105."\n".$pmlink."\n"; 460 461 if(sendemail($pmInfo['from_email'], $subject, $txt, $pmInfo['from_name'])) 462 { 463 return true; 464 } 465 466 return false; 467 } 468 469 470 /** 471 * Get list of users blocked from sending to a specific user ID. 472 * 473 * @param int|mixed $to - user ID 474 * @return array of blocked users as user IDs 475 */ 476 function block_get($to = USERID) 477 { 478 $sql = e107::getDb(); 479 $ret = array(); 480 $to = intval($to); // Precautionary 481 if ($sql->select('private_msg_block', 'pm_block_from', 'pm_block_to = '.$to)) 482 { 483 while($row = $sql->fetch()) 484 { 485 $ret[] = $row['pm_block_from']; 486 } 487 } 488 return $ret; 489 } 490 491 492 /** 493 * Get list of users blocked from sending to a specific user ID. 494 * 495 * @param integer $to - user ID 496 * 497 * @return array of blocked users, including specific user info 498 */ 499 function block_get_user($to = USERID) 500 { 501 $sql = e107::getDb(); 502 $ret = array(); 503 $to = intval($to); // Precautionary 504 if ($sql->gen('SELECT pm.*, u.user_name FROM `#private_msg_block` AS pm LEFT JOIN `#user` AS u ON `pm`.`pm_block_from` = `u`.`user_id` WHERE pm_block_to = '.$to)) 505 { 506 while($row = $sql->fetch()) 507 { 508 $ret[] = $row; 509 } 510 } 511 return $ret; 512 } 513 514 515 /** 516 * Add a user block 517 * 518 * @param int $from - sender to block 519 * @param int $to - user doing the blocking 520 * 521 * @return string result message 522 */ 523 function block_add($from, $to = USERID) 524 { 525 $sql = e107::getDb(); 526 $from = intval($from); 527 if($sql->select('user', 'user_name, user_perms', 'user_id = '.$from)) 528 { 529 $uinfo = $sql->fetch(); 530 if (($uinfo['user_perms'] == '0') || ($uinfo['user_perms'] == '0.')) 531 { // Don't allow block of main admin 532 return LAN_PM_64; 533 } 534 535 if(!$sql->count('private_msg_block', '(*)', 'WHERE pm_block_from = '.$from." AND pm_block_to = '".e107::getParser()->toDB($to)."'")) 536 { 537 if($sql->insert('private_msg_block', array( 538 'pm_block_from' => $from, 539 'pm_block_to' => $to, 540 'pm_block_datestamp' => time() 541 ))) 542 { 543 return str_replace('{UNAME}', $uinfo['user_name'], LAN_PM_47); 544 } 545 else 546 { 547 return LAN_PM_48; 548 } 549 } 550 else 551 { 552 return str_replace('{UNAME}', $uinfo['user_name'], LAN_PM_49); 553 } 554 } 555 else 556 { 557 return LAN_PM_17; 558 } 559 } 560 561 562 563 /** 564 * Delete user block 565 * 566 * @param int $from - sender to block 567 * @param int $to - user doing the blocking 568 * 569 * @return string result message 570 */ 571 function block_del($from, $to = USERID) 572 { 573 $sql = e107::getDb(); 574 $from = intval($from); 575 if($sql->select('user', 'user_name', 'user_id = '.$from)) 576 { 577 $uinfo = $sql->fetch(); 578 if($sql->select('private_msg_block', 'pm_block_id', 'pm_block_from = '.$from.' AND pm_block_to = '.intval($to))) 579 { 580 $row = $sql->fetch(); 581 if($sql->delete('private_msg_block', 'pm_block_id = '.intval($row['pm_block_id']))) 582 { 583 return str_replace('{UNAME}', $uinfo['user_name'], LAN_PM_44); 584 } 585 else 586 { 587 return LAN_PM_45; 588 } 589 } 590 else 591 { 592 return str_replace('{UNAME}', $uinfo['user_name'], LAN_PM_46); 593 } 594 } 595 else 596 { 597 return LAN_PM_17; 598 } 599 } 600 601 602 /** 603 * Get user ID matching a name 604 * 605 * @param string var - name to match 606 * 607 * @return boolean|array - FALSE if no match, array of user info if found 608 */ 609 function pm_getuid($var) 610 { 611 $sql = e107::getDb(); 612 613 if(is_numeric($var)) 614 { 615 $where = "user_id = ".intval($var); 616 } 617 else 618 { 619 $var = strip_if_magic($var); 620 $var = str_replace("'", ''', trim($var)); // Display name uses entities for apostrophe 621 $where = "user_name LIKE '".$sql->escape($var, FALSE)."'"; 622 } 623 624 if($sql->select('user', 'user_id, user_name, user_class, user_email', $where)) 625 { 626 $row = $sql->fetch(); 627 return $row; 628 } 629 630 return false; 631 632 } 633 634 635 /** 636 * Get list of users in class 637 * 638 * @param int $class - class ID 639 * 640 * @return boolean|array - FALSE on error/none found, else array of user information arrays 641 */ 642 function get_users_inclass($class) 643 { 644 645 return e107::getUserClass()->getUsersInClass($class, 'user_name, user_email, user_class'); 646 647 648 /*$sql = e107::getDb(); 649 650 if($class == e_UC_MEMBER) 651 { 652 $qry = "SELECT user_id, user_name, user_email, user_class FROM `#user` WHERE 1"; 653 } 654 elseif($class == e_UC_ADMIN) 655 { 656 $qry = "SELECT user_id, user_name, user_email, user_class FROM `#user` WHERE user_admin = 1"; 657 } 658 elseif($class) 659 { 660 $regex = "(^|,)(".e107::getParser()->toDB($class).")(,|$)"; 661 $qry = "SELECT user_id, user_name, user_email, user_class FROM `#user` WHERE user_class REGEXP '{$regex}'"; 662 } 663 664 665 if(!empty($qry) && $sql->gen($qry)) 666 { 667 $ret = $sql->db_getList(); 668 return $ret; 669 } 670 return FALSE;*/ 671 } 672 673 674 /** 675 * Check permission to send a PM to someone. 676 * @param int $uid user_id of the person to send to 677 * @return bool 678 */ 679 function canSendTo($uid) 680 { 681 if(empty($uid)) 682 { 683 return false; 684 } 685 686 if(!empty($this->pmPrefs['vip_class'])) 687 { 688 if(check_class($this->pmPrefs['vip_class'],null,$uid) && !check_class($this->pmPrefs['vip_class'])) 689 { 690 return false; 691 } 692 693 } 694 695 $user = e107::user($uid); 696 697 $uclass = explode(",", $user['user_class']); 698 699 if($this->pmPrefs['send_to_class'] == 'matchclass') 700 { 701 $tmp = explode(",", USERCLASS); 702 $result = array_intersect($uclass, $tmp); 703 704 return !empty($result); 705 } 706 707 return in_array($this->pmPrefs['send_to_class'], $uclass); 708 709 } 710 711 712 713 714 /** 715 * Get inbox - up to $limit messages from $from 716 * 717 * @param int $uid - user ID 718 * @param int $from - first message 719 * @param int $limit - number of messages 720 * 721 * @return boolean|array - FALSE if none found or error, array of PMs if available 722 */ 723 function pm_get_inbox($uid = USERID, $from = 0, $limit = 10) 724 { 725 $sql = e107::getDb(); 726 $ret = array(); 727 $total_messages = 0; 728 $uid = intval($uid); 729 $limit = intval($limit); 730 if ($limit < 2) { $limit = 10; } 731 $from = intval($from); 732 $qry = " 733 SELECT SQL_CALC_FOUND_ROWS pm.*, u.user_image, u.user_name FROM `#private_msg` AS pm 734 LEFT JOIN `#user` AS u ON u.user_id = pm.pm_from 735 WHERE pm.pm_to='{$uid}' AND pm.pm_read_del=0 736 ORDER BY pm.pm_sent DESC 737 LIMIT ".$from.", ".$limit." 738 "; 739 740 if($sql->gen($qry)) 741 { 742 $total_messages = $sql->foundRows(); // Total number of messages 743 $ret['messages'] = $sql->db_getList(); 744 } 745 746 $ret['total_messages'] = $total_messages; // Should always be defined 747 return $ret; 748 } 749 750 751 /** 752 * Get outbox - up to $limit messages from $from 753 * 754 * @param int $uid - user ID 755 * @param int $from - first message 756 * @param int $limit - number of messages 757 * 758 * @return boolean|array - FALSE if none found or error, array of PMs if available 759 */ 760 function pm_get_outbox($uid = USERID, $from = 0, $limit = 10) 761 { 762 $sql = e107::getDb(); 763 $ret = array(); 764 $total_messages = 0; 765 $uid = intval($uid); 766 $limit = intval($limit); 767 if ($limit < 2) { $limit = 10; } 768 $from = intval($from); 769 $qry = " 770 SELECT SQL_CALC_FOUND_ROWS pm.*, u.user_image, u.user_name FROM #private_msg AS pm 771 LEFT JOIN #user AS u ON u.user_id = pm.pm_to 772 WHERE pm.pm_from='{$uid}' AND pm.pm_sent_del = '0' 773 774 ORDER BY pm.pm_sent DESC 775 LIMIT ".$from.', '.$limit; 776 777 if($sql->gen($qry)) 778 { 779 $total_messages = $sql->total_results; // Total number of messages 780 $ret['messages'] = $sql->db_getList(); 781 } 782 $ret['total_messages'] = $total_messages; 783 return $ret; 784 } 785 786 787 /** 788 * Send a file down to the user 789 * 790 * @param int $pmid - PM ID 791 * @param string $filenum - attachment number within the list associated with the PM 792 * 793 * @return none 794 * 795 */ 796 function send_file($pmid, $filenum) 797 { 798 $pm_info = $this->pm_get($pmid); 799 800 $attachments = explode(chr(0), $pm_info['pm_attachments']); 801 802 if(!isset($attachments[$filenum])) 803 { 804 return false; 805 } 806 807 $fname = $attachments[$filenum]; 808 list($timestamp, $fromid, $rand, $file) = explode("_", $fname, 4); 809 810 811 $filename = false; // getcwd()."/attachments/{$fname}"; 812 813 $pathList = array(); 814 $pathList[] = e_PLUGIN."pm/attachments/"; // getcwd()."/attachments/"; // legacy path. 815 $pathList[] = e107::getFile()->getUserDir($fromid, false, 'attachments'); // new media path. 816 817 foreach($pathList as $path) 818 { 819 $tPath = $path.$fname; 820 821 if(is_file($tPath)) 822 { 823 $filename = $tPath; 824 break; 825 } 826 827 } 828 829 if(empty($filename) || !is_file($filename)) 830 { 831 return false; 832 } 833 834 835 if($fromid != $pm_info['pm_from']) 836 { 837 return false; 838 } 839 840 // e107::getFile()->send($filename); // limited to Media and system folders. Won't work for legacy plugin path. 841 // exit; 842 843 844 845 @set_time_limit(10 * 60); 846 @e107_ini_set("max_execution_time", 10 * 60); 847 while (@ob_end_clean()); // kill all output buffering else it eats server resources 848 if (connection_status() == 0) 849 { 850 if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE")) { 851 $file = preg_replace('/\./', '%2e', $file, substr_count($file, '.') - 1); 852 } 853 if (isset($_SERVER['HTTP_RANGE'])) 854 { 855 $seek = intval(substr($_SERVER['HTTP_RANGE'] , strlen('bytes='))); 856 } 857 $bufsize = 2048; 858 ignore_user_abort(true); 859 $data_len = filesize($filename); 860 if ($seek > ($data_len - 1)) $seek = 0; 861 $res =& fopen($filename, 'rb'); 862 if ($seek) 863 { 864 fseek($res , $seek); 865 } 866 $data_len -= $seek; 867 header("Expires: 0"); 868 header("Cache-Control: max-age=30" ); 869 header("Content-Type: application/force-download"); 870 header("Content-Disposition: attachment; filename={$file}"); 871 header("Content-Length: {$data_len}"); 872 header("Pragma: public"); 873 if ($seek) 874 { 875 header("Accept-Ranges: bytes"); 876 header("HTTP/1.0 206 Partial Content"); 877 header("status: 206 Partial Content"); 878 header("Content-Range: bytes {$seek}-".($data_len - 1)."/{$data_len}"); 879 } 880 while (!connection_aborted() && $data_len > 0) 881 { 882 echo fread($res , $bufsize); 883 $data_len -= $bufsize; 884 } 885 fclose($res); 886 } 887 } 888 889 890 891 892 893 894 895 896 897 function updateTemplate($template) 898 { 899 $array = array( 900 'FORM_TOUSER' => 'PM_FORM_TOUSER', 901 'FORM_TOCLASS' => 'PM_FORM_TOCLASS', 902 'FORM_SUBJECT' => 'PM_FORM_SUBJECT', 903 'FORM_MESSAGE' => 'PM_FORM_MESSAGE', 904 'EMOTES' => 'PM_EMOTES', 905 'ATTACHMENT' => 'PM_ATTACHMENT', 906 'RECEIPT' => 'PM_RECEIPT', 907 'INBOX_TOTAL' => 'PM_INBOX_TOTAL', 908 'INBOX_UNREAD' => 'PM_INBOX_UNREAD', 909 'INBOX_FILLED' => 'PM_INBOX_FILLED', 910 'OUTBOX_TOTAL' => 'PM_OUTBOX_TOTAL', 911 'OUTBOX_UNREAD' => 'PM_OUTBOX_UNREAD', 912 'OUTBOX_FILLED' => 'PM_OUTBOX_FILLED', 913 914 'SEND_PM_LINK' => 'PM_SEND_PM_LINK', 915 'NEWPM_ANIMATE' => 'PM_NEWPM_ANIMATE', 916 917 'BLOCKED_SENDERS_MANAGE' => 'PM_BLOCKED_SENDERS_MANAGE', 918 'DELETE_BLOCKED_SELECTED' => 'DELETE_BLOCKED_SELECTED' 919 ); 920 921 922 foreach($array as $old => $new) 923 { 924 $template = str_replace("{".$old."}", "{".$new."}", $template); 925 } 926 927 return $template; 928 929 } 930 931} 932