1<?php 2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project 3// 4// All Rights Reserved. See copyright.txt for details and a complete list of authors. 5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 6// $Id$ 7 8//this script may only be included - so its better to die if called directly. 9if (strpos($_SERVER['SCRIPT_NAME'], basename(__FILE__)) !== false) { 10 header('location: index.php'); 11 exit; 12} 13 14class Messu extends TikiLib 15{ 16 17 /** 18 * Put sent message to 'sent' box 19 */ 20 function save_sent_message($user, $from, $to, $cc, $subject, $body, $priority, $replyto_hash = '') 21 { 22 global $prefs; 23 $userlib = TikiLib::lib('user'); 24 $smarty = TikiLib::lib('smarty'); 25 26 $subject = strip_tags($subject); 27 $body = strip_tags($body, '<a><b><img><i>'); 28 // Prevent duplicates 29 $hash = md5($subject . $body); 30 31 if ($this->getOne( 32 'select count(*) from `messu_sent` where `user`=? and `user_from`=? and `hash`=?', 33 [$user, $from, $hash] 34 ) 35 ) { 36 return false; 37 } 38 39 $query = 'insert into `messu_sent`' . 40 ' (`user`, `user_from`, `user_to`, `user_cc`, `subject`, `body`, `date`,' . 41 ' `isRead`, `isReplied`, `isFlagged`, `priority`, `hash`, `replyto_hash`)' . 42 ' values(?,?,?,?,?,?,?,?,?,?,?,?,?)'; 43 $this->query( 44 $query, 45 [ 46 $user, 47 $from, 48 $to, 49 $cc, 50 $subject, 51 $body, 52 (int) $this->now, 53 'n', 54 'n', 55 'n', 56 (int) $priority, 57 $hash, 58 $replyto_hash 59 ] 60 ); 61 62 return true; 63 } 64 65 /** 66 * Send a message to a user 67 * 68 * @param string $user username 69 * @param string $from from username 70 * @param string $to to username (again?) 71 * @param string $cc cc username 72 * @param string $subject 73 * @param string $body 74 * @param int $priority 75 * @param string $replyto_hash 76 * @param string $replyto_email y/n 77 * @param string $bcc_sender y/n send blind copy email to from user's 78 * @return bool success 79 */ 80 function post_message($user, $from, $to, $cc, $subject, $body, $priority, $replyto_hash = '', $replyto_email = '', $bcc_sender = '') 81 { 82 global $prefs; 83 $userlib = TikiLib::lib('user'); 84 $smarty = TikiLib::lib('smarty'); 85 86 $subject = strip_tags($subject); 87 $body = strip_tags($body, '<a><b><img><i>'); 88 // Prevent duplicates 89 $hash = md5($subject . $body); 90 91 if ($this->getOne( 92 'select count(*) from `messu_messages` where `user`=? and `user_from`=? and `hash`=?', 93 [$user, $from, $hash] 94 ) 95 ) { 96 return false; 97 } 98 99 $query = 'insert into `messu_messages`' . 100 ' (`user`, `user_from`, `user_to`, `user_cc`, `subject`, `body`, `date`' . 101 ', `isRead`, `isReplied`, `isFlagged`, `priority`, `hash`, `replyto_hash`)' . 102 ' values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; 103 104 $this->query( 105 $query, 106 [ 107 $user, 108 $from, 109 $to, 110 $cc, 111 $subject, 112 $body, 113 (int) $this->now, 114 'n', 115 'n', 116 'n', 117 (int) $priority, 118 $hash, 119 $replyto_hash 120 ] 121 ); 122 123 // Now check if the user should be notified by email 124 $magId = $this->getOne('select LAST_INSERT_ID() from `messu_messages`', []); 125 $foo = parse_url($_SERVER['REQUEST_URI']); 126 $machine = $this->httpPrefix(true) . $foo['path']; 127 $machine = str_replace('messu-compose', 'messu-mailbox', $machine); 128 $machine = str_replace('messu-broadcast', 'messu-mailbox', $machine); 129 // For non-sefurl calls, replace tiki-ajax_services with messu-mailbox if 130 // service called is user > send_message 131 if ($foo['query'] == "controller=user&action=send_message") { 132 $machine = str_replace('tiki-ajax_services', 'messu-mailbox', $machine); 133 } 134 //For sefurl service call user > send_message, redirect to messu-mailbox.php 135 $machine = str_replace('tiki-user-send_message', 'messu-mailbox.php', $machine); 136 137 if ($this->get_user_preference($user, 'minPrio', 6) <= $priority) { 138 if (! isset($_SERVER['SERVER_NAME'])) { 139 $_SERVER['SERVER_NAME'] = $_SERVER['HTTP_HOST']; 140 } 141 $email = $userlib->get_user_email($user); 142 if ($userlib->user_exists($from)) { 143 $from_email = $userlib->get_user_email($from); // $from_email required for TikiMail constructor 144 } elseif ($from == 'tiki-contact.php' && ! empty($prefs['sender_email'])) { 145 $from_email = $prefs['sender_email']; 146 } else { 147 return false; // non-existent users can't send messages (etc) 148 } 149 if ($email) { 150 include_once('lib/webmail/tikimaillib.php'); 151 $smarty->assign('mail_site', $_SERVER['SERVER_NAME']); 152 $smarty->assign('mail_machine', $machine); 153 $smarty->assign('mail_date', $this->now); 154 $smarty->assign('mail_user', stripslashes($user)); 155 $smarty->assign('mail_from', stripslashes($from)); 156 $smarty->assign('mail_subject', stripslashes($subject)); 157 $smarty->assign('mail_body', stripslashes($body)); 158 $smarty->assign('mail_truncate', $prefs['messu_truncate_internal_message']); 159 $smarty->assign('messageid', $magId); 160 161 try { 162 $mail = new TikiMail($user, $from_email); 163 $lg = $this->get_user_preference($user, 'language', $prefs['site_language']); 164 165 if (empty($subject)) { 166 $s = $smarty->fetchLang($lg, 'mail/messu_message_notification_subject.tpl'); 167 $mail->setSubject(sprintf($s, $_SERVER['SERVER_NAME'])); 168 } else { 169 $mail->setSubject($subject); 170 } 171 172 $mail_data = $smarty->fetchLang($lg, 'mail/messu_message_notification.tpl'); 173 $mail->setText($mail_data); 174 175 if ($from_email) { 176 if ($bcc_sender === 'y' && ! empty($from_email)) { 177 $mail->setBcc($from_email); 178 } 179 180 if ($replyto_email !== 'y' && $userlib->get_user_preference($from, 'email is public', 'n') == 'n') { 181 $from_email = ''; // empty $from_email if not to be used - saves getting it twice 182 } 183 184 if (! empty($from_email)) { 185 $mail->setReplyTo($from_email); 186 } 187 } 188 189 if (! $mail->send([$email], 'mail')) { 190 return false; //TODO echo $mail->errors; 191 } 192 } catch (Zend\Mail\Exception\ExceptionInterface $e) { 193 Feedback::error($e->getMessage()); 194 return false; 195 } 196 } 197 } 198 return true; 199 } 200 201 /** 202 * Get a list of messages from users mailbox or users mail archive (from 203 * which depends on $dbsource) 204 */ 205 function list_user_messages( 206 $user, 207 $offset, 208 $maxRecords, 209 $sort_mode, 210 $find, 211 $flag = '', 212 $flagval = '', 213 $prio = '', 214 $dbsource, 215 $replyto_hash = '', 216 $orig_or_reply = 'r' 217 ) { 218 219 if ($dbsource == '') { 220 $dbsource = 'messages'; 221 } 222 223 $bindvars = [$user]; 224 $mid = ''; 225 226 if ($prio) { 227 $mid = ' and priority=? '; 228 $bindvars[] = $prio; 229 } 230 if ($replyto_hash) { 231 // find replies 232 if ($orig_or_reply == 'r') { 233 $mid .= ' and replyto_hash=? '; 234 // find original for the reply 235 } else { 236 $mid .= ' and hash=? '; 237 } 238 $bindvars[] = $replyto_hash; 239 } 240 if ($flag) { 241 // Process the flags 242 $mid .= " and `$flag`=? "; 243 $bindvars[] = $flagval; 244 } 245 if ($find) { 246 $findesc = '%' . $find . '%'; 247 $mid .= ' and (`subject` like ? or `body` like ?)'; 248 $bindvars[] = $findesc; 249 $bindvars[] = $findesc; 250 } 251 252 $query = 'select * from `messu_' . $dbsource . "` where `user`=? $mid order by " . 253 $this->convertSortMode($sort_mode) . ',' . $this->convertSortMode('msgId_desc'); 254 $query_cant = 'select count(*) from `messu_' . $dbsource . "` where `user`=? $mid"; 255 $result = $this->query($query, $bindvars, $maxRecords, $offset); 256 $cant = $this->getOne($query_cant, $bindvars); 257 $ret = []; 258 259 while ($res = $result->fetchRow()) { 260 $res['len'] = strlen($res['body']); 261 262 if (empty($res['subject'])) { 263 $res['subject'] = tra('NONE'); 264 } 265 266 $ret[] = $res; 267 } 268 269 $retval = []; 270 $retval['data'] = $ret; 271 $retval['cant'] = $cant; 272 return $retval; 273 } 274 275 /** 276 * Get the number of messages in the users mailbox or mail archive (from 277 * which depends on $dbsource) 278 */ 279 function count_messages($user, $dbsource = 'messages', $unreadOnly = false, $newSince = 0) 280 { 281 if ($dbsource == '') { 282 $dbsource = 'messages'; 283 } 284 285 $bindvars = [$user]; 286 $query_cant = 'select count(*) from `messu_' . $dbsource . '` where `user`=?'; 287 if ($unreadOnly == true) { 288 $query_cant .= ' and `isRead`="n"'; 289 } 290 if (! empty($newSince)) { 291 $query_cant .= ' and `date` >= ?'; 292 $bindvars[] = $newSince; 293 } 294 $cant = $this->getOne($query_cant, $bindvars); 295 return $cant; 296 } 297 298 /** 299 * Update message flagging 300 */ 301 function flag_message($user, $msgId, $flag, $val, $dbsource = 'messages') 302 { 303 if (! $msgId || ! (in_array($flag, ['isRead', 'isFlagged']))) { 304 return false; 305 } 306 307 if ($dbsource == '') { 308 $dbsource = 'messages'; 309 } 310 311 $query = 'update `messu_' . $dbsource . "` set `$flag`=? where `user`=? and `msgId`=?"; 312 return $this->query($query, [$val, $user, (int)$msgId]); 313 } 314 315 /** 316 * Mark a message as replied 317 */ 318 function mark_replied($user, $replyto_hash, $dbsource = 'sent') 319 { 320 if ((! $replyto_hash) || ($replyto_hash == '')) { 321 return false; 322 } 323 324 if ($dbsource == '') { 325 $dbsource = 'sent'; 326 } 327 328 $query = 'update `messu_' . $dbsource . '` set `isReplied`=? where `user`=? and `hash`=?'; 329 $this->query($query, ['y', $user, $replyto_hash]); 330 } 331 332 /** 333 * Delete message from mailbox or users mail archive (from which depends on 334 * $dbsource) 335 */ 336 function delete_message($user, $msgId, $dbsource = 'messages') 337 { 338 if (! $msgId) { 339 return false; 340 } 341 342 if ($dbsource == '') { 343 $dbsource = 'messages'; 344 } 345 346 $query = 'delete from `messu_' . $dbsource . '` where `user`=? and `msgId`=?'; 347 return $this->query($query, [$user, (int)$msgId]); 348 } 349 350 /** 351 * Move message from mailbox to users mail archive 352 */ 353 function archive_message($user, $msgId, $dbsource = 'messages') 354 { 355 if (! $msgId) { 356 return false; 357 } 358 359 if ($dbsource == '') { 360 $dbsource = 'messages'; 361 } 362 363 $columns = '`user`, `user_from`, `user_to`, `user_cc`, `subject`, `body`, `date`, `isRead`, `isReplied`, `isFlagged`, `priority`, `hash`, `replyto_hash`'; 364 $query = 'insert into `messu_archive` (' . $columns . ') select ' . $columns . ' from `messu_' . $dbsource . '` where `user`=? and `msgId`=?'; 365 $this->query($query, [$user, (int)$msgId]); 366 367 $query = 'delete from `messu_' . $dbsource . '` where `user`=? and `msgId`=?'; 368 return $this->query($query, [$user, (int)$msgId]); 369 } 370 371 /** 372 * Move message from archive to users mailbox 373 */ 374 function unarchive_message($user, $msgId, $dbsource = 'messages') 375 { 376 if (! $msgId) { 377 return false; 378 } 379 380 $dbsource = $this->get_archive_source($user, $msgId); 381 382 if ($dbsource == '') { 383 $dbsource = 'messages'; 384 } 385 386 $columns = '`user`, `user_from`, `user_to`, `user_cc`, `subject`, `body`, `date`, `isRead`, `isReplied`, `isFlagged`, `priority`, `hash`, `replyto_hash`'; 387 $query = 'insert into `messu_' . $dbsource . '` (' . $columns . ') select ' . $columns . ' from `messu_archive` where `user`=? and `msgId`=?'; 388 $this->query($query, [$user, (int)$msgId]); 389 390 $query = 'delete from `messu_archive` where `user`=? and `msgId`=?'; 391 return $this->query($query, [$user, (int)$msgId]); 392 } 393 394 /** 395 * Move read message older than x days from mailbox to users mail archive 396 */ 397 function archive_messages($user, $days, $dbsource = 'messages') 398 { 399 if ($days < 1) { 400 return false; 401 } 402 403 if ($dbsource == '') { 404 $dbsource = 'messages'; 405 } 406 407 $age = $this->now - ($days * 3600 * 24); 408 409 // TODO: only move as much msgs into archive as there is space left in there 410 $query = 'insert into `messu_archive` select * from `messu_' . $dbsource . '` where `user`=? and `isRead`=? and `date`<=?'; 411 $this->query($query, [$user, 'y', (int)$age]); 412 413 $query = 'delete from `messu_' . $dbsource . '` where `user`=? and `isRead`=? and `date`<=?'; 414 $this->query($query, [$user, 'y', (int)$age]); 415 } 416 417 /** 418 * Move forward to the next message and get it from the database 419 */ 420 function get_next_message($user, $msgId, $sort_mode, $find, $flag, $flagval, $prio, $dbsource = 'messages') 421 { 422 if (! $msgId) { 423 return 0; 424 } 425 426 if ($dbsource == '') { 427 $dbsource = 'messages'; 428 } 429 430 $mid = ''; 431 $bindvars = [$user,(int)$msgId]; 432 if ($prio) { 433 $mid .= ' and priority=? '; 434 $bindvars[] = $prio; 435 } 436 437 if ($flag) { 438 // Process the flags 439 $mid .= " and `$flag`=? "; 440 $bindvars[] = $flagval; 441 } 442 443 if ($find) { 444 $findesc = '%' . $find . '%'; 445 $mid .= ' and (`subject` like ? or `body` like ?)'; 446 $bindvars[] = $findesc; 447 $bindvars[] = $findesc; 448 } 449 450 $query = 'select min(`msgId`) as `nextmsg` from `messu_' . $dbsource . "` where `user`=? and `msgId` > ? $mid"; 451 $result = $this->query($query, $bindvars, 1, 0); 452 $res = $result->fetchRow(); 453 454 if (! $res) { 455 return false; 456 } 457 458 return $res['nextmsg']; 459 } 460 461 /** 462 * Move backward to the next message and get it from the database 463 */ 464 function get_prev_message($user, $msgId, $sort_mode, $find, $flag, $flagval, $prio, $dbsource = 'messages') 465 { 466 if (! $msgId) { 467 return 0; 468 } 469 470 if ($dbsource == '') { 471 $dbsource = 'messages'; 472 } 473 474 $mid = ''; 475 $bindvars = [$user, (int)$msgId]; 476 if ($prio) { 477 $mid .= ' and priority=? '; 478 $bindvars[] = $prio; 479 } 480 481 if ($flag) { 482 // Process the flags 483 $mid .= " and `$flag`=? "; 484 $bindvars[] = $flagval; 485 } 486 if ($find) { 487 $findesc = '%' . $find . '%'; 488 $mid .= ' and (`subject` like ? or `body` like ?)'; 489 $bindvars[] = $findesc; 490 $bindvars[] = $findesc; 491 } 492 493 $query = 'select max(`msgId`) as `prevmsg` from `messu_' . $dbsource . "` where `user`=? and `msgId` < ? $mid"; 494 $result = $this->query($query, $bindvars, 1, 0); 495 $res = $result->fetchRow(); 496 497 if (! $res) { 498 return false; 499 } 500 501 return $res['prevmsg']; 502 } 503 504 /** 505 * Get a message from the users mailbox or his mail archive (from which 506 * depends on $dbsource) 507 */ 508 function get_message($user, $msgId, $dbsource = 'messages') 509 { 510 if ($dbsource == '') { 511 $dbsource = 'messages'; 512 } 513 514 $bindvars = [$user, (int)$msgId]; 515 $query = 'select * from `messu_' . $dbsource . '` where `user`=? and `msgId`=?'; 516 $result = $this->query($query, $bindvars); 517 $res = $result->fetchRow(); 518 $res['parsed'] = TikiLib::lib('parser')->parse_data($res['body']); 519 $res['len'] = strlen($res['parsed']); 520 521 if (empty($res['subject'])) { 522 $res['subject'] = tra('NONE'); 523 } 524 525 return $res; 526 } 527 528 /** 529 * Get message from the users mailbox or his mail archive (from which 530 * depends on $dbsource) 531 */ 532 function get_messages($user, $dbsource = 'messages', $subject = '', $to = '', $from = '') 533 { 534 if ($dbsource == '') { 535 $dbsource = 'messages'; 536 } 537 538 $bindvars[] = $user; 539 540 $mid = ''; 541 542 // find mails with a specific subject 543 if ($subject <> '') { 544 $findesc = '%' . $subject . '%'; 545 $bindvars[] = $findesc; 546 $mid .= ' and `subject` like ?'; 547 } 548 549 // find mails to a specific user (to, cc, bcc) 550 if ($to <> '') { 551 $findesc = '%' . $to . '%'; 552 $bindvars[] = $findesc; 553 $bindvars[] = $findesc; 554 $bindvars[] = $findesc; 555 $mid .= ' and (`user_to` like ? or `user_cc` like ? or `user_bcc` like ?)'; 556 } 557 558 // find mails from a specific user 559 if ($from <> '') { 560 $findesc = '%' . $from . '%'; 561 $bindvars[] = $findesc; 562 $mid .= ' and `user_from` like ?'; 563 } 564 $query = 'select * from `messu_' . $dbsource . "` where `user`=? $mid"; 565 566 $result = $this->query($query, $bindvars); 567 $ret = []; 568 569 while ($res = $result->fetchRow()) { 570 $res['parsed'] = TikiLib::lib('parser')->parse_data($res['body']); 571 $res['len'] = strlen($res['parsed']); 572 if (empty($res['subject'])) { 573 $res['subject'] = tra('NONE'); 574 } 575 $ret[] = $res; 576 } 577 return $ret; 578 } 579 580 /** 581 * Get mail source info from the mail archive 582 */ 583 function get_archive_source($user, $msgId) 584 { 585 $dbsource =''; 586 587 $res= $this->get_message($user, $msgId, 'archive'); 588 589 if($res['user_from']==$user){ 590 $dbsource = 'sent'; 591 } 592 593 return $dbsource; 594 } 595 596} 597